Skip to content

Commit c385fa1

Browse files
committed
fix: address unicode issue in context.call
1 parent af834e3 commit c385fa1

File tree

14 files changed

+243
-128
lines changed

14 files changed

+243
-128
lines changed

.github/workflows/test.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ jobs:
224224
- name: Run example
225225
run: npm run dev &
226226
working-directory: examples/image-gen-with-workflow
227-
227+
228228
agents-researcher-local-build:
229229
needs:
230230
- local-tests

examples/ci/app/test-routes/call/constants.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ export const FAILING_HEADER_VALUE = "fail-header-value-BAR"
55
export const GET_HEADER = "Get-Header"
66
export const GET_HEADER_VALUE = "get-header-value-FOO"
77

8-
export const PATCH_RESULT = 99999999
8+
export const PATCH_RESULT = 99999999
9+
10+
export const DELETE_RESULT = { foo: "bar", zed: 2, unicode: "`“X” - 𐐷𐐶𐐹`" }

examples/ci/app/test-routes/call/third-party/route.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FAILING_HEADER_VALUE, FAILING_HEADER, GET_HEADER, GET_HEADER_VALUE, PATCH_RESULT } from "../constants";
1+
import { FAILING_HEADER_VALUE, FAILING_HEADER, GET_HEADER, GET_HEADER_VALUE, PATCH_RESULT, DELETE_RESULT } from "../constants";
22

33
const thirdPartyResult = "third-party-result";
44

@@ -8,7 +8,7 @@ export const GET = async (request: Request) => {
88
{
99
status: 200,
1010
headers: {
11-
[ GET_HEADER ]: GET_HEADER_VALUE
11+
[GET_HEADER]: GET_HEADER_VALUE
1212
}
1313
}
1414
)
@@ -28,15 +28,15 @@ export const PATCH = async () => {
2828
{
2929
status: 401,
3030
headers: {
31-
[ FAILING_HEADER ]: FAILING_HEADER_VALUE
31+
[FAILING_HEADER]: FAILING_HEADER_VALUE
3232
}
3333
}
3434
)
3535
}
3636

3737
export const DELETE = async () => {
3838
return new Response(
39-
JSON.stringify({ foo: "bar", zed: 2 }),
39+
JSON.stringify(DELETE_RESULT),
4040
{
4141
status: 400
4242
}

examples/ci/app/test-routes/call/workflow/route.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { serve } from "@upstash/workflow/nextjs";
22
import { BASE_URL, TEST_ROUTE_PREFIX } from "app/ci/constants";
33
import { testServe, expect } from "app/ci/utils";
44
import { saveResult } from "app/ci/upstash/redis"
5-
import { FAILING_HEADER, FAILING_HEADER_VALUE, GET_HEADER, GET_HEADER_VALUE, PATCH_RESULT } from "../constants";
5+
import { DELETE_RESULT, FAILING_HEADER, FAILING_HEADER_VALUE, GET_HEADER, GET_HEADER_VALUE, PATCH_RESULT } from "../constants";
66

77
const testHeader = `test-header-foo`
88
const headerValue = `header-foo`
@@ -38,18 +38,18 @@ export const { POST, GET } = testServe(
3838
// check payload after first step because we can't check above
3939
expect(input, payload);
4040
expect(postStatus, 201)
41-
42-
expect(postResult as string,
41+
42+
expect(postResult as string,
4343
"called POST 'third-party-result' 'post-header-value-x' '\"post-payload\"'"
4444
);
45-
45+
4646
await context.sleep("sleep 1", 2);
47-
47+
4848
const { body: getResult, header: getHeaders, status: getStatus } = await context.call<string>("get call", {
4949
url: thirdPartyEndpoint,
5050
headers: getHeader,
5151
});
52-
52+
5353
expect(getStatus, 200)
5454
expect(getHeaders[GET_HEADER][0], GET_HEADER_VALUE)
5555
expect(getResult, "called GET 'third-party-result' 'get-header-value-x'");
@@ -84,7 +84,7 @@ export const { POST, GET } = testServe(
8484

8585
expect(deleteStatus, 400)
8686
expect(typeof deleteBody, "object");
87-
expect(JSON.stringify(deleteBody), '{"foo":"bar","zed":2}');
87+
expect(JSON.stringify(deleteBody), JSON.stringify(DELETE_RESULT));
8888

8989
await saveResult(
9090
context,

examples/ci/app/test-routes/invoke/workflows/[...]/route.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { WorkflowContext } from "@upstash/workflow";
22
import { createWorkflow, serveMany } from "@upstash/workflow/nextjs";
3-
import { CI_RANDOM_ID_HEADER, CI_ROUTE_HEADER, TEST_ROUTE_PREFIX } from "app/ci/constants";
3+
import { BASE_URL, CI_RANDOM_ID_HEADER, CI_ROUTE_HEADER, TEST_ROUTE_PREFIX } from "app/ci/constants";
44
import { saveResult } from "app/ci/upstash/redis";
55
import { expect, nanoid, testServe } from "app/ci/utils";
66
import { z } from "zod";
@@ -13,6 +13,9 @@ const payload = 123
1313
const invokePayload = "invoke-payload"
1414
const invokeResult = "invoke-result"
1515

16+
const BRANCH_ONE_RESULT = { "branch-one": "result" }
17+
const BRANCH_TWO_RESULT = "branch-two-result"
18+
1619
const invokeHeader = "invoke-header"
1720
const invokeHeaderValue = "invoke-header-value"
1821

@@ -64,7 +67,7 @@ const workflowOne = createWorkflow(async (context: WorkflowContext<number>) => {
6467
"done invoke"
6568
)
6669
}, {
67-
schema: z.number()
70+
schema: z.number(),
6871
})
6972

7073
const workflowTwo = createWorkflow(async (context: WorkflowContext<string>) => {
@@ -105,8 +108,9 @@ const workflowTwo = createWorkflow(async (context: WorkflowContext<string>) => {
105108
})
106109
])
107110

108-
expect(result[0].body, "branch-one-result")
109-
expect(result[1].body, "branch-two-result")
111+
expect(typeof result[0].body, "object")
112+
expect(JSON.stringify(result[0].body), JSON.stringify(BRANCH_ONE_RESULT))
113+
expect(result[1].body, BRANCH_TWO_RESULT)
110114

111115
return invokeResult
112116
})
@@ -143,7 +147,7 @@ const branchOne = createWorkflow(async (context: WorkflowContext<number>) => {
143147

144148
await context.sleep("check", 1)
145149

146-
return "branch-one-result"
150+
return BRANCH_ONE_RESULT
147151
})
148152

149153
/**
@@ -176,7 +180,7 @@ const branchTwo = createWorkflow(async (context: WorkflowContext<number>) => {
176180

177181
await context.sleep("check", 1)
178182

179-
return "branch-two-result"
183+
return BRANCH_TWO_RESULT
180184
})
181185

182186
export const { POST, GET } = testServe(
@@ -186,6 +190,8 @@ export const { POST, GET } = testServe(
186190
workflowThree,
187191
branchOne,
188192
branchTwo,
193+
}, {
194+
baseUrl: BASE_URL
189195
}),
190196
{
191197
expectedCallCount: 26,

examples/ci/app/test-routes/path/route.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export const { POST, GET } = testServe(
3131
});
3232

3333
expect(result2, "processed 'processed '“unicode-quotes”''");
34+
35+
const result3 = await context.run("step 3", () => true)
36+
expect(result3, true)
37+
expect(typeof result3, "boolean")
38+
3439
await saveResult(
3540
context,
3641
result2
@@ -40,7 +45,7 @@ export const { POST, GET } = testServe(
4045
retries: 0
4146
}
4247
), {
43-
expectedCallCount: 4,
48+
expectedCallCount: 5,
4449
expectedResult: "processed 'processed '“unicode-quotes”''",
4550
payload,
4651
headers: {

src/context/auto-executor.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe("auto-executor", () => {
4646
stepId: 1,
4747
stepName: "attemptCharge",
4848
stepType: "Run",
49-
out: { input: initialPayload, success: false },
49+
out: JSON.stringify({ input: initialPayload, success: false }),
5050
concurrent: 1,
5151
};
5252

@@ -134,7 +134,6 @@ describe("auto-executor", () => {
134134
},
135135
body: JSON.stringify({
136136
...singleStep,
137-
out: JSON.stringify(singleStep.out),
138137
}),
139138
},
140139
],

src/context/auto-executor.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class AutoExecutor {
135135
step,
136136
stepCount: this.stepCount,
137137
});
138-
return step.out as TResult;
138+
return lazyStep.parseOut(step.out);
139139
}
140140

141141
const resultStep = await lazyStep.getResultStep(NO_CONCURRENCY, this.stepCount);
@@ -268,7 +268,9 @@ export class AutoExecutor {
268268

269269
validateParallelSteps(parallelSteps, parallelResultSteps);
270270

271-
return parallelResultSteps.map((step) => step.out) as TResults;
271+
return parallelResultSteps.map((step, index) =>
272+
parallelSteps[index].parseOut(step.out)
273+
) as TResults;
272274
}
273275
}
274276
const fillValue = undefined;

src/context/context.ts

+16-62
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export class WorkflowContext<TInitialPayload = unknown> {
237237
): Promise<TResult> {
238238
const wrappedStepFunction = (() =>
239239
this.executor.wrapStep(stepName, stepFunction)) as StepFunction<TResult>;
240-
return this.addStep<TResult>(new LazyFunctionStep(stepName, wrappedStepFunction));
240+
return await this.addStep<TResult>(new LazyFunctionStep(stepName, wrappedStepFunction));
241241
}
242242

243243
/**
@@ -316,51 +316,28 @@ export class WorkflowContext<TInitialPayload = unknown> {
316316
stepName: string,
317317
settings: CallSettings<TBody>
318318
): Promise<CallResponse<TResult>> {
319-
const { url, method = "GET", body, headers = {}, retries = 0, timeout, flowControl } = settings;
319+
const {
320+
url,
321+
method = "GET",
322+
body: requestBody,
323+
headers = {},
324+
retries = 0,
325+
timeout,
326+
flowControl,
327+
} = settings;
320328

321-
const result = await this.addStep(
322-
new LazyCallStep<CallResponse<string> | string>(
329+
return await this.addStep(
330+
new LazyCallStep<TResult>(
323331
stepName,
324332
url,
325333
method,
326-
body,
334+
requestBody,
327335
headers,
328336
retries,
329337
timeout,
330338
flowControl
331339
)
332340
);
333-
334-
// <for backwards compatibity>
335-
// if you transition to upstash/workflow from upstash/qstash,
336-
// the out field in the steps will be the body of the response.
337-
// we need to handle them explicitly here
338-
if (typeof result === "string") {
339-
try {
340-
const body = JSON.parse(result);
341-
return {
342-
status: 200,
343-
header: {},
344-
body,
345-
};
346-
} catch {
347-
return {
348-
status: 200,
349-
header: {},
350-
body: result as TResult,
351-
};
352-
}
353-
}
354-
// </for backwards compatibity>
355-
356-
try {
357-
return {
358-
...result,
359-
body: JSON.parse(result.body as string),
360-
};
361-
} catch {
362-
return result as CallResponse<TResult>;
363-
}
364341
}
365342

366343
/**
@@ -406,16 +383,7 @@ export class WorkflowContext<TInitialPayload = unknown> {
406383

407384
const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
408385

409-
const result = await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
410-
411-
try {
412-
return {
413-
...result,
414-
eventData: JSON.parse(result.eventData as string),
415-
};
416-
} catch {
417-
return result;
418-
}
386+
return await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
419387
}
420388

421389
/**
@@ -444,30 +412,16 @@ export class WorkflowContext<TInitialPayload = unknown> {
444412
eventId: string,
445413
eventData: unknown
446414
): Promise<NotifyStepResponse> {
447-
const result = await this.addStep(
415+
return await this.addStep(
448416
new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
449417
);
450-
451-
try {
452-
return {
453-
...result,
454-
eventData: JSON.parse(result.eventData as string),
455-
};
456-
} catch {
457-
return result;
458-
}
459418
}
460419

461420
public async invoke<TInitialPayload, TResult>(
462421
stepName: string,
463422
settings: LazyInvokeStepParams<TInitialPayload, TResult>
464423
) {
465-
const result = await this.addStep(new LazyInvokeStep(stepName, settings));
466-
467-
return {
468-
...result,
469-
body: (result.body ? JSON.parse(result.body as string) : undefined) as TResult,
470-
};
424+
return await this.addStep(new LazyInvokeStep(stepName, settings));
471425
}
472426

473427
/**

0 commit comments

Comments
 (0)