From 777724d85c80725c6644fe994b7f533d157cb041 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 02:32:48 +0000 Subject: [PATCH 1/3] Surface package workflow export failures Co-authored-by: Kent C. Dodds --- .../package-workflows.node.test.ts | 56 +++++++++++++++++++ .../src/package-runtime/package-workflows.ts | 21 +++++++ 2 files changed, 77 insertions(+) diff --git a/packages/worker/src/package-runtime/package-workflows.node.test.ts b/packages/worker/src/package-runtime/package-workflows.node.test.ts index 0cc7b662d6..9c9a080c08 100644 --- a/packages/worker/src/package-runtime/package-workflows.node.test.ts +++ b/packages/worker/src/package-runtime/package-workflows.node.test.ts @@ -469,6 +469,62 @@ test('DynamicCallableWorkflowBase restores attached remote connectors for packag ) }) +test('DynamicCallableWorkflowBase marks package export error responses as workflow errors', async () => { + const binding = createStatefulWorkflowBinding() + const db = createWorkflowRunsDatabase() + const env = { + APP_DB: db, + DYNAMIC_CALLABLE_WORKFLOWS: binding.workflow, + APP_BASE_URL: 'https://app.example.com', + } as Env + const created = await createDynamicCallableWorkflow({ + env, + userId: 'user-1', + packageContext: null, + body: { + packageId: 'pkg-1', + exportName: './workflow-run-event', + runAt: '2026-05-03T12:34:56.000Z', + idempotencyKey: 'package-error-response-smoke', + params: { key: 'west-sensitive-reopen' }, + }, + }) + const queued = binding.instances.get(created.id) + if (!queued?.params) throw new Error('Expected queued workflow payload.') + invocationMocks.invokePackageExport.mockReset() + invocationMocks.invokePackageExport.mockResolvedValueOnce({ + status: 500, + body: { + ok: false, + error: { + message: + 'Shade workflow event failed: Tool "home_default_bond_shade_set_position" not found', + }, + }, + }) + + const workflow = new DynamicCallableWorkflowBase({} as ExecutionContext, env) + const stepDo = vi.fn( + async (_name: string, _config: unknown, callback: () => unknown) => + await callback(), + ) + await expect( + workflow.run( + { + payload: queued.params as never, + timestamp: new Date(), + instanceId: created.id, + }, + { sleepUntil: vi.fn(), do: stepDo } as unknown as WorkflowStep, + ), + ).rejects.toThrow('home_default_bond_shade_set_position') + expect(db.workflowRuns.get(created.id)).toMatchObject({ + status: 'errored', + completed_at: expect.any(String), + last_error: expect.stringContaining('home_default_bond_shade_set_position'), + }) +}) + test('createDynamicCallableWorkflow verifies package ownership before queueing package exports', async () => { const binding = createWorkflowBinding({ existing: null }) const db = createWorkflowRunsDatabase() diff --git a/packages/worker/src/package-runtime/package-workflows.ts b/packages/worker/src/package-runtime/package-workflows.ts index eef9019123..5f387c09b6 100644 --- a/packages/worker/src/package-runtime/package-workflows.ts +++ b/packages/worker/src/package-runtime/package-workflows.ts @@ -201,6 +201,24 @@ function toSerializableJson(value: unknown): JsonValue { } } +function getWorkflowInvocationErrorMessage(response: { + status: number + body: unknown +}) { + const body = response.body + const error = + body && typeof body === 'object' + ? (body as Record)['error'] + : null + const message = + error && typeof error === 'object' + ? (error as Record)['message'] + : null + return typeof message === 'string' && message.trim() + ? message + : `Package workflow export failed with HTTP ${response.status}.` +} + function normalizeNonEmptyString(value: string, fieldName: string) { const trimmed = value.trim() if (!trimmed) { @@ -992,6 +1010,9 @@ export class DynamicCallableWorkflowBase extends WorkflowEntrypoint< topic: payload.workflowName, }, }) + if (response.status < 200 || response.status >= 400) { + throw new Error(getWorkflowInvocationErrorMessage(response)) + } return { status: response.status, body: toSerializableJson(response.body), From e0946642aebfa3e9f6cc943c81a2b4017530cb2d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 03:12:22 +0000 Subject: [PATCH 2/3] Route connector ingress before assets Co-authored-by: Kent C. Dodds --- packages/worker/wrangler.jsonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/worker/wrangler.jsonc b/packages/worker/wrangler.jsonc index cdb6f8cff7..ee50fce88c 100644 --- a/packages/worker/wrangler.jsonc +++ b/packages/worker/wrangler.jsonc @@ -99,7 +99,7 @@ "assets": { "directory": "./public", "binding": "ASSETS", - "run_worker_first": ["/mcp-apps/*", "/styles.css"], + "run_worker_first": ["/connectors/*", "/mcp-apps/*", "/styles.css"], }, "durable_objects": { "bindings": [ @@ -183,7 +183,7 @@ "assets": { "directory": "./public", "binding": "ASSETS", - "run_worker_first": ["/mcp-apps/*", "/styles.css"], + "run_worker_first": ["/connectors/*", "/mcp-apps/*", "/styles.css"], }, "durable_objects": { "bindings": [ From e705a2bdee397abb74451411172441b1bd8fe2d0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 03:17:10 +0000 Subject: [PATCH 3/3] Address workflow and connector review feedback Co-authored-by: Kent C. Dodds --- .../package-workflows.node.test.ts | 50 +++++++++++++++++++ .../src/package-runtime/package-workflows.ts | 2 +- packages/worker/wrangler.jsonc | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/packages/worker/src/package-runtime/package-workflows.node.test.ts b/packages/worker/src/package-runtime/package-workflows.node.test.ts index 9c9a080c08..3f95eba8d2 100644 --- a/packages/worker/src/package-runtime/package-workflows.node.test.ts +++ b/packages/worker/src/package-runtime/package-workflows.node.test.ts @@ -525,6 +525,56 @@ test('DynamicCallableWorkflowBase marks package export error responses as workfl }) }) +test('DynamicCallableWorkflowBase rejects package export redirect responses', async () => { + const binding = createStatefulWorkflowBinding() + const db = createWorkflowRunsDatabase() + const env = { + APP_DB: db, + DYNAMIC_CALLABLE_WORKFLOWS: binding.workflow, + APP_BASE_URL: 'https://app.example.com', + } as Env + const created = await createDynamicCallableWorkflow({ + env, + userId: 'user-1', + packageContext: null, + body: { + packageId: 'pkg-1', + exportName: './workflow-run-event', + runAt: '2026-05-03T12:34:56.000Z', + idempotencyKey: 'package-redirect-response-smoke', + params: { key: 'west-sensitive-reopen' }, + }, + }) + const queued = binding.instances.get(created.id) + if (!queued?.params) throw new Error('Expected queued workflow payload.') + invocationMocks.invokePackageExport.mockReset() + invocationMocks.invokePackageExport.mockResolvedValueOnce({ + status: 302, + body: { ok: false }, + }) + + const workflow = new DynamicCallableWorkflowBase({} as ExecutionContext, env) + const stepDo = vi.fn( + async (_name: string, _config: unknown, callback: () => unknown) => + await callback(), + ) + await expect( + workflow.run( + { + payload: queued.params as never, + timestamp: new Date(), + instanceId: created.id, + }, + { sleepUntil: vi.fn(), do: stepDo } as unknown as WorkflowStep, + ), + ).rejects.toThrow('Package workflow export failed with HTTP 302.') + expect(db.workflowRuns.get(created.id)).toMatchObject({ + status: 'errored', + completed_at: expect.any(String), + last_error: 'Package workflow export failed with HTTP 302.', + }) +}) + test('createDynamicCallableWorkflow verifies package ownership before queueing package exports', async () => { const binding = createWorkflowBinding({ existing: null }) const db = createWorkflowRunsDatabase() diff --git a/packages/worker/src/package-runtime/package-workflows.ts b/packages/worker/src/package-runtime/package-workflows.ts index 5f387c09b6..0105cdd850 100644 --- a/packages/worker/src/package-runtime/package-workflows.ts +++ b/packages/worker/src/package-runtime/package-workflows.ts @@ -1010,7 +1010,7 @@ export class DynamicCallableWorkflowBase extends WorkflowEntrypoint< topic: payload.workflowName, }, }) - if (response.status < 200 || response.status >= 400) { + if (response.status < 200 || response.status >= 300) { throw new Error(getWorkflowInvocationErrorMessage(response)) } return { diff --git a/packages/worker/wrangler.jsonc b/packages/worker/wrangler.jsonc index ee50fce88c..f87320d233 100644 --- a/packages/worker/wrangler.jsonc +++ b/packages/worker/wrangler.jsonc @@ -267,7 +267,7 @@ "assets": { "directory": "./public", "binding": "ASSETS", - "run_worker_first": ["/mcp-apps/*", "/styles.css"], + "run_worker_first": ["/connectors/*", "/mcp-apps/*", "/styles.css"], }, "durable_objects": { "bindings": [