Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/run-metadata-json-string.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@trigger.dev/core": patch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add the opening changeset fence.

Line 1 starts with the package bump, but Changesets requires --- before the bump and after it. This file has only the closing fence. Changesets cannot read it as a valid patch changeset, which can block release commands. Add --- above Line 1. (github.com)

As per coding guidelines, “Changes to packages/ are customer-facing. Always add a changeset: pnpm run changeset:add.”

Proposed fix
--- "a/.changeset/run-metadata-json-string.md"
+++ "b/.changeset/run-metadata-json-string.md"
@@ -1,4 +1,5 @@
+---
 "@trigger.dev/core": patch
 ---
 
 `metadata.refresh()` now works against deployments where `GET /api/v1/runs/:runId/metadata` returns the run metadata as a JSON string rather than an object. The response schema parses a string payload before validating, so `refresh()` resolves with the same metadata record on every version.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"@trigger.dev/core": patch
---
"@trigger.dev/core": patch

Source: Coding guidelines

---
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

`metadata.refresh()` now works against deployments where `GET /api/v1/runs/:runId/metadata` returns the run metadata as a JSON string rather than an object. The response schema parses a string payload before validating, so `refresh()` resolves with the same metadata record on every version.
15 changes: 14 additions & 1 deletion packages/core/src/v3/schemas/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1769,7 +1769,20 @@ export const UpdateMetadataRequestBody = FlushedRunMetadata;
export type UpdateMetadataRequestBody = z.infer<typeof UpdateMetadataRequestBody>;

export const UpdateMetadataResponseBody = z.object({
metadata: z.record(z.string(), DeserializedJsonSchema),
metadata: z.preprocess(
(value) => {
if (typeof value !== "string") {
return value;
}

try {
return JSON.parse(value);
} catch {
return value;
}
},
z.record(z.string(), DeserializedJsonSchema)
),
});

export type UpdateMetadataResponseBody = z.infer<typeof UpdateMetadataResponseBody>;
Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/v3/schemas/runMetadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, expect, it } from "vitest";
import { UpdateMetadataResponseBody } from "./api.js";

describe("UpdateMetadataResponseBody", () => {
it("parses an object metadata payload", () => {
const result = UpdateMetadataResponseBody.safeParse({
metadata: { key: "value", count: 2 },
});

expect(result.success).toBe(true);
if (result.success) {
expect(result.data.metadata).toEqual({ key: "value", count: 2 });
}
});

it("parses a metadata payload returned as a JSON string", () => {
const result = UpdateMetadataResponseBody.safeParse({
metadata: '{"key":"value","count":2}',
});

expect(result.success).toBe(true);
if (result.success) {
expect(result.data.metadata).toEqual({ key: "value", count: 2 });
}
});

it("rejects a metadata payload that is neither object nor valid JSON", () => {
const result = UpdateMetadataResponseBody.safeParse({ metadata: "not-json" });

expect(result.success).toBe(false);
});
});