diff --git a/packages/core/src/parse-name.test.ts b/packages/core/src/parse-name.test.ts index 236f7cd22..98b45f622 100644 --- a/packages/core/src/parse-name.test.ts +++ b/packages/core/src/parse-name.test.ts @@ -36,6 +36,22 @@ describe('parseWorkflowName', () => { }); }); + test('should handle Windows path with backslashes during workflow name normalization', () => { + // This tests the scenario from the bug report where the workflow name contains backslashes + const windowsWorkflowName = 'workflow//C:\\dev\\birthday-card-generator\\app\\api\\generate\\route.ts//handleOrder'; + const normalizedName = windowsWorkflowName.replace(/\\/g, '/'); + + // The normalized name should equal the expected format + expect(normalizedName).toBe('workflow//C:/dev/birthday-card-generator/app/api/generate/route.ts//handleOrder'); + + const result = parseWorkflowName(normalizedName); + expect(result).toEqual({ + shortName: 'handleOrder', + path: 'C:/dev/birthday-card-generator/app/api/generate/route.ts', + functionName: 'handleOrder', + }); + }); + test('should parse workflow name with nested function names', () => { const result = parseWorkflowName( 'workflow//src/app.ts//nested//function//name' diff --git a/packages/core/src/workflow.test.ts b/packages/core/src/workflow.test.ts index 93d868ede..1771d0662 100644 --- a/packages/core/src/workflow.test.ts +++ b/packages/core/src/workflow.test.ts @@ -2303,5 +2303,32 @@ describe('runWorkflow', () => { 'sleep with date completed' ); }); + + it('should handle Windows paths with backslashes in workflow names', async () => { + // Test the specific Windows path issue from the bug report + const workflowName = 'workflow//C:/dev/birthday-card-generator/app/api/generate/route.ts//handleOrder'; + const workflowCode = `function handleOrder() { return "success from Windows"; }${getWorkflowTransformCode(workflowName)}`; + + // Simulate the problematic workflow name with backslashes (as might occur on Windows) + const windowsWorkflowName = 'workflow//C:\\dev\\birthday-card-generator\\app\\api\\generate\\route.ts//handleOrder'; + + const ops: Promise[] = []; + const workflowRun: WorkflowRun = { + runId: 'wrun_windows_test', + workflowName: windowsWorkflowName, // Use the backslash version + status: 'running', + input: dehydrateWorkflowArguments([], ops), + createdAt: new Date('2024-01-01T00:00:00.000Z'), + updatedAt: new Date('2024-01-01T00:00:00.000Z'), + startedAt: new Date('2024-01-01T00:00:00.000Z'), + deploymentId: 'test-deployment', + }; + + const events: Event[] = []; + + // This should work now because the workflow.ts normalizes the name before lookup + const result = await runWorkflow(workflowCode, workflowRun, events); + expect(result).toBe("success from Windows"); + }); }); }); diff --git a/packages/core/src/workflow.ts b/packages/core/src/workflow.ts index f27f4453f..bf646eb62 100644 --- a/packages/core/src/workflow.ts +++ b/packages/core/src/workflow.ts @@ -549,8 +549,13 @@ export async function runWorkflow( const parsedName = parseWorkflowName(workflowRun.workflowName); const filename = parsedName?.path || workflowRun.workflowName; + // Normalize the workflow name to handle Windows path separators + // The SWC transform normalizes paths to forward slashes during bundling, + // but the workflow name lookup might contain backslashes on Windows + const normalizedWorkflowName = workflowRun.workflowName.replace(/\\/g, '/'); + const workflowFn = runInContext( - `${workflowCode}; globalThis.__private_workflows?.get(${JSON.stringify(workflowRun.workflowName)})`, + `${workflowCode}; globalThis.__private_workflows?.get(${JSON.stringify(normalizedWorkflowName)})`, context, { filename } ); @@ -558,7 +563,7 @@ export async function runWorkflow( if (typeof workflowFn !== 'function') { throw new ReferenceError( `Workflow ${JSON.stringify( - workflowRun.workflowName + normalizedWorkflowName )} must be a function, but got "${typeof workflowFn}" instead` ); }