@upstash/workflow 0.3.0-rc → 0.3.0-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/astro.d.mts +3 -3
- package/astro.d.ts +3 -3
- package/astro.js +1048 -676
- package/astro.mjs +1 -1
- package/{chunk-AGYYZKP7.mjs → chunk-2Z32SOYM.mjs} +1047 -674
- package/cloudflare.d.mts +3 -3
- package/cloudflare.d.ts +3 -3
- package/cloudflare.js +1048 -676
- package/cloudflare.mjs +1 -1
- package/express.d.mts +3 -3
- package/express.d.ts +3 -3
- package/express.js +1058 -681
- package/express.mjs +11 -6
- package/h3.d.mts +3 -3
- package/h3.d.ts +3 -3
- package/h3.js +1053 -677
- package/h3.mjs +6 -2
- package/hono.d.mts +3 -3
- package/hono.d.ts +3 -3
- package/hono.js +1048 -676
- package/hono.mjs +1 -1
- package/index.d.mts +98 -64
- package/index.d.ts +98 -64
- package/index.js +1079 -697
- package/index.mjs +30 -20
- package/nextjs.d.mts +4 -4
- package/nextjs.d.ts +4 -4
- package/nextjs.js +1049 -677
- package/nextjs.mjs +2 -2
- package/package.json +1 -1
- package/{serve-many-DVtHRxeg.d.ts → serve-many-DhB8-zPD.d.mts} +2 -2
- package/{serve-many-DEwKPF6H.d.mts → serve-many-qnfynN1x.d.ts} +2 -2
- package/solidjs.d.mts +2 -2
- package/solidjs.d.ts +2 -2
- package/solidjs.js +1053 -677
- package/solidjs.mjs +6 -2
- package/svelte.d.mts +5 -6
- package/svelte.d.ts +5 -6
- package/svelte.js +1061 -682
- package/svelte.mjs +14 -7
- package/tanstack.d.mts +3 -3
- package/tanstack.d.ts +3 -3
- package/tanstack.js +1048 -676
- package/tanstack.mjs +1 -1
- package/{types-DESkn7K9.d.ts → types-pEje3VEB.d.mts} +212 -239
- package/{types-DESkn7K9.d.mts → types-pEje3VEB.d.ts} +212 -239
package/nextjs.js
CHANGED
|
@@ -41,26 +41,36 @@ var WorkflowError = class extends import_qstash.QstashError {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
var WorkflowAbort = class extends Error {
|
|
44
|
-
stepInfo;
|
|
45
44
|
stepName;
|
|
45
|
+
stepInfo;
|
|
46
46
|
/**
|
|
47
|
-
* whether workflow is to be canceled on abort
|
|
48
|
-
*/
|
|
49
|
-
cancelWorkflow;
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
47
|
* @param stepName name of the aborting step
|
|
53
48
|
* @param stepInfo step information
|
|
54
|
-
* @param cancelWorkflow
|
|
55
49
|
*/
|
|
56
|
-
constructor(stepName, stepInfo
|
|
50
|
+
constructor(stepName, stepInfo) {
|
|
57
51
|
super(
|
|
58
52
|
`This is an Upstash Workflow error thrown after a step executes. It is expected to be raised. Make sure that you await for each step. Also, if you are using try/catch blocks, you should not wrap context.run/sleep/sleepUntil/call methods with try/catch. Aborting workflow after executing step '${stepName}'.`
|
|
59
53
|
);
|
|
60
54
|
this.name = "WorkflowAbort";
|
|
61
55
|
this.stepName = stepName;
|
|
62
56
|
this.stepInfo = stepInfo;
|
|
63
|
-
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var WorkflowAuthError = class extends WorkflowAbort {
|
|
60
|
+
/**
|
|
61
|
+
* @param stepName name of the step found during authorization
|
|
62
|
+
*/
|
|
63
|
+
constructor(stepName) {
|
|
64
|
+
super(stepName);
|
|
65
|
+
this.name = "WorkflowAuthError";
|
|
66
|
+
this.message = `This is an Upstash Workflow error thrown during authorization check. Found step '${stepName}' during dry-run.`;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var WorkflowCancelAbort = class extends WorkflowAbort {
|
|
70
|
+
constructor() {
|
|
71
|
+
super("cancel");
|
|
72
|
+
this.name = "WorkflowCancelAbort";
|
|
73
|
+
this.message = "Workflow has been canceled by user via context.cancel().";
|
|
64
74
|
}
|
|
65
75
|
};
|
|
66
76
|
var WorkflowNonRetryableError = class extends WorkflowAbort {
|
|
@@ -68,22 +78,22 @@ var WorkflowNonRetryableError = class extends WorkflowAbort {
|
|
|
68
78
|
* @param message error message to be displayed
|
|
69
79
|
*/
|
|
70
80
|
constructor(message) {
|
|
71
|
-
super("
|
|
81
|
+
super("non-retryable-error");
|
|
72
82
|
this.name = "WorkflowNonRetryableError";
|
|
73
|
-
|
|
83
|
+
this.message = message ?? "Workflow failed with non-retryable error.";
|
|
74
84
|
}
|
|
75
85
|
};
|
|
76
86
|
var WorkflowRetryAfterError = class extends WorkflowAbort {
|
|
77
87
|
retryAfter;
|
|
78
88
|
/**
|
|
79
|
-
* @param retryAfter time in seconds after which the workflow should be retried
|
|
80
89
|
* @param message error message to be displayed
|
|
90
|
+
* @param retryAfter time in seconds after which the workflow should be retried
|
|
81
91
|
*/
|
|
82
92
|
constructor(message, retryAfter) {
|
|
83
|
-
super("retry"
|
|
93
|
+
super("retry-after-error");
|
|
84
94
|
this.name = "WorkflowRetryAfterError";
|
|
95
|
+
this.message = message;
|
|
85
96
|
this.retryAfter = retryAfter;
|
|
86
|
-
if (message) this.message = message;
|
|
87
97
|
}
|
|
88
98
|
};
|
|
89
99
|
var formatWorkflowError = (error) => {
|
|
@@ -135,15 +145,21 @@ var makeCancelRequest = async (requester, workflowRunId) => {
|
|
|
135
145
|
});
|
|
136
146
|
return true;
|
|
137
147
|
};
|
|
138
|
-
var getSteps = async (requester, workflowRunId, messageId,
|
|
148
|
+
var getSteps = async (requester, workflowRunId, messageId, dispatchDebug) => {
|
|
139
149
|
try {
|
|
140
150
|
const steps = await requester.request({
|
|
141
151
|
path: ["v2", "workflows", "runs", workflowRunId],
|
|
142
152
|
parseResponseAsJson: true
|
|
143
153
|
});
|
|
154
|
+
if (steps.length === 1) {
|
|
155
|
+
return {
|
|
156
|
+
steps,
|
|
157
|
+
workflowRunEnded: false
|
|
158
|
+
};
|
|
159
|
+
}
|
|
144
160
|
if (!messageId) {
|
|
145
|
-
await
|
|
146
|
-
|
|
161
|
+
await dispatchDebug?.("onInfo", {
|
|
162
|
+
info: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
147
163
|
});
|
|
148
164
|
return { steps, workflowRunEnded: false };
|
|
149
165
|
} else {
|
|
@@ -152,16 +168,15 @@ var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
|
152
168
|
return { steps: [], workflowRunEnded: false };
|
|
153
169
|
}
|
|
154
170
|
const filteredSteps = steps.slice(0, index + 1);
|
|
155
|
-
await
|
|
156
|
-
|
|
171
|
+
await dispatchDebug?.("onInfo", {
|
|
172
|
+
info: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
|
|
157
173
|
});
|
|
158
174
|
return { steps: filteredSteps, workflowRunEnded: false };
|
|
159
175
|
}
|
|
160
176
|
} catch (error) {
|
|
161
177
|
if (isInstanceOf(error, import_qstash2.QstashError) && error.status === 404) {
|
|
162
|
-
await
|
|
163
|
-
|
|
164
|
-
error
|
|
178
|
+
await dispatchDebug?.("onWarning", {
|
|
179
|
+
warning: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed."
|
|
165
180
|
});
|
|
166
181
|
return { steps: void 0, workflowRunEnded: true };
|
|
167
182
|
} else {
|
|
@@ -175,15 +190,18 @@ var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
|
|
|
175
190
|
var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
|
|
176
191
|
var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
|
|
177
192
|
var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
|
|
193
|
+
var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
|
|
178
194
|
var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
|
|
179
195
|
var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
|
|
180
196
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
197
|
+
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
198
|
+
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
181
199
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
182
200
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
183
201
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
184
202
|
var NO_CONCURRENCY = 1;
|
|
185
203
|
var DEFAULT_RETRIES = 3;
|
|
186
|
-
var VERSION = "
|
|
204
|
+
var VERSION = "v1.0.0";
|
|
187
205
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
188
206
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
189
207
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -201,8 +219,8 @@ var NANOID_LENGTH = 21;
|
|
|
201
219
|
function getRandomInt() {
|
|
202
220
|
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
203
221
|
}
|
|
204
|
-
function nanoid() {
|
|
205
|
-
return Array.from({ length
|
|
222
|
+
function nanoid(length = NANOID_LENGTH) {
|
|
223
|
+
return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
|
|
206
224
|
}
|
|
207
225
|
function getWorkflowRunId(id) {
|
|
208
226
|
return `wfr_${id ?? nanoid()}`;
|
|
@@ -219,6 +237,46 @@ function decodeBase64(base64) {
|
|
|
219
237
|
return binString;
|
|
220
238
|
}
|
|
221
239
|
}
|
|
240
|
+
function getUserIdFromToken(qstashClient) {
|
|
241
|
+
try {
|
|
242
|
+
const token = qstashClient.token;
|
|
243
|
+
const decodedToken = decodeBase64(token);
|
|
244
|
+
const tokenPayload = JSON.parse(decodedToken);
|
|
245
|
+
const userId = tokenPayload.UserID;
|
|
246
|
+
if (!userId) {
|
|
247
|
+
throw new WorkflowError("QStash token payload does not contain userId");
|
|
248
|
+
}
|
|
249
|
+
return userId;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
throw new WorkflowError(
|
|
252
|
+
`Failed to decode QStash token while running create webhook step: ${error.message}`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function getQStashUrl(qstashClient) {
|
|
257
|
+
try {
|
|
258
|
+
const requester = qstashClient.http;
|
|
259
|
+
const baseUrl = requester.baseUrl;
|
|
260
|
+
if (!baseUrl) {
|
|
261
|
+
throw new WorkflowError("QStash client does not have a baseUrl");
|
|
262
|
+
}
|
|
263
|
+
return baseUrl;
|
|
264
|
+
} catch (error) {
|
|
265
|
+
throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function getEventId() {
|
|
269
|
+
return `evt_${nanoid(15)}`;
|
|
270
|
+
}
|
|
271
|
+
function stringifyBody(body) {
|
|
272
|
+
if (body === void 0) {
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
if (typeof body === "string") {
|
|
276
|
+
return body;
|
|
277
|
+
}
|
|
278
|
+
return JSON.stringify(body);
|
|
279
|
+
}
|
|
222
280
|
|
|
223
281
|
// node_modules/neverthrow/dist/index.es.js
|
|
224
282
|
var defaultErrorConfig = {
|
|
@@ -644,7 +702,9 @@ var StepTypes = [
|
|
|
644
702
|
"Call",
|
|
645
703
|
"Wait",
|
|
646
704
|
"Notify",
|
|
647
|
-
"Invoke"
|
|
705
|
+
"Invoke",
|
|
706
|
+
"CreateWebhook",
|
|
707
|
+
"WaitForWebhook"
|
|
648
708
|
];
|
|
649
709
|
|
|
650
710
|
// src/workflow-requests.ts
|
|
@@ -660,23 +720,26 @@ var triggerFirstInvocation = async (params) => {
|
|
|
660
720
|
invokeCount,
|
|
661
721
|
delay,
|
|
662
722
|
notBefore,
|
|
663
|
-
|
|
723
|
+
failureUrl,
|
|
724
|
+
retries,
|
|
725
|
+
retryDelay,
|
|
726
|
+
flowControl,
|
|
727
|
+
unknownSdk
|
|
664
728
|
}) => {
|
|
665
729
|
const { headers } = getHeaders({
|
|
666
730
|
initHeaderValue: "true",
|
|
667
731
|
workflowConfig: {
|
|
668
732
|
workflowRunId: workflowContext.workflowRunId,
|
|
669
733
|
workflowUrl: workflowContext.url,
|
|
670
|
-
failureUrl
|
|
671
|
-
retries
|
|
672
|
-
retryDelay
|
|
734
|
+
failureUrl,
|
|
735
|
+
retries,
|
|
736
|
+
retryDelay,
|
|
673
737
|
telemetry,
|
|
674
|
-
flowControl
|
|
738
|
+
flowControl,
|
|
675
739
|
useJSONContent: useJSONContent ?? false
|
|
676
740
|
},
|
|
677
741
|
invokeCount: invokeCount ?? 0,
|
|
678
|
-
userHeaders: workflowContext.headers
|
|
679
|
-
keepTriggerConfig
|
|
742
|
+
userHeaders: workflowContext.headers
|
|
680
743
|
});
|
|
681
744
|
if (workflowContext.headers.get("content-type")) {
|
|
682
745
|
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
@@ -684,6 +747,9 @@ var triggerFirstInvocation = async (params) => {
|
|
|
684
747
|
if (useJSONContent) {
|
|
685
748
|
headers["content-type"] = "application/json";
|
|
686
749
|
}
|
|
750
|
+
if (unknownSdk) {
|
|
751
|
+
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
752
|
+
}
|
|
687
753
|
if (workflowContext.label) {
|
|
688
754
|
headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
|
|
689
755
|
}
|
|
@@ -704,21 +770,15 @@ var triggerFirstInvocation = async (params) => {
|
|
|
704
770
|
for (let i = 0; i < results.length; i++) {
|
|
705
771
|
const result = results[i];
|
|
706
772
|
const invocationParams = firstInvocationParams[i];
|
|
773
|
+
invocationParams.middlewareManager?.assignContext(invocationParams.workflowContext);
|
|
707
774
|
if (result.deduplicated) {
|
|
708
|
-
await invocationParams.
|
|
709
|
-
|
|
710
|
-
headers: invocationBatch[i].headers,
|
|
711
|
-
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
712
|
-
url: invocationParams.workflowContext.url,
|
|
713
|
-
messageId: result.messageId
|
|
775
|
+
await invocationParams.middlewareManager?.dispatchDebug("onWarning", {
|
|
776
|
+
warning: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`
|
|
714
777
|
});
|
|
715
778
|
invocationStatuses.push("workflow-run-already-exists");
|
|
716
779
|
} else {
|
|
717
|
-
await invocationParams.
|
|
718
|
-
|
|
719
|
-
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
720
|
-
url: invocationParams.workflowContext.url,
|
|
721
|
-
messageId: result.messageId
|
|
780
|
+
await invocationParams.middlewareManager?.dispatchDebug("onInfo", {
|
|
781
|
+
info: `Workflow run started successfully with URL ${invocationParams.workflowContext.url}.`
|
|
722
782
|
});
|
|
723
783
|
invocationStatuses.push("success");
|
|
724
784
|
}
|
|
@@ -740,7 +800,7 @@ var triggerRouteFunction = async ({
|
|
|
740
800
|
onCleanup,
|
|
741
801
|
onStep,
|
|
742
802
|
onCancel,
|
|
743
|
-
|
|
803
|
+
middlewareManager
|
|
744
804
|
}) => {
|
|
745
805
|
try {
|
|
746
806
|
const result = await onStep();
|
|
@@ -749,27 +809,25 @@ var triggerRouteFunction = async ({
|
|
|
749
809
|
} catch (error) {
|
|
750
810
|
const error_ = error;
|
|
751
811
|
if (isInstanceOf(error, import_qstash3.QstashError) && error.status === 400) {
|
|
752
|
-
await
|
|
753
|
-
|
|
754
|
-
name: error.name,
|
|
755
|
-
errorMessage: error.message
|
|
812
|
+
await middlewareManager?.dispatchDebug("onWarning", {
|
|
813
|
+
warning: `Tried to append to a cancelled workflow. Exiting without publishing. Error: ${error.message}`
|
|
756
814
|
});
|
|
757
815
|
return ok("workflow-was-finished");
|
|
758
816
|
} else if (isInstanceOf(error_, WorkflowNonRetryableError) || isInstanceOf(error_, WorkflowRetryAfterError)) {
|
|
759
817
|
return ok(error_);
|
|
760
|
-
} else if (
|
|
761
|
-
return err(error_);
|
|
762
|
-
} else if (error_.cancelWorkflow) {
|
|
818
|
+
} else if (isInstanceOf(error_, WorkflowCancelAbort)) {
|
|
763
819
|
await onCancel();
|
|
764
820
|
return ok("workflow-finished");
|
|
765
|
-
} else {
|
|
821
|
+
} else if (isInstanceOf(error_, WorkflowAbort)) {
|
|
766
822
|
return ok("step-finished");
|
|
823
|
+
} else {
|
|
824
|
+
return err(error_);
|
|
767
825
|
}
|
|
768
826
|
}
|
|
769
827
|
};
|
|
770
|
-
var triggerWorkflowDelete = async (workflowContext, result,
|
|
771
|
-
await
|
|
772
|
-
|
|
828
|
+
var triggerWorkflowDelete = async (workflowContext, result, cancel = false, dispatchDebug) => {
|
|
829
|
+
await dispatchDebug?.("onInfo", {
|
|
830
|
+
info: `Deleting workflow run ${workflowContext.workflowRunId} from QStash` + (cancel ? " with cancel=true." : ".")
|
|
773
831
|
});
|
|
774
832
|
await workflowContext.qstashClient.http.request({
|
|
775
833
|
path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
|
|
@@ -777,18 +835,16 @@ var triggerWorkflowDelete = async (workflowContext, result, debug, cancel = fals
|
|
|
777
835
|
parseResponseAsJson: false,
|
|
778
836
|
body: JSON.stringify(result)
|
|
779
837
|
});
|
|
780
|
-
await
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
`workflow run ${workflowContext.workflowRunId} deleted.`
|
|
784
|
-
);
|
|
838
|
+
await dispatchDebug?.("onInfo", {
|
|
839
|
+
info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
|
|
840
|
+
});
|
|
785
841
|
};
|
|
786
842
|
var recreateUserHeaders = (headers) => {
|
|
787
843
|
const filteredHeaders = new Headers();
|
|
788
844
|
const pairs = headers.entries();
|
|
789
845
|
for (const [header, value] of pairs) {
|
|
790
846
|
const headerLowerCase = header.toLowerCase();
|
|
791
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
847
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
792
848
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
793
849
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
794
850
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -803,12 +859,8 @@ var handleThirdPartyCallResult = async ({
|
|
|
803
859
|
requestPayload,
|
|
804
860
|
client,
|
|
805
861
|
workflowUrl,
|
|
806
|
-
failureUrl,
|
|
807
|
-
retries,
|
|
808
|
-
retryDelay,
|
|
809
862
|
telemetry,
|
|
810
|
-
|
|
811
|
-
debug
|
|
863
|
+
middlewareManager
|
|
812
864
|
}) => {
|
|
813
865
|
try {
|
|
814
866
|
if (request.headers.get("Upstash-Workflow-Callback")) {
|
|
@@ -825,7 +877,7 @@ var handleThirdPartyCallResult = async ({
|
|
|
825
877
|
client.http,
|
|
826
878
|
workflowRunId2,
|
|
827
879
|
messageId,
|
|
828
|
-
|
|
880
|
+
middlewareManager?.dispatchDebug.bind(middlewareManager)
|
|
829
881
|
);
|
|
830
882
|
if (workflowRunEnded) {
|
|
831
883
|
return ok("workflow-ended");
|
|
@@ -839,9 +891,8 @@ var handleThirdPartyCallResult = async ({
|
|
|
839
891
|
}
|
|
840
892
|
const callbackMessage = JSON.parse(callbackPayload);
|
|
841
893
|
if (!(callbackMessage.status >= 200 && callbackMessage.status < 300) && callbackMessage.maxRetries && callbackMessage.retried !== callbackMessage.maxRetries) {
|
|
842
|
-
await
|
|
843
|
-
|
|
844
|
-
body: atob(callbackMessage.body ?? "")
|
|
894
|
+
await middlewareManager?.dispatchDebug("onWarning", {
|
|
895
|
+
warning: `Third party call returned status ${callbackMessage.status}. Retrying (${callbackMessage.retried} out of ${callbackMessage.maxRetries}).`
|
|
845
896
|
});
|
|
846
897
|
console.warn(
|
|
847
898
|
`Workflow Warning: "context.call" failed with status ${callbackMessage.status} and will retry (retried ${callbackMessage.retried ?? 0} out of ${callbackMessage.maxRetries} times). Error Message:
|
|
@@ -874,11 +925,7 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
874
925
|
workflowConfig: {
|
|
875
926
|
workflowRunId,
|
|
876
927
|
workflowUrl,
|
|
877
|
-
|
|
878
|
-
retries,
|
|
879
|
-
retryDelay,
|
|
880
|
-
telemetry,
|
|
881
|
-
flowControl
|
|
928
|
+
telemetry
|
|
882
929
|
},
|
|
883
930
|
userHeaders,
|
|
884
931
|
invokeCount: Number(invokeCount)
|
|
@@ -895,19 +942,17 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
895
942
|
out: JSON.stringify(callResponse),
|
|
896
943
|
concurrent: Number(concurrentString)
|
|
897
944
|
};
|
|
898
|
-
await
|
|
899
|
-
|
|
900
|
-
headers: requestHeaders,
|
|
901
|
-
url: workflowUrl
|
|
945
|
+
await middlewareManager?.dispatchDebug("onInfo", {
|
|
946
|
+
info: `Submitting third party call result, step ${stepName} (${stepIdString}).`
|
|
902
947
|
});
|
|
903
|
-
|
|
948
|
+
await client.publishJSON({
|
|
904
949
|
headers: requestHeaders,
|
|
905
950
|
method: "POST",
|
|
906
951
|
body: callResultStep,
|
|
907
952
|
url: workflowUrl
|
|
908
953
|
});
|
|
909
|
-
await
|
|
910
|
-
|
|
954
|
+
await middlewareManager?.dispatchDebug("onInfo", {
|
|
955
|
+
info: `Third party call result submitted successfully, step ${stepName} (${stepIdString}).`
|
|
911
956
|
});
|
|
912
957
|
return ok("is-call-return");
|
|
913
958
|
} else {
|
|
@@ -956,15 +1001,17 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
|
|
|
956
1001
|
// src/context/steps.ts
|
|
957
1002
|
var BaseLazyStep = class _BaseLazyStep {
|
|
958
1003
|
stepName;
|
|
959
|
-
|
|
1004
|
+
context;
|
|
1005
|
+
constructor(context, stepName) {
|
|
1006
|
+
this.context = context;
|
|
960
1007
|
if (!stepName) {
|
|
961
1008
|
throw new WorkflowError(
|
|
962
1009
|
"A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
|
|
963
1010
|
);
|
|
964
1011
|
}
|
|
965
1012
|
if (typeof stepName !== "string") {
|
|
966
|
-
|
|
967
|
-
|
|
1013
|
+
throw new WorkflowError(
|
|
1014
|
+
`A workflow step name must be a string. Received "${stepName}" (${typeof stepName}).`
|
|
968
1015
|
);
|
|
969
1016
|
}
|
|
970
1017
|
this.stepName = stepName;
|
|
@@ -974,13 +1021,14 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
974
1021
|
*
|
|
975
1022
|
* will be called when returning the steps to the context from auto executor
|
|
976
1023
|
*
|
|
977
|
-
* @param
|
|
1024
|
+
* @param step step
|
|
978
1025
|
* @returns parsed out field
|
|
979
1026
|
*/
|
|
980
|
-
parseOut(
|
|
1027
|
+
parseOut(step) {
|
|
1028
|
+
const out = step.out;
|
|
981
1029
|
if (out === void 0) {
|
|
982
1030
|
if (this.allowUndefinedOut) {
|
|
983
|
-
return
|
|
1031
|
+
return this.handleUndefinedOut(step);
|
|
984
1032
|
} else {
|
|
985
1033
|
throw new WorkflowError(
|
|
986
1034
|
`Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
|
|
@@ -988,27 +1036,26 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
988
1036
|
}
|
|
989
1037
|
}
|
|
990
1038
|
if (typeof out === "object") {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
return out;
|
|
996
|
-
}
|
|
997
|
-
return {
|
|
998
|
-
...out,
|
|
999
|
-
eventData: _BaseLazyStep.tryParsing(out.eventData)
|
|
1000
|
-
};
|
|
1039
|
+
console.warn(
|
|
1040
|
+
`Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
|
|
1041
|
+
);
|
|
1042
|
+
return out;
|
|
1001
1043
|
}
|
|
1002
1044
|
if (typeof out !== "string") {
|
|
1003
1045
|
throw new WorkflowError(
|
|
1004
1046
|
`Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
|
|
1005
1047
|
);
|
|
1006
1048
|
}
|
|
1007
|
-
return this.safeParseOut(out);
|
|
1049
|
+
return this.safeParseOut(out, step);
|
|
1008
1050
|
}
|
|
1009
|
-
|
|
1051
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1052
|
+
safeParseOut(out, step) {
|
|
1010
1053
|
return _BaseLazyStep.tryParsing(out);
|
|
1011
1054
|
}
|
|
1055
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1056
|
+
handleUndefinedOut(step) {
|
|
1057
|
+
return void 0;
|
|
1058
|
+
}
|
|
1012
1059
|
static tryParsing(stepOut) {
|
|
1013
1060
|
try {
|
|
1014
1061
|
return JSON.parse(stepOut);
|
|
@@ -1026,12 +1073,8 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1026
1073
|
workflowConfig: {
|
|
1027
1074
|
workflowRunId: context.workflowRunId,
|
|
1028
1075
|
workflowUrl: context.url,
|
|
1029
|
-
failureUrl: context.failureUrl,
|
|
1030
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1031
|
-
retryDelay: context.retryDelay,
|
|
1032
1076
|
useJSONContent: false,
|
|
1033
|
-
telemetry
|
|
1034
|
-
flowControl: context.flowControl
|
|
1077
|
+
telemetry
|
|
1035
1078
|
},
|
|
1036
1079
|
userHeaders: context.headers,
|
|
1037
1080
|
invokeCount,
|
|
@@ -1047,9 +1090,6 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1047
1090
|
body,
|
|
1048
1091
|
headers,
|
|
1049
1092
|
method: "POST",
|
|
1050
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1051
|
-
retryDelay: context.retryDelay,
|
|
1052
|
-
flowControl: context.flowControl,
|
|
1053
1093
|
url: context.url
|
|
1054
1094
|
}
|
|
1055
1095
|
]);
|
|
@@ -1059,8 +1099,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
|
|
|
1059
1099
|
stepFunction;
|
|
1060
1100
|
stepType = "Run";
|
|
1061
1101
|
allowUndefinedOut = true;
|
|
1062
|
-
constructor(stepName, stepFunction) {
|
|
1063
|
-
super(stepName);
|
|
1102
|
+
constructor(context, stepName, stepFunction) {
|
|
1103
|
+
super(context, stepName);
|
|
1064
1104
|
this.stepFunction = stepFunction;
|
|
1065
1105
|
}
|
|
1066
1106
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -1090,8 +1130,8 @@ var LazySleepStep = class extends BaseLazyStep {
|
|
|
1090
1130
|
sleep;
|
|
1091
1131
|
stepType = "SleepFor";
|
|
1092
1132
|
allowUndefinedOut = true;
|
|
1093
|
-
constructor(stepName, sleep) {
|
|
1094
|
-
super(stepName);
|
|
1133
|
+
constructor(context, stepName, sleep) {
|
|
1134
|
+
super(context, stepName);
|
|
1095
1135
|
this.sleep = sleep;
|
|
1096
1136
|
}
|
|
1097
1137
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -1120,9 +1160,6 @@ var LazySleepStep = class extends BaseLazyStep {
|
|
|
1120
1160
|
headers,
|
|
1121
1161
|
method: "POST",
|
|
1122
1162
|
url: context.url,
|
|
1123
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1124
|
-
retryDelay: context.retryDelay,
|
|
1125
|
-
flowControl: context.flowControl,
|
|
1126
1163
|
delay: isParallel ? void 0 : this.sleep
|
|
1127
1164
|
}
|
|
1128
1165
|
]);
|
|
@@ -1132,8 +1169,8 @@ var LazySleepUntilStep = class extends BaseLazyStep {
|
|
|
1132
1169
|
sleepUntil;
|
|
1133
1170
|
stepType = "SleepUntil";
|
|
1134
1171
|
allowUndefinedOut = true;
|
|
1135
|
-
constructor(stepName, sleepUntil) {
|
|
1136
|
-
super(stepName);
|
|
1172
|
+
constructor(context, stepName, sleepUntil) {
|
|
1173
|
+
super(context, stepName);
|
|
1137
1174
|
this.sleepUntil = sleepUntil;
|
|
1138
1175
|
}
|
|
1139
1176
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -1165,9 +1202,6 @@ var LazySleepUntilStep = class extends BaseLazyStep {
|
|
|
1165
1202
|
headers,
|
|
1166
1203
|
method: "POST",
|
|
1167
1204
|
url: context.url,
|
|
1168
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1169
|
-
retryDelay: context.retryDelay,
|
|
1170
|
-
flowControl: context.flowControl,
|
|
1171
1205
|
notBefore: isParallel ? void 0 : this.sleepUntil
|
|
1172
1206
|
}
|
|
1173
1207
|
]);
|
|
@@ -1182,20 +1216,18 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1182
1216
|
retryDelay;
|
|
1183
1217
|
timeout;
|
|
1184
1218
|
flowControl;
|
|
1185
|
-
stringifyBody;
|
|
1186
1219
|
stepType = "Call";
|
|
1187
1220
|
allowUndefinedOut = false;
|
|
1188
|
-
constructor(
|
|
1189
|
-
super(stepName);
|
|
1190
|
-
this.url = url;
|
|
1191
|
-
this.method = method;
|
|
1192
|
-
this.body = body;
|
|
1193
|
-
this.headers = headers;
|
|
1194
|
-
this.retries = retries;
|
|
1195
|
-
this.retryDelay = retryDelay;
|
|
1196
|
-
this.timeout = timeout;
|
|
1197
|
-
this.flowControl = flowControl;
|
|
1198
|
-
this.stringifyBody = stringifyBody;
|
|
1221
|
+
constructor(params) {
|
|
1222
|
+
super(params.context, params.stepName);
|
|
1223
|
+
this.url = params.url;
|
|
1224
|
+
this.method = params.method ?? "GET";
|
|
1225
|
+
this.body = params.body;
|
|
1226
|
+
this.headers = params.headers ?? {};
|
|
1227
|
+
this.retries = params.retries ?? 0;
|
|
1228
|
+
this.retryDelay = params.retryDelay;
|
|
1229
|
+
this.timeout = params.timeout;
|
|
1230
|
+
this.flowControl = params.flowControl;
|
|
1199
1231
|
}
|
|
1200
1232
|
getPlanStep(concurrent, targetStep) {
|
|
1201
1233
|
return {
|
|
@@ -1292,7 +1324,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1292
1324
|
"Upstash-Callback-Workflow-CallType": "fromCallback",
|
|
1293
1325
|
"Upstash-Callback-Workflow-Init": "false",
|
|
1294
1326
|
"Upstash-Callback-Workflow-Url": context.url,
|
|
1295
|
-
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger",
|
|
1327
|
+
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
|
|
1296
1328
|
"Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
|
|
1297
1329
|
"Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
|
|
1298
1330
|
"Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
|
|
@@ -1305,22 +1337,10 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1305
1337
|
};
|
|
1306
1338
|
}
|
|
1307
1339
|
async submitStep({ context, headers }) {
|
|
1308
|
-
let callBody;
|
|
1309
|
-
if (this.stringifyBody) {
|
|
1310
|
-
callBody = JSON.stringify(this.body);
|
|
1311
|
-
} else {
|
|
1312
|
-
if (typeof this.body === "string") {
|
|
1313
|
-
callBody = this.body;
|
|
1314
|
-
} else {
|
|
1315
|
-
throw new WorkflowError(
|
|
1316
|
-
"When stringifyBody is false, body must be a string. Please check the body type of your call step."
|
|
1317
|
-
);
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
1340
|
return await context.qstashClient.batch([
|
|
1321
1341
|
{
|
|
1322
1342
|
headers,
|
|
1323
|
-
body:
|
|
1343
|
+
body: this.body,
|
|
1324
1344
|
method: this.method,
|
|
1325
1345
|
url: this.url,
|
|
1326
1346
|
retries: DEFAULT_RETRIES === this.retries ? void 0 : this.retries,
|
|
@@ -1330,13 +1350,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1330
1350
|
]);
|
|
1331
1351
|
}
|
|
1332
1352
|
};
|
|
1333
|
-
var
|
|
1353
|
+
var LazyWaitEventStep = class extends BaseLazyStep {
|
|
1334
1354
|
eventId;
|
|
1335
1355
|
timeout;
|
|
1336
|
-
stepType = "Wait";
|
|
1337
1356
|
allowUndefinedOut = false;
|
|
1338
|
-
constructor(stepName, eventId, timeout) {
|
|
1339
|
-
super(stepName);
|
|
1357
|
+
constructor(context, stepName, eventId, timeout) {
|
|
1358
|
+
super(context, stepName);
|
|
1340
1359
|
this.eventId = eventId;
|
|
1341
1360
|
this.timeout = timeout;
|
|
1342
1361
|
}
|
|
@@ -1361,13 +1380,6 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1361
1380
|
concurrent
|
|
1362
1381
|
});
|
|
1363
1382
|
}
|
|
1364
|
-
safeParseOut(out) {
|
|
1365
|
-
const result = JSON.parse(out);
|
|
1366
|
-
return {
|
|
1367
|
-
...result,
|
|
1368
|
-
eventData: BaseLazyStep.tryParsing(result.eventData)
|
|
1369
|
-
};
|
|
1370
|
-
}
|
|
1371
1383
|
getHeaders({ context, telemetry, invokeCount, step }) {
|
|
1372
1384
|
const headers = super.getHeaders({ context, telemetry, invokeCount, step });
|
|
1373
1385
|
headers.headers["Upstash-Workflow-CallType"] = "step";
|
|
@@ -1401,7 +1413,7 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1401
1413
|
timeoutHeaders,
|
|
1402
1414
|
step: {
|
|
1403
1415
|
stepId: step.stepId,
|
|
1404
|
-
stepType:
|
|
1416
|
+
stepType: this.stepType,
|
|
1405
1417
|
stepName: step.stepName,
|
|
1406
1418
|
concurrent: step.concurrent,
|
|
1407
1419
|
targetStep: step.targetStep
|
|
@@ -1422,8 +1434,8 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1422
1434
|
};
|
|
1423
1435
|
var LazyNotifyStep = class extends LazyFunctionStep {
|
|
1424
1436
|
stepType = "Notify";
|
|
1425
|
-
constructor(stepName, eventId, eventData, requester) {
|
|
1426
|
-
super(stepName, async () => {
|
|
1437
|
+
constructor(context, stepName, eventId, eventData, requester) {
|
|
1438
|
+
super(context, stepName, async () => {
|
|
1427
1439
|
const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
|
|
1428
1440
|
return {
|
|
1429
1441
|
eventId,
|
|
@@ -1448,28 +1460,10 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1448
1460
|
* workflow id of the invoked workflow
|
|
1449
1461
|
*/
|
|
1450
1462
|
workflowId;
|
|
1451
|
-
constructor(stepName, {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
workflowRunId,
|
|
1456
|
-
retries,
|
|
1457
|
-
retryDelay,
|
|
1458
|
-
flowControl,
|
|
1459
|
-
stringifyBody = true
|
|
1460
|
-
}) {
|
|
1461
|
-
super(stepName);
|
|
1462
|
-
this.params = {
|
|
1463
|
-
workflow,
|
|
1464
|
-
body,
|
|
1465
|
-
headers,
|
|
1466
|
-
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
1467
|
-
retries,
|
|
1468
|
-
retryDelay,
|
|
1469
|
-
flowControl,
|
|
1470
|
-
stringifyBody
|
|
1471
|
-
};
|
|
1472
|
-
const { workflowId } = workflow;
|
|
1463
|
+
constructor(context, stepName, params) {
|
|
1464
|
+
super(context, stepName);
|
|
1465
|
+
this.params = params;
|
|
1466
|
+
const { workflowId } = params.workflow;
|
|
1473
1467
|
if (!workflowId) {
|
|
1474
1468
|
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1475
1469
|
}
|
|
@@ -1509,31 +1503,18 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1509
1503
|
workflowConfig: {
|
|
1510
1504
|
workflowRunId: context.workflowRunId,
|
|
1511
1505
|
workflowUrl: context.url,
|
|
1512
|
-
failureUrl: context.failureUrl,
|
|
1513
|
-
retries: context.retries,
|
|
1514
|
-
retryDelay: context.retryDelay,
|
|
1515
1506
|
telemetry,
|
|
1516
|
-
flowControl: context.flowControl,
|
|
1517
1507
|
useJSONContent: false
|
|
1518
1508
|
},
|
|
1519
1509
|
userHeaders: context.headers,
|
|
1520
1510
|
invokeCount
|
|
1521
1511
|
});
|
|
1512
|
+
context.qstashClient.http.headers?.forEach((value, key) => {
|
|
1513
|
+
invokerHeaders[key] = value;
|
|
1514
|
+
});
|
|
1522
1515
|
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1523
|
-
let invokeBody;
|
|
1524
|
-
if (this.params.stringifyBody) {
|
|
1525
|
-
invokeBody = JSON.stringify(this.params.body);
|
|
1526
|
-
} else {
|
|
1527
|
-
if (typeof this.params.body === "string") {
|
|
1528
|
-
invokeBody = this.params.body;
|
|
1529
|
-
} else {
|
|
1530
|
-
throw new WorkflowError(
|
|
1531
|
-
"When stringifyBody is false, body must be a string. Please check the body type of your invoke step."
|
|
1532
|
-
);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
1516
|
const request = {
|
|
1536
|
-
body:
|
|
1517
|
+
body: stringifyBody(this.params.body),
|
|
1537
1518
|
headers: Object.fromEntries(
|
|
1538
1519
|
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1539
1520
|
),
|
|
@@ -1544,34 +1525,19 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1544
1525
|
return JSON.stringify(request);
|
|
1545
1526
|
}
|
|
1546
1527
|
getHeaders({ context, telemetry, invokeCount }) {
|
|
1547
|
-
const {
|
|
1548
|
-
workflow,
|
|
1549
|
-
headers = {},
|
|
1550
|
-
workflowRunId = getWorkflowRunId(),
|
|
1551
|
-
retries,
|
|
1552
|
-
retryDelay,
|
|
1553
|
-
flowControl
|
|
1554
|
-
} = this.params;
|
|
1528
|
+
const { workflow, headers = {}, workflowRunId, retries, retryDelay, flowControl } = this.params;
|
|
1555
1529
|
const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
|
|
1556
|
-
const {
|
|
1557
|
-
retries: workflowRetries,
|
|
1558
|
-
retryDelay: workflowRetryDelay,
|
|
1559
|
-
failureFunction,
|
|
1560
|
-
failureUrl,
|
|
1561
|
-
useJSONContent,
|
|
1562
|
-
flowControl: workflowFlowControl
|
|
1563
|
-
} = workflow.options;
|
|
1564
1530
|
const { headers: triggerHeaders, contentType } = getHeaders({
|
|
1565
1531
|
initHeaderValue: "true",
|
|
1566
1532
|
workflowConfig: {
|
|
1567
|
-
workflowRunId,
|
|
1533
|
+
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
1568
1534
|
workflowUrl: newUrl,
|
|
1569
|
-
retries
|
|
1570
|
-
retryDelay
|
|
1535
|
+
retries,
|
|
1536
|
+
retryDelay,
|
|
1571
1537
|
telemetry,
|
|
1572
|
-
failureUrl:
|
|
1573
|
-
flowControl
|
|
1574
|
-
useJSONContent: useJSONContent ?? false
|
|
1538
|
+
failureUrl: newUrl,
|
|
1539
|
+
flowControl,
|
|
1540
|
+
useJSONContent: workflow.useJSONContent ?? false
|
|
1575
1541
|
},
|
|
1576
1542
|
invokeCount: invokeCount + 1,
|
|
1577
1543
|
userHeaders: new Headers(headers)
|
|
@@ -1590,6 +1556,88 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1590
1556
|
return [result];
|
|
1591
1557
|
}
|
|
1592
1558
|
};
|
|
1559
|
+
var LazyCreateWebhookStep = class extends BaseLazyStep {
|
|
1560
|
+
stepType = "CreateWebhook";
|
|
1561
|
+
allowUndefinedOut = false;
|
|
1562
|
+
getPlanStep(concurrent, targetStep) {
|
|
1563
|
+
return {
|
|
1564
|
+
stepId: 0,
|
|
1565
|
+
stepName: this.stepName,
|
|
1566
|
+
stepType: this.stepType,
|
|
1567
|
+
concurrent,
|
|
1568
|
+
targetStep
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
async getResultStep(concurrent, stepId) {
|
|
1572
|
+
return {
|
|
1573
|
+
stepId,
|
|
1574
|
+
stepName: this.stepName,
|
|
1575
|
+
stepType: this.stepType,
|
|
1576
|
+
out: void 0,
|
|
1577
|
+
concurrent
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
getBody({ step, context }) {
|
|
1581
|
+
const userId = getUserIdFromToken(context.qstashClient);
|
|
1582
|
+
const workflowRunId = context.workflowRunId;
|
|
1583
|
+
const eventId = getEventId();
|
|
1584
|
+
const qstashUrl = getQStashUrl(this.context.qstashClient);
|
|
1585
|
+
return JSON.stringify({
|
|
1586
|
+
...step,
|
|
1587
|
+
out: JSON.stringify({
|
|
1588
|
+
webhookUrl: `${qstashUrl}/v2/workflows/hooks/${userId}/${workflowRunId}/${eventId}`,
|
|
1589
|
+
eventId
|
|
1590
|
+
})
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
|
|
1595
|
+
stepType = "WaitForWebhook";
|
|
1596
|
+
allowUndefinedOut = true;
|
|
1597
|
+
constructor(context, stepName, webhook, timeout) {
|
|
1598
|
+
super(context, stepName, webhook.eventId, timeout);
|
|
1599
|
+
}
|
|
1600
|
+
safeParseOut(out) {
|
|
1601
|
+
const eventData = decodeBase64(out);
|
|
1602
|
+
const parsedEventData = BaseLazyStep.tryParsing(eventData);
|
|
1603
|
+
const body = parsedEventData.body;
|
|
1604
|
+
const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
|
|
1605
|
+
const request = new Request(
|
|
1606
|
+
`${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
|
|
1607
|
+
{
|
|
1608
|
+
method: parsedEventData.method,
|
|
1609
|
+
headers: parsedEventData.header,
|
|
1610
|
+
body: parsedBody
|
|
1611
|
+
}
|
|
1612
|
+
);
|
|
1613
|
+
return {
|
|
1614
|
+
request,
|
|
1615
|
+
timeout: false
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
handleUndefinedOut() {
|
|
1619
|
+
return {
|
|
1620
|
+
timeout: true,
|
|
1621
|
+
request: void 0
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
var LazyWaitForEventStep = class extends LazyWaitEventStep {
|
|
1626
|
+
stepType = "Wait";
|
|
1627
|
+
allowUndefinedOut = true;
|
|
1628
|
+
parseWaitForEventOut(out, waitTimeout) {
|
|
1629
|
+
return {
|
|
1630
|
+
eventData: out ? BaseLazyStep.tryParsing(decodeBase64(out)) : void 0,
|
|
1631
|
+
timeout: waitTimeout ?? false
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
safeParseOut(out, step) {
|
|
1635
|
+
return this.parseWaitForEventOut(out, step.waitTimeout);
|
|
1636
|
+
}
|
|
1637
|
+
handleUndefinedOut(step) {
|
|
1638
|
+
return this.parseWaitForEventOut(void 0, step.waitTimeout);
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1593
1641
|
|
|
1594
1642
|
// src/qstash/headers.ts
|
|
1595
1643
|
var WorkflowHeaders = class {
|
|
@@ -1599,14 +1647,15 @@ var WorkflowHeaders = class {
|
|
|
1599
1647
|
initHeaderValue;
|
|
1600
1648
|
stepInfo;
|
|
1601
1649
|
headers;
|
|
1602
|
-
|
|
1650
|
+
/**
|
|
1651
|
+
* @param params workflow header parameters
|
|
1652
|
+
*/
|
|
1603
1653
|
constructor({
|
|
1604
1654
|
userHeaders,
|
|
1605
1655
|
workflowConfig,
|
|
1606
1656
|
invokeCount,
|
|
1607
1657
|
initHeaderValue,
|
|
1608
|
-
stepInfo
|
|
1609
|
-
keepTriggerConfig
|
|
1658
|
+
stepInfo
|
|
1610
1659
|
}) {
|
|
1611
1660
|
this.userHeaders = userHeaders;
|
|
1612
1661
|
this.workflowConfig = workflowConfig;
|
|
@@ -1618,7 +1667,6 @@ var WorkflowHeaders = class {
|
|
|
1618
1667
|
workflowHeaders: {},
|
|
1619
1668
|
failureHeaders: {}
|
|
1620
1669
|
};
|
|
1621
|
-
this.keepTriggerConfig = keepTriggerConfig;
|
|
1622
1670
|
}
|
|
1623
1671
|
getHeaders() {
|
|
1624
1672
|
this.addBaseHeaders();
|
|
@@ -1637,7 +1685,7 @@ var WorkflowHeaders = class {
|
|
|
1637
1685
|
[WORKFLOW_INIT_HEADER]: this.initHeaderValue,
|
|
1638
1686
|
[WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
|
|
1639
1687
|
[WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
|
|
1640
|
-
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger
|
|
1688
|
+
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
|
|
1641
1689
|
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
1642
1690
|
...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
|
|
1643
1691
|
};
|
|
@@ -1707,12 +1755,12 @@ var WorkflowHeaders = class {
|
|
|
1707
1755
|
}
|
|
1708
1756
|
this.headers.workflowHeaders["Failure-Callback"] = this.workflowConfig.failureUrl;
|
|
1709
1757
|
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
1710
|
-
this.headers.failureHeaders[`Forward
|
|
1758
|
+
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_CALLBACK_HEADER}`] = "true";
|
|
1711
1759
|
this.headers.failureHeaders["Workflow-Runid"] = this.workflowConfig.workflowRunId;
|
|
1712
1760
|
this.headers.failureHeaders["Workflow-Init"] = "false";
|
|
1713
1761
|
this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
|
|
1714
1762
|
this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
|
|
1715
|
-
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger";
|
|
1763
|
+
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
|
|
1716
1764
|
if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
|
|
1717
1765
|
this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
|
|
1718
1766
|
}
|
|
@@ -1782,14 +1830,13 @@ var submitParallelSteps = async ({
|
|
|
1782
1830
|
initialStepCount,
|
|
1783
1831
|
invokeCount,
|
|
1784
1832
|
telemetry,
|
|
1785
|
-
|
|
1833
|
+
dispatchDebug
|
|
1786
1834
|
}) => {
|
|
1787
1835
|
const planSteps = steps.map(
|
|
1788
1836
|
(step, index) => step.getPlanStep(steps.length, initialStepCount + index)
|
|
1789
1837
|
);
|
|
1790
|
-
await
|
|
1791
|
-
|
|
1792
|
-
steps: planSteps
|
|
1838
|
+
await dispatchDebug("onInfo", {
|
|
1839
|
+
info: `Submitting ${planSteps.length} parallel steps.`
|
|
1793
1840
|
});
|
|
1794
1841
|
const result = await context.qstashClient.batch(
|
|
1795
1842
|
planSteps.map((planStep) => {
|
|
@@ -1798,10 +1845,6 @@ var submitParallelSteps = async ({
|
|
|
1798
1845
|
workflowConfig: {
|
|
1799
1846
|
workflowRunId: context.workflowRunId,
|
|
1800
1847
|
workflowUrl: context.url,
|
|
1801
|
-
failureUrl: context.failureUrl,
|
|
1802
|
-
retries: context.retries,
|
|
1803
|
-
retryDelay: context.retryDelay,
|
|
1804
|
-
flowControl: context.flowControl,
|
|
1805
1848
|
telemetry
|
|
1806
1849
|
},
|
|
1807
1850
|
userHeaders: context.headers,
|
|
@@ -1817,13 +1860,11 @@ var submitParallelSteps = async ({
|
|
|
1817
1860
|
};
|
|
1818
1861
|
})
|
|
1819
1862
|
);
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
})
|
|
1826
|
-
});
|
|
1863
|
+
if (result && result.length > 0) {
|
|
1864
|
+
await dispatchDebug("onInfo", {
|
|
1865
|
+
info: `Submitted ${planSteps.length} parallel steps. messageIds: ${result.filter((r) => r).map((r) => r.messageId).join(", ")}.`
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1827
1868
|
throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
|
|
1828
1869
|
};
|
|
1829
1870
|
var submitSingleStep = async ({
|
|
@@ -1833,14 +1874,13 @@ var submitSingleStep = async ({
|
|
|
1833
1874
|
invokeCount,
|
|
1834
1875
|
concurrency,
|
|
1835
1876
|
telemetry,
|
|
1836
|
-
|
|
1877
|
+
dispatchDebug,
|
|
1878
|
+
dispatchLifecycle
|
|
1837
1879
|
}) => {
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
fromRequest: false,
|
|
1841
|
-
step: resultStep,
|
|
1842
|
-
stepCount: stepId
|
|
1880
|
+
await dispatchLifecycle("beforeExecution", {
|
|
1881
|
+
stepName: lazyStep.stepName
|
|
1843
1882
|
});
|
|
1883
|
+
const resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
1844
1884
|
const { headers } = lazyStep.getHeaders({
|
|
1845
1885
|
context,
|
|
1846
1886
|
step: resultStep,
|
|
@@ -1854,10 +1894,6 @@ var submitSingleStep = async ({
|
|
|
1854
1894
|
invokeCount,
|
|
1855
1895
|
telemetry
|
|
1856
1896
|
});
|
|
1857
|
-
await debug?.log("SUBMIT", "SUBMIT_STEP", {
|
|
1858
|
-
length: 1,
|
|
1859
|
-
steps: [resultStep]
|
|
1860
|
-
});
|
|
1861
1897
|
const submitResult = await lazyStep.submitStep({
|
|
1862
1898
|
context,
|
|
1863
1899
|
body,
|
|
@@ -1867,13 +1903,11 @@ var submitSingleStep = async ({
|
|
|
1867
1903
|
step: resultStep,
|
|
1868
1904
|
telemetry
|
|
1869
1905
|
});
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
})
|
|
1876
|
-
});
|
|
1906
|
+
if (submitResult && submitResult[0]) {
|
|
1907
|
+
await dispatchDebug("onInfo", {
|
|
1908
|
+
info: `Submitted step "${resultStep.stepName}" with messageId: ${submitResult[0].messageId}.`
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1877
1911
|
return resultStep;
|
|
1878
1912
|
};
|
|
1879
1913
|
|
|
@@ -1882,21 +1916,31 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1882
1916
|
context;
|
|
1883
1917
|
promises = /* @__PURE__ */ new WeakMap();
|
|
1884
1918
|
activeLazyStepList;
|
|
1885
|
-
debug;
|
|
1886
1919
|
nonPlanStepCount;
|
|
1887
1920
|
steps;
|
|
1888
1921
|
indexInCurrentList = 0;
|
|
1889
1922
|
invokeCount;
|
|
1890
1923
|
telemetry;
|
|
1924
|
+
dispatchDebug;
|
|
1925
|
+
dispatchLifecycle;
|
|
1891
1926
|
stepCount = 0;
|
|
1892
1927
|
planStepCount = 0;
|
|
1893
1928
|
executingStep = false;
|
|
1894
|
-
|
|
1929
|
+
/**
|
|
1930
|
+
* @param context workflow context
|
|
1931
|
+
* @param steps list of steps
|
|
1932
|
+
* @param dispatchDebug debug event dispatcher
|
|
1933
|
+
* @param dispatchLifecycle lifecycle event dispatcher
|
|
1934
|
+
* @param telemetry optional telemetry information
|
|
1935
|
+
* @param invokeCount optional invoke count
|
|
1936
|
+
*/
|
|
1937
|
+
constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry, invokeCount) {
|
|
1895
1938
|
this.context = context;
|
|
1896
1939
|
this.steps = steps;
|
|
1940
|
+
this.dispatchDebug = dispatchDebug;
|
|
1941
|
+
this.dispatchLifecycle = dispatchLifecycle;
|
|
1897
1942
|
this.telemetry = telemetry;
|
|
1898
1943
|
this.invokeCount = invokeCount ?? 0;
|
|
1899
|
-
this.debug = debug;
|
|
1900
1944
|
this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
|
|
1901
1945
|
}
|
|
1902
1946
|
/**
|
|
@@ -1964,7 +2008,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1964
2008
|
/**
|
|
1965
2009
|
* Executes a step:
|
|
1966
2010
|
* - If the step result is available in the steps, returns the result
|
|
1967
|
-
* - If the result is not
|
|
2011
|
+
* - If the result is not available, runs the function
|
|
1968
2012
|
* - Sends the result to QStash
|
|
1969
2013
|
*
|
|
1970
2014
|
* @param lazyStep lazy step to execute
|
|
@@ -1974,12 +2018,15 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1974
2018
|
if (this.stepCount < this.nonPlanStepCount) {
|
|
1975
2019
|
const step = this.steps[this.stepCount + this.planStepCount];
|
|
1976
2020
|
validateStep(lazyStep, step);
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2021
|
+
const parsedOut = lazyStep.parseOut(step);
|
|
2022
|
+
const isLastMemoized = this.stepCount + 1 === this.nonPlanStepCount && this.steps.at(-1).stepId !== 0;
|
|
2023
|
+
if (isLastMemoized) {
|
|
2024
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2025
|
+
stepName: lazyStep.stepName,
|
|
2026
|
+
result: parsedOut
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
return parsedOut;
|
|
1983
2030
|
}
|
|
1984
2031
|
const resultStep = await submitSingleStep({
|
|
1985
2032
|
context: this.context,
|
|
@@ -1988,15 +2035,15 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1988
2035
|
invokeCount: this.invokeCount,
|
|
1989
2036
|
concurrency: 1,
|
|
1990
2037
|
telemetry: this.telemetry,
|
|
1991
|
-
|
|
2038
|
+
dispatchDebug: this.dispatchDebug,
|
|
2039
|
+
dispatchLifecycle: this.dispatchLifecycle
|
|
1992
2040
|
});
|
|
1993
2041
|
throw new WorkflowAbort(lazyStep.stepName, resultStep);
|
|
1994
2042
|
}
|
|
1995
2043
|
/**
|
|
1996
2044
|
* Runs steps in parallel.
|
|
1997
2045
|
*
|
|
1998
|
-
* @param
|
|
1999
|
-
* @param stepFunctions list of async functions to run in parallel
|
|
2046
|
+
* @param parallelSteps list of lazy steps to run in parallel
|
|
2000
2047
|
* @returns results of the functions run in parallel
|
|
2001
2048
|
*/
|
|
2002
2049
|
async runParallel(parallelSteps) {
|
|
@@ -2009,12 +2056,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2009
2056
|
`Incompatible number of parallel steps when call state was '${parallelCallState}'. Expected ${parallelSteps.length}, got ${plannedParallelStepCount} from the request.`
|
|
2010
2057
|
);
|
|
2011
2058
|
}
|
|
2012
|
-
await this.
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2059
|
+
await this.dispatchDebug("onInfo", {
|
|
2060
|
+
info: `Executing parallel steps with: ` + JSON.stringify({
|
|
2061
|
+
parallelCallState,
|
|
2062
|
+
initialStepCount,
|
|
2063
|
+
plannedParallelStepCount,
|
|
2064
|
+
stepCount: this.stepCount,
|
|
2065
|
+
planStepCount: this.planStepCount
|
|
2066
|
+
})
|
|
2018
2067
|
});
|
|
2019
2068
|
switch (parallelCallState) {
|
|
2020
2069
|
case "first": {
|
|
@@ -2024,7 +2073,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2024
2073
|
initialStepCount,
|
|
2025
2074
|
invokeCount: this.invokeCount,
|
|
2026
2075
|
telemetry: this.telemetry,
|
|
2027
|
-
|
|
2076
|
+
dispatchDebug: this.dispatchDebug
|
|
2028
2077
|
});
|
|
2029
2078
|
break;
|
|
2030
2079
|
}
|
|
@@ -2046,7 +2095,8 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2046
2095
|
invokeCount: this.invokeCount,
|
|
2047
2096
|
concurrency: parallelSteps.length,
|
|
2048
2097
|
telemetry: this.telemetry,
|
|
2049
|
-
|
|
2098
|
+
dispatchDebug: this.dispatchDebug,
|
|
2099
|
+
dispatchLifecycle: this.dispatchLifecycle
|
|
2050
2100
|
});
|
|
2051
2101
|
throw new WorkflowAbort(parallelStep.stepName, resultStep);
|
|
2052
2102
|
} catch (error) {
|
|
@@ -2060,13 +2110,34 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2060
2110
|
break;
|
|
2061
2111
|
}
|
|
2062
2112
|
case "discard": {
|
|
2113
|
+
const resultStep = this.steps.at(-1);
|
|
2114
|
+
const lazyStep = parallelSteps.find(
|
|
2115
|
+
(planStep, index) => resultStep.stepId - index === initialStepCount
|
|
2116
|
+
);
|
|
2117
|
+
if (lazyStep) {
|
|
2118
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2119
|
+
stepName: lazyStep.stepName,
|
|
2120
|
+
result: lazyStep.parseOut(resultStep)
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2063
2123
|
throw new WorkflowAbort("discarded parallel");
|
|
2064
2124
|
}
|
|
2065
2125
|
case "last": {
|
|
2066
2126
|
const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
|
|
2067
2127
|
validateParallelSteps(parallelSteps, parallelResultSteps);
|
|
2128
|
+
const isLastMemoized = this.stepCount + 1 === this.nonPlanStepCount && this.steps.at(-1).stepId !== 0;
|
|
2129
|
+
if (isLastMemoized) {
|
|
2130
|
+
const resultStep = this.steps.at(-1);
|
|
2131
|
+
const lazyStep = parallelSteps.find(
|
|
2132
|
+
(planStep, index) => resultStep.stepId - index === initialStepCount
|
|
2133
|
+
);
|
|
2134
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2135
|
+
stepName: lazyStep.stepName,
|
|
2136
|
+
result: lazyStep.parseOut(resultStep)
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2068
2139
|
return parallelResultSteps.map(
|
|
2069
|
-
(step, index) => parallelSteps[index].parseOut(step
|
|
2140
|
+
(step, index) => parallelSteps[index].parseOut(step)
|
|
2070
2141
|
);
|
|
2071
2142
|
}
|
|
2072
2143
|
}
|
|
@@ -2122,7 +2193,6 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2122
2193
|
* @param index index of the current step
|
|
2123
2194
|
* @returns result[index] if lazyStepList > 1, otherwise result
|
|
2124
2195
|
*/
|
|
2125
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
2126
2196
|
static getResult(lazyStepList, result, index) {
|
|
2127
2197
|
if (lazyStepList.length === 1) {
|
|
2128
2198
|
return result;
|
|
@@ -2209,15 +2279,18 @@ var getProviderInfo = (api) => {
|
|
|
2209
2279
|
// src/context/api/base.ts
|
|
2210
2280
|
var BaseWorkflowApi = class {
|
|
2211
2281
|
context;
|
|
2282
|
+
/**
|
|
2283
|
+
* @param context workflow context
|
|
2284
|
+
*/
|
|
2212
2285
|
constructor({ context }) {
|
|
2213
2286
|
this.context = context;
|
|
2214
2287
|
}
|
|
2215
2288
|
/**
|
|
2216
2289
|
* context.call which uses a QStash API
|
|
2217
2290
|
*
|
|
2218
|
-
* @param stepName
|
|
2219
|
-
* @param settings
|
|
2220
|
-
* @returns
|
|
2291
|
+
* @param stepName name of the step
|
|
2292
|
+
* @param settings call settings including api configuration
|
|
2293
|
+
* @returns call response
|
|
2221
2294
|
*/
|
|
2222
2295
|
async callApi(stepName, settings) {
|
|
2223
2296
|
const { url, appendHeaders, method } = getProviderInfo(settings.api);
|
|
@@ -2225,7 +2298,7 @@ var BaseWorkflowApi = class {
|
|
|
2225
2298
|
return await this.context.call(stepName, {
|
|
2226
2299
|
url,
|
|
2227
2300
|
method: userMethod ?? method,
|
|
2228
|
-
body,
|
|
2301
|
+
body: typeof body === "string" ? body : JSON.stringify(body),
|
|
2229
2302
|
headers: {
|
|
2230
2303
|
...appendHeaders,
|
|
2231
2304
|
...headers
|
|
@@ -2377,6 +2450,129 @@ var getNewUrlFromWorkflowId = (url, workflowId) => {
|
|
|
2377
2450
|
return url.replace(/[^/]+$/, workflowId);
|
|
2378
2451
|
};
|
|
2379
2452
|
|
|
2453
|
+
// src/middleware/default-callbacks.ts
|
|
2454
|
+
var onErrorWithConsole = async ({ workflowRunId, error }) => {
|
|
2455
|
+
console.error(` [Upstash Workflow]: Error in workflow run ${workflowRunId}: ` + error);
|
|
2456
|
+
};
|
|
2457
|
+
var onWarningWithConsole = async ({ workflowRunId, warning }) => {
|
|
2458
|
+
console.warn(` [Upstash Workflow]: Warning in workflow run ${workflowRunId}: ` + warning);
|
|
2459
|
+
};
|
|
2460
|
+
var onInfoWithConsole = async ({
|
|
2461
|
+
workflowRunId,
|
|
2462
|
+
info
|
|
2463
|
+
}) => {
|
|
2464
|
+
console.info(` [Upstash Workflow]: Info in workflow run ${workflowRunId}: ` + info);
|
|
2465
|
+
};
|
|
2466
|
+
|
|
2467
|
+
// src/middleware/manager.ts
|
|
2468
|
+
var MiddlewareManager = class {
|
|
2469
|
+
middlewares;
|
|
2470
|
+
workflowRunId;
|
|
2471
|
+
context;
|
|
2472
|
+
/**
|
|
2473
|
+
* @param middlewares list of workflow middlewares
|
|
2474
|
+
*/
|
|
2475
|
+
constructor(middlewares = []) {
|
|
2476
|
+
this.middlewares = middlewares;
|
|
2477
|
+
}
|
|
2478
|
+
/**
|
|
2479
|
+
* Assign workflow run ID - will be passed to debug events
|
|
2480
|
+
*
|
|
2481
|
+
* @param workflowRunId workflow run id to assign
|
|
2482
|
+
*/
|
|
2483
|
+
assignWorkflowRunId(workflowRunId) {
|
|
2484
|
+
this.workflowRunId = workflowRunId;
|
|
2485
|
+
}
|
|
2486
|
+
/**
|
|
2487
|
+
* Assign context - required for lifecycle events
|
|
2488
|
+
*
|
|
2489
|
+
* also assigns workflowRunId from context
|
|
2490
|
+
*
|
|
2491
|
+
* @param context workflow context to assign
|
|
2492
|
+
*/
|
|
2493
|
+
assignContext(context) {
|
|
2494
|
+
this.context = context;
|
|
2495
|
+
this.workflowRunId = context.workflowRunId;
|
|
2496
|
+
}
|
|
2497
|
+
/**
|
|
2498
|
+
* Internal method to execute middlewares with common error handling logic
|
|
2499
|
+
*
|
|
2500
|
+
* @param event event name to dispatch
|
|
2501
|
+
* @param params event parameters
|
|
2502
|
+
*/
|
|
2503
|
+
async executeMiddlewares(event, params) {
|
|
2504
|
+
await Promise.all(this.middlewares.map((m) => m.ensureInit()));
|
|
2505
|
+
await Promise.all(
|
|
2506
|
+
this.middlewares.map(async (middleware) => {
|
|
2507
|
+
const callback = middleware.getCallback(event);
|
|
2508
|
+
if (callback) {
|
|
2509
|
+
try {
|
|
2510
|
+
await callback(params);
|
|
2511
|
+
} catch (error) {
|
|
2512
|
+
try {
|
|
2513
|
+
const onErrorCallback = middleware.getCallback("onError") ?? onErrorWithConsole;
|
|
2514
|
+
await onErrorCallback({
|
|
2515
|
+
workflowRunId: this.workflowRunId,
|
|
2516
|
+
error
|
|
2517
|
+
});
|
|
2518
|
+
} catch (onErrorError) {
|
|
2519
|
+
console.error(
|
|
2520
|
+
`Failed while executing "onError" of middleware "${middleware.name}", falling back to logging the error to console. Error: ${onErrorError}`
|
|
2521
|
+
);
|
|
2522
|
+
onErrorWithConsole({
|
|
2523
|
+
workflowRunId: this.workflowRunId,
|
|
2524
|
+
error
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
})
|
|
2530
|
+
);
|
|
2531
|
+
if (event === "onError") {
|
|
2532
|
+
onErrorWithConsole({
|
|
2533
|
+
workflowRunId: this.workflowRunId,
|
|
2534
|
+
...params
|
|
2535
|
+
});
|
|
2536
|
+
} else if (event === "onWarning") {
|
|
2537
|
+
onWarningWithConsole({
|
|
2538
|
+
workflowRunId: this.workflowRunId,
|
|
2539
|
+
...params
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
/**
|
|
2544
|
+
* Dispatch a debug event (onError, onWarning, onInfo)
|
|
2545
|
+
*
|
|
2546
|
+
* @param event debug event name
|
|
2547
|
+
* @param params event parameters
|
|
2548
|
+
*/
|
|
2549
|
+
async dispatchDebug(event, params) {
|
|
2550
|
+
const paramsWithRunId = {
|
|
2551
|
+
...params,
|
|
2552
|
+
workflowRunId: this.workflowRunId
|
|
2553
|
+
};
|
|
2554
|
+
await this.executeMiddlewares(event, paramsWithRunId);
|
|
2555
|
+
}
|
|
2556
|
+
/**
|
|
2557
|
+
* Dispatch a lifecycle event (beforeExecution, afterExecution, runStarted, runCompleted)
|
|
2558
|
+
*
|
|
2559
|
+
* @param event lifecycle event name
|
|
2560
|
+
* @param params event parameters
|
|
2561
|
+
*/
|
|
2562
|
+
async dispatchLifecycle(event, params) {
|
|
2563
|
+
if (!this.context) {
|
|
2564
|
+
throw new WorkflowError(
|
|
2565
|
+
`Something went wrong while calling middlewares. Lifecycle event "${event}" was called before assignContext.`
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
2568
|
+
const paramsWithContext = {
|
|
2569
|
+
...params,
|
|
2570
|
+
context: this.context
|
|
2571
|
+
};
|
|
2572
|
+
await this.executeMiddlewares(event, paramsWithContext);
|
|
2573
|
+
}
|
|
2574
|
+
};
|
|
2575
|
+
|
|
2380
2576
|
// src/context/context.ts
|
|
2381
2577
|
var WorkflowContext = class {
|
|
2382
2578
|
executor;
|
|
@@ -2422,32 +2618,13 @@ var WorkflowContext = class {
|
|
|
2422
2618
|
*/
|
|
2423
2619
|
url;
|
|
2424
2620
|
/**
|
|
2425
|
-
*
|
|
2426
|
-
*
|
|
2427
|
-
* https://upstash.com/docs/qstash/features/callbacks#what-is-a-failure-callback
|
|
2621
|
+
* Payload of the request which started the workflow.
|
|
2428
2622
|
*
|
|
2429
|
-
*
|
|
2623
|
+
* To specify its type, you can define `serve` as follows:
|
|
2430
2624
|
*
|
|
2431
2625
|
* ```ts
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
* ...
|
|
2435
|
-
* },
|
|
2436
|
-
* {
|
|
2437
|
-
* failureUrl: "new-url-value"
|
|
2438
|
-
* }
|
|
2439
|
-
* )
|
|
2440
|
-
* ```
|
|
2441
|
-
*/
|
|
2442
|
-
failureUrl;
|
|
2443
|
-
/**
|
|
2444
|
-
* Payload of the request which started the workflow.
|
|
2445
|
-
*
|
|
2446
|
-
* To specify its type, you can define `serve` as follows:
|
|
2447
|
-
*
|
|
2448
|
-
* ```ts
|
|
2449
|
-
* // set requestPayload type to MyPayload:
|
|
2450
|
-
* export const POST = serve<MyPayload>(
|
|
2626
|
+
* // set requestPayload type to MyPayload:
|
|
2627
|
+
* export const POST = serve<MyPayload>(
|
|
2451
2628
|
* async (context) => {
|
|
2452
2629
|
* ...
|
|
2453
2630
|
* }
|
|
@@ -2495,46 +2672,6 @@ var WorkflowContext = class {
|
|
|
2495
2672
|
* Default value is set to `process.env`.
|
|
2496
2673
|
*/
|
|
2497
2674
|
env;
|
|
2498
|
-
/**
|
|
2499
|
-
* Number of retries
|
|
2500
|
-
*/
|
|
2501
|
-
retries;
|
|
2502
|
-
/**
|
|
2503
|
-
* Delay between retries.
|
|
2504
|
-
*
|
|
2505
|
-
* By default, the `retryDelay` is exponential backoff.
|
|
2506
|
-
* More details can be found in: https://upstash.com/docs/qstash/features/retry.
|
|
2507
|
-
*
|
|
2508
|
-
* The `retryDelay` option allows you to customize the delay (in milliseconds) between retry attempts when message delivery fails.
|
|
2509
|
-
*
|
|
2510
|
-
* You can use mathematical expressions and the following built-in functions to calculate the delay dynamically.
|
|
2511
|
-
* The special variable `retried` represents the current retry attempt count (starting from 0).
|
|
2512
|
-
*
|
|
2513
|
-
* Supported functions:
|
|
2514
|
-
* - `pow`
|
|
2515
|
-
* - `sqrt`
|
|
2516
|
-
* - `abs`
|
|
2517
|
-
* - `exp`
|
|
2518
|
-
* - `floor`
|
|
2519
|
-
* - `ceil`
|
|
2520
|
-
* - `round`
|
|
2521
|
-
* - `min`
|
|
2522
|
-
* - `max`
|
|
2523
|
-
*
|
|
2524
|
-
* Examples of valid `retryDelay` values:
|
|
2525
|
-
* ```ts
|
|
2526
|
-
* 1000 // 1 second
|
|
2527
|
-
* 1000 * (1 + retried) // 1 second multiplied by the current retry attempt
|
|
2528
|
-
* pow(2, retried) // 2 to the power of the current retry attempt
|
|
2529
|
-
* max(10, pow(2, retried)) // The greater of 10 or 2^retried
|
|
2530
|
-
* ```
|
|
2531
|
-
*/
|
|
2532
|
-
retryDelay;
|
|
2533
|
-
/**
|
|
2534
|
-
* Settings for controlling the number of active requests
|
|
2535
|
-
* and number of requests per second with the same key.
|
|
2536
|
-
*/
|
|
2537
|
-
flowControl;
|
|
2538
2675
|
/**
|
|
2539
2676
|
* Label to apply to the workflow run.
|
|
2540
2677
|
*
|
|
@@ -2557,30 +2694,31 @@ var WorkflowContext = class {
|
|
|
2557
2694
|
headers,
|
|
2558
2695
|
steps,
|
|
2559
2696
|
url,
|
|
2560
|
-
failureUrl,
|
|
2561
|
-
debug,
|
|
2562
2697
|
initialPayload,
|
|
2563
2698
|
env,
|
|
2564
|
-
retries,
|
|
2565
|
-
retryDelay,
|
|
2566
2699
|
telemetry,
|
|
2567
2700
|
invokeCount,
|
|
2568
|
-
|
|
2569
|
-
|
|
2701
|
+
label,
|
|
2702
|
+
middlewareManager
|
|
2570
2703
|
}) {
|
|
2571
2704
|
this.qstashClient = qstashClient;
|
|
2572
2705
|
this.workflowRunId = workflowRunId;
|
|
2573
2706
|
this.steps = steps;
|
|
2574
2707
|
this.url = url;
|
|
2575
|
-
this.failureUrl = failureUrl;
|
|
2576
2708
|
this.headers = headers;
|
|
2577
2709
|
this.requestPayload = initialPayload;
|
|
2578
2710
|
this.env = env ?? {};
|
|
2579
|
-
this.retries = retries ?? DEFAULT_RETRIES;
|
|
2580
|
-
this.retryDelay = retryDelay;
|
|
2581
|
-
this.flowControl = flowControl;
|
|
2582
2711
|
this.label = label;
|
|
2583
|
-
|
|
2712
|
+
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
2713
|
+
middlewareManagerInstance.assignContext(this);
|
|
2714
|
+
this.executor = new AutoExecutor(
|
|
2715
|
+
this,
|
|
2716
|
+
this.steps,
|
|
2717
|
+
middlewareManagerInstance.dispatchDebug.bind(middlewareManagerInstance),
|
|
2718
|
+
middlewareManagerInstance.dispatchLifecycle.bind(middlewareManagerInstance),
|
|
2719
|
+
telemetry,
|
|
2720
|
+
invokeCount
|
|
2721
|
+
);
|
|
2584
2722
|
}
|
|
2585
2723
|
/**
|
|
2586
2724
|
* Executes a workflow step
|
|
@@ -2611,7 +2749,7 @@ var WorkflowContext = class {
|
|
|
2611
2749
|
*/
|
|
2612
2750
|
async run(stepName, stepFunction) {
|
|
2613
2751
|
const wrappedStepFunction = (() => this.executor.wrapStep(stepName, stepFunction));
|
|
2614
|
-
return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
|
|
2752
|
+
return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
|
|
2615
2753
|
}
|
|
2616
2754
|
/**
|
|
2617
2755
|
* Stops the execution for the duration provided.
|
|
@@ -2625,7 +2763,7 @@ var WorkflowContext = class {
|
|
|
2625
2763
|
* @returns undefined
|
|
2626
2764
|
*/
|
|
2627
2765
|
async sleep(stepName, duration) {
|
|
2628
|
-
await this.addStep(new LazySleepStep(stepName, duration));
|
|
2766
|
+
await this.addStep(new LazySleepStep(this, stepName, duration));
|
|
2629
2767
|
}
|
|
2630
2768
|
/**
|
|
2631
2769
|
* Stops the execution until the date time provided.
|
|
@@ -2647,48 +2785,38 @@ var WorkflowContext = class {
|
|
|
2647
2785
|
datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
|
|
2648
2786
|
time = Math.round(datetime.getTime() / 1e3);
|
|
2649
2787
|
}
|
|
2650
|
-
await this.addStep(new LazySleepUntilStep(stepName, time));
|
|
2788
|
+
await this.addStep(new LazySleepUntilStep(this, stepName, time));
|
|
2651
2789
|
}
|
|
2652
2790
|
async call(stepName, settings) {
|
|
2653
2791
|
let callStep;
|
|
2654
2792
|
if ("workflow" in settings) {
|
|
2655
2793
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2656
|
-
|
|
2794
|
+
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
2795
|
+
callStep = new LazyCallStep({
|
|
2796
|
+
context: this,
|
|
2657
2797
|
stepName,
|
|
2658
2798
|
url,
|
|
2659
|
-
"POST",
|
|
2660
|
-
|
|
2661
|
-
settings.headers || {},
|
|
2662
|
-
settings.retries || 0,
|
|
2663
|
-
settings.retryDelay,
|
|
2664
|
-
settings.timeout,
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
);
|
|
2799
|
+
method: "POST",
|
|
2800
|
+
body: stringBody,
|
|
2801
|
+
headers: settings.headers || {},
|
|
2802
|
+
retries: settings.retries || 0,
|
|
2803
|
+
retryDelay: settings.retryDelay,
|
|
2804
|
+
timeout: settings.timeout,
|
|
2805
|
+
flowControl: settings.flowControl
|
|
2806
|
+
});
|
|
2668
2807
|
} else {
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
method = "GET",
|
|
2672
|
-
body,
|
|
2673
|
-
headers = {},
|
|
2674
|
-
retries = 0,
|
|
2675
|
-
retryDelay,
|
|
2676
|
-
timeout,
|
|
2677
|
-
flowControl,
|
|
2678
|
-
stringifyBody = true
|
|
2679
|
-
} = settings;
|
|
2680
|
-
callStep = new LazyCallStep(
|
|
2808
|
+
callStep = new LazyCallStep({
|
|
2809
|
+
context: this,
|
|
2681
2810
|
stepName,
|
|
2682
|
-
url,
|
|
2683
|
-
method,
|
|
2684
|
-
body,
|
|
2685
|
-
headers,
|
|
2686
|
-
retries,
|
|
2687
|
-
retryDelay,
|
|
2688
|
-
timeout,
|
|
2689
|
-
flowControl
|
|
2690
|
-
|
|
2691
|
-
);
|
|
2811
|
+
url: settings.url,
|
|
2812
|
+
method: settings.method ?? "GET",
|
|
2813
|
+
body: settings.body,
|
|
2814
|
+
headers: settings.headers ?? {},
|
|
2815
|
+
retries: settings.retries ?? 0,
|
|
2816
|
+
retryDelay: settings.retryDelay,
|
|
2817
|
+
timeout: settings.timeout,
|
|
2818
|
+
flowControl: settings.flowControl
|
|
2819
|
+
});
|
|
2692
2820
|
}
|
|
2693
2821
|
return await this.addStep(callStep);
|
|
2694
2822
|
}
|
|
@@ -2729,7 +2857,9 @@ var WorkflowContext = class {
|
|
|
2729
2857
|
async waitForEvent(stepName, eventId, options = {}) {
|
|
2730
2858
|
const { timeout = "7d" } = options;
|
|
2731
2859
|
const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
|
|
2732
|
-
return await this.addStep(
|
|
2860
|
+
return await this.addStep(
|
|
2861
|
+
new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
|
|
2862
|
+
);
|
|
2733
2863
|
}
|
|
2734
2864
|
/**
|
|
2735
2865
|
* Notify workflow runs waiting for an event
|
|
@@ -2754,20 +2884,28 @@ var WorkflowContext = class {
|
|
|
2754
2884
|
*/
|
|
2755
2885
|
async notify(stepName, eventId, eventData) {
|
|
2756
2886
|
return await this.addStep(
|
|
2757
|
-
new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
|
|
2887
|
+
new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
|
|
2758
2888
|
);
|
|
2759
2889
|
}
|
|
2760
2890
|
async invoke(stepName, settings) {
|
|
2761
|
-
return await this.addStep(
|
|
2891
|
+
return await this.addStep(
|
|
2892
|
+
new LazyInvokeStep(this, stepName, settings)
|
|
2893
|
+
);
|
|
2894
|
+
}
|
|
2895
|
+
async createWebhook(stepName) {
|
|
2896
|
+
return await this.addStep(new LazyCreateWebhookStep(this, stepName));
|
|
2897
|
+
}
|
|
2898
|
+
async waitForWebhook(stepName, webhook, timeout) {
|
|
2899
|
+
return await this.addStep(new LazyWaitForWebhookStep(this, stepName, webhook, timeout));
|
|
2762
2900
|
}
|
|
2763
2901
|
/**
|
|
2764
2902
|
* Cancel the current workflow run
|
|
2765
2903
|
*
|
|
2766
|
-
* Will throw
|
|
2904
|
+
* Will throw WorkflowCancelAbort to stop workflow execution.
|
|
2767
2905
|
* Shouldn't be inside try/catch.
|
|
2768
2906
|
*/
|
|
2769
2907
|
async cancel() {
|
|
2770
|
-
throw new
|
|
2908
|
+
throw new WorkflowCancelAbort();
|
|
2771
2909
|
}
|
|
2772
2910
|
/**
|
|
2773
2911
|
* Adds steps to the executor. Needed so that it can be overwritten in
|
|
@@ -2783,74 +2921,25 @@ var WorkflowContext = class {
|
|
|
2783
2921
|
}
|
|
2784
2922
|
};
|
|
2785
2923
|
|
|
2786
|
-
// src/logger.ts
|
|
2787
|
-
var LOG_LEVELS = ["DEBUG", "INFO", "SUBMIT", "WARN", "ERROR"];
|
|
2788
|
-
var WorkflowLogger = class _WorkflowLogger {
|
|
2789
|
-
logs = [];
|
|
2790
|
-
options;
|
|
2791
|
-
workflowRunId = void 0;
|
|
2792
|
-
constructor(options) {
|
|
2793
|
-
this.options = options;
|
|
2794
|
-
}
|
|
2795
|
-
async log(level, eventType, details) {
|
|
2796
|
-
if (this.shouldLog(level)) {
|
|
2797
|
-
const timestamp = Date.now();
|
|
2798
|
-
const logEntry = {
|
|
2799
|
-
timestamp,
|
|
2800
|
-
workflowRunId: this.workflowRunId ?? "",
|
|
2801
|
-
logLevel: level,
|
|
2802
|
-
eventType,
|
|
2803
|
-
details
|
|
2804
|
-
};
|
|
2805
|
-
this.logs.push(logEntry);
|
|
2806
|
-
if (this.options.logOutput === "console") {
|
|
2807
|
-
this.writeToConsole(logEntry);
|
|
2808
|
-
}
|
|
2809
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2810
|
-
}
|
|
2811
|
-
}
|
|
2812
|
-
setWorkflowRunId(workflowRunId) {
|
|
2813
|
-
this.workflowRunId = workflowRunId;
|
|
2814
|
-
}
|
|
2815
|
-
writeToConsole(logEntry) {
|
|
2816
|
-
const JSON_SPACING = 2;
|
|
2817
|
-
const logMethod = logEntry.logLevel === "ERROR" ? console.error : logEntry.logLevel === "WARN" ? console.warn : console.log;
|
|
2818
|
-
logMethod(JSON.stringify(logEntry, void 0, JSON_SPACING));
|
|
2819
|
-
}
|
|
2820
|
-
shouldLog(level) {
|
|
2821
|
-
return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.options.logLevel);
|
|
2822
|
-
}
|
|
2823
|
-
static getLogger(verbose) {
|
|
2824
|
-
if (typeof verbose === "object") {
|
|
2825
|
-
return verbose;
|
|
2826
|
-
} else {
|
|
2827
|
-
return verbose ? new _WorkflowLogger({
|
|
2828
|
-
logLevel: "INFO",
|
|
2829
|
-
logOutput: "console"
|
|
2830
|
-
}) : void 0;
|
|
2831
|
-
}
|
|
2832
|
-
}
|
|
2833
|
-
};
|
|
2834
|
-
|
|
2835
2924
|
// src/serve/authorization.ts
|
|
2836
2925
|
var import_qstash9 = require("@upstash/qstash");
|
|
2837
2926
|
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
2838
2927
|
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
2839
2928
|
disabled = true;
|
|
2840
2929
|
/**
|
|
2841
|
-
* overwrite the WorkflowContext.addStep method to always raise
|
|
2930
|
+
* overwrite the WorkflowContext.addStep method to always raise WorkflowAuthError
|
|
2842
2931
|
* error in order to stop the execution whenever we encounter a step.
|
|
2843
2932
|
*
|
|
2844
2933
|
* @param _step
|
|
2845
2934
|
*/
|
|
2846
2935
|
async addStep(_step) {
|
|
2847
|
-
throw new
|
|
2936
|
+
throw new WorkflowAuthError(_DisabledWorkflowContext.disabledMessage);
|
|
2848
2937
|
}
|
|
2849
2938
|
/**
|
|
2850
|
-
* overwrite cancel method to throw
|
|
2939
|
+
* overwrite cancel method to throw WorkflowAuthError with the disabledMessage
|
|
2851
2940
|
*/
|
|
2852
2941
|
async cancel() {
|
|
2853
|
-
throw new
|
|
2942
|
+
throw new WorkflowAuthError(_DisabledWorkflowContext.disabledMessage);
|
|
2854
2943
|
}
|
|
2855
2944
|
/**
|
|
2856
2945
|
* copies the passed context to create a DisabledWorkflowContext. Then, runs the
|
|
@@ -2873,18 +2962,14 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
2873
2962
|
headers: context.headers,
|
|
2874
2963
|
steps: [],
|
|
2875
2964
|
url: context.url,
|
|
2876
|
-
failureUrl: context.failureUrl,
|
|
2877
2965
|
initialPayload: context.requestPayload,
|
|
2878
2966
|
env: context.env,
|
|
2879
|
-
retries: context.retries,
|
|
2880
|
-
retryDelay: context.retryDelay,
|
|
2881
|
-
flowControl: context.flowControl,
|
|
2882
2967
|
label: context.label
|
|
2883
2968
|
});
|
|
2884
2969
|
try {
|
|
2885
2970
|
await routeFunction(disabledContext);
|
|
2886
2971
|
} catch (error) {
|
|
2887
|
-
if (isInstanceOf(error,
|
|
2972
|
+
if (isInstanceOf(error, WorkflowAuthError) && error.stepName === this.disabledMessage || isInstanceOf(error, WorkflowNonRetryableError) || isInstanceOf(error, WorkflowRetryAfterError)) {
|
|
2888
2973
|
return ok("step-found");
|
|
2889
2974
|
}
|
|
2890
2975
|
console.warn(
|
|
@@ -2917,13 +3002,6 @@ var processRawSteps = (rawSteps) => {
|
|
|
2917
3002
|
const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
|
|
2918
3003
|
const otherSteps = stepsToDecode.map((rawStep) => {
|
|
2919
3004
|
const step = JSON.parse(decodeBase64(rawStep.body));
|
|
2920
|
-
if (step.waitEventId) {
|
|
2921
|
-
const newOut = {
|
|
2922
|
-
eventData: step.out ? decodeBase64(step.out) : void 0,
|
|
2923
|
-
timeout: step.waitTimeout ?? false
|
|
2924
|
-
};
|
|
2925
|
-
step.out = newOut;
|
|
2926
|
-
}
|
|
2927
3005
|
return step;
|
|
2928
3006
|
});
|
|
2929
3007
|
const steps = [initialStep, ...otherSteps];
|
|
@@ -2951,7 +3029,7 @@ var deduplicateSteps = (steps) => {
|
|
|
2951
3029
|
}
|
|
2952
3030
|
return deduplicatedSteps;
|
|
2953
3031
|
};
|
|
2954
|
-
var checkIfLastOneIsDuplicate = async (steps,
|
|
3032
|
+
var checkIfLastOneIsDuplicate = async (steps, dispatchDebug) => {
|
|
2955
3033
|
if (steps.length < 2) {
|
|
2956
3034
|
return false;
|
|
2957
3035
|
}
|
|
@@ -2962,14 +3040,41 @@ var checkIfLastOneIsDuplicate = async (steps, debug) => {
|
|
|
2962
3040
|
const step = steps[index];
|
|
2963
3041
|
if (step.stepId === lastStepId && step.targetStep === lastTargetStepId) {
|
|
2964
3042
|
const message = `Upstash Workflow: The step '${step.stepName}' with id '${step.stepId}' has run twice during workflow execution. Rest of the workflow will continue running as usual.`;
|
|
2965
|
-
await
|
|
2966
|
-
|
|
3043
|
+
await dispatchDebug?.("onWarning", {
|
|
3044
|
+
warning: message
|
|
3045
|
+
});
|
|
2967
3046
|
return true;
|
|
2968
3047
|
}
|
|
2969
3048
|
}
|
|
2970
3049
|
return false;
|
|
2971
3050
|
};
|
|
2972
3051
|
var validateRequest = (request) => {
|
|
3052
|
+
if (request.headers.get(WORKFLOW_UNKOWN_SDK_VERSION_HEADER)) {
|
|
3053
|
+
const workflowRunId2 = request.headers.get(WORKFLOW_ID_HEADER);
|
|
3054
|
+
if (!workflowRunId2) {
|
|
3055
|
+
throw new WorkflowError(
|
|
3056
|
+
"Couldn't get workflow id from header when handling unknown sdk request"
|
|
3057
|
+
);
|
|
3058
|
+
}
|
|
3059
|
+
return {
|
|
3060
|
+
unknownSdk: true,
|
|
3061
|
+
isFirstInvocation: true,
|
|
3062
|
+
workflowRunId: workflowRunId2
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
if (request.headers.get(WORKFLOW_FAILURE_CALLBACK_HEADER)) {
|
|
3066
|
+
const workflowRunId2 = request.headers.get(WORKFLOW_ID_HEADER);
|
|
3067
|
+
if (!workflowRunId2) {
|
|
3068
|
+
throw new WorkflowError(
|
|
3069
|
+
"Couldn't get workflow id from header when handling failure callback request"
|
|
3070
|
+
);
|
|
3071
|
+
}
|
|
3072
|
+
return {
|
|
3073
|
+
unknownSdk: false,
|
|
3074
|
+
isFirstInvocation: true,
|
|
3075
|
+
workflowRunId: workflowRunId2
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
2973
3078
|
const versionHeader = request.headers.get(WORKFLOW_PROTOCOL_VERSION_HEADER);
|
|
2974
3079
|
const isFirstInvocation = !versionHeader;
|
|
2975
3080
|
if (!isFirstInvocation && versionHeader !== WORKFLOW_PROTOCOL_VERSION) {
|
|
@@ -2983,11 +3088,20 @@ var validateRequest = (request) => {
|
|
|
2983
3088
|
}
|
|
2984
3089
|
return {
|
|
2985
3090
|
isFirstInvocation,
|
|
2986
|
-
workflowRunId
|
|
3091
|
+
workflowRunId,
|
|
3092
|
+
unknownSdk: false
|
|
2987
3093
|
};
|
|
2988
3094
|
};
|
|
2989
|
-
var parseRequest = async (
|
|
2990
|
-
|
|
3095
|
+
var parseRequest = async ({
|
|
3096
|
+
requestPayload,
|
|
3097
|
+
isFirstInvocation,
|
|
3098
|
+
unknownSdk,
|
|
3099
|
+
workflowRunId,
|
|
3100
|
+
requester,
|
|
3101
|
+
messageId,
|
|
3102
|
+
dispatchDebug
|
|
3103
|
+
}) => {
|
|
3104
|
+
if (isFirstInvocation && !unknownSdk) {
|
|
2991
3105
|
return {
|
|
2992
3106
|
rawInitialPayload: requestPayload ?? "",
|
|
2993
3107
|
steps: [],
|
|
@@ -2997,16 +3111,14 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
2997
3111
|
} else {
|
|
2998
3112
|
let rawSteps;
|
|
2999
3113
|
if (!requestPayload) {
|
|
3000
|
-
await
|
|
3001
|
-
"
|
|
3002
|
-
|
|
3003
|
-
"request payload is empty, steps will be fetched from QStash."
|
|
3004
|
-
);
|
|
3114
|
+
await dispatchDebug?.("onInfo", {
|
|
3115
|
+
info: "request payload is empty, steps will be fetched from QStash."
|
|
3116
|
+
});
|
|
3005
3117
|
const { steps: fetchedSteps, workflowRunEnded } = await getSteps(
|
|
3006
3118
|
requester,
|
|
3007
3119
|
workflowRunId,
|
|
3008
3120
|
messageId,
|
|
3009
|
-
|
|
3121
|
+
dispatchDebug
|
|
3010
3122
|
);
|
|
3011
3123
|
if (workflowRunEnded) {
|
|
3012
3124
|
return {
|
|
@@ -3021,7 +3133,7 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3021
3133
|
rawSteps = JSON.parse(requestPayload);
|
|
3022
3134
|
}
|
|
3023
3135
|
const { rawInitialPayload, steps } = processRawSteps(rawSteps);
|
|
3024
|
-
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps,
|
|
3136
|
+
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps, dispatchDebug);
|
|
3025
3137
|
const deduplicatedSteps = deduplicateSteps(steps);
|
|
3026
3138
|
return {
|
|
3027
3139
|
rawInitialPayload,
|
|
@@ -3031,16 +3143,21 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3031
3143
|
};
|
|
3032
3144
|
}
|
|
3033
3145
|
};
|
|
3034
|
-
var handleFailure = async (
|
|
3035
|
-
|
|
3146
|
+
var handleFailure = async ({
|
|
3147
|
+
request,
|
|
3148
|
+
requestPayload,
|
|
3149
|
+
qstashClient,
|
|
3150
|
+
initialPayloadParser,
|
|
3151
|
+
routeFunction,
|
|
3152
|
+
failureFunction,
|
|
3153
|
+
env,
|
|
3154
|
+
dispatchDebug
|
|
3155
|
+
}) => {
|
|
3156
|
+
if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true" && !request.headers.get(WORKFLOW_FAILURE_CALLBACK_HEADER)) {
|
|
3036
3157
|
return ok({ result: "not-failure-callback" });
|
|
3037
3158
|
}
|
|
3038
3159
|
if (!failureFunction) {
|
|
3039
|
-
return
|
|
3040
|
-
new WorkflowError(
|
|
3041
|
-
"Workflow endpoint is called to handle a failure, but a failureFunction is not provided in serve options. Either provide a failureUrl or a failureFunction."
|
|
3042
|
-
)
|
|
3043
|
-
);
|
|
3160
|
+
return ok({ result: "failure-function-undefined" });
|
|
3044
3161
|
}
|
|
3045
3162
|
try {
|
|
3046
3163
|
const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
|
|
@@ -3068,23 +3185,21 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
3068
3185
|
headers: userHeaders,
|
|
3069
3186
|
steps: [],
|
|
3070
3187
|
url,
|
|
3071
|
-
failureUrl: url,
|
|
3072
|
-
debug,
|
|
3073
3188
|
env,
|
|
3074
|
-
retries,
|
|
3075
|
-
retryDelay,
|
|
3076
|
-
flowControl,
|
|
3077
3189
|
telemetry: void 0,
|
|
3078
3190
|
// not going to make requests in authentication check
|
|
3079
|
-
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0
|
|
3191
|
+
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
|
|
3192
|
+
middlewareManager: void 0
|
|
3080
3193
|
});
|
|
3081
3194
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
3082
3195
|
routeFunction,
|
|
3083
3196
|
workflowContext
|
|
3084
3197
|
);
|
|
3085
3198
|
if (authCheck.isErr()) {
|
|
3086
|
-
await
|
|
3087
|
-
|
|
3199
|
+
await dispatchDebug?.("onError", {
|
|
3200
|
+
error: authCheck.error
|
|
3201
|
+
});
|
|
3202
|
+
return err(authCheck.error);
|
|
3088
3203
|
} else if (authCheck.value === "run-ended") {
|
|
3089
3204
|
return err(new WorkflowError("Not authorized to run the failure function."));
|
|
3090
3205
|
}
|
|
@@ -3095,74 +3210,309 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
3095
3210
|
failHeaders: header,
|
|
3096
3211
|
failStack
|
|
3097
3212
|
});
|
|
3098
|
-
return ok({ result: "
|
|
3213
|
+
return ok({ result: "failure-function-executed", response: failureResponse });
|
|
3099
3214
|
} catch (error) {
|
|
3100
3215
|
return err(error);
|
|
3101
3216
|
}
|
|
3102
3217
|
};
|
|
3103
3218
|
|
|
3104
|
-
// src/serve/
|
|
3219
|
+
// src/serve/multi-region/handlers.ts
|
|
3105
3220
|
var import_qstash10 = require("@upstash/qstash");
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3221
|
+
|
|
3222
|
+
// src/serve/multi-region/utils.ts
|
|
3223
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3224
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3225
|
+
const region = environment.QSTASH_REGION;
|
|
3226
|
+
return normalizeRegionHeader(region);
|
|
3227
|
+
};
|
|
3228
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3229
|
+
const result = {};
|
|
3230
|
+
for (const variable of environmentVariables) {
|
|
3231
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3232
|
+
result[variable] = environment[key];
|
|
3233
|
+
}
|
|
3234
|
+
return result;
|
|
3235
|
+
}
|
|
3236
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3237
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3238
|
+
}
|
|
3239
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3240
|
+
return readEnvironmentVariables(
|
|
3241
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3242
|
+
environment,
|
|
3243
|
+
region
|
|
3111
3244
|
);
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3245
|
+
}
|
|
3246
|
+
function normalizeRegionHeader(region) {
|
|
3247
|
+
if (!region) {
|
|
3248
|
+
return void 0;
|
|
3249
|
+
}
|
|
3250
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3251
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3252
|
+
return region;
|
|
3253
|
+
}
|
|
3254
|
+
console.warn(
|
|
3255
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3256
|
+
", "
|
|
3257
|
+
)}.`
|
|
3258
|
+
);
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
// src/serve/multi-region/handlers.ts
|
|
3263
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3264
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3265
|
+
return qstashHandlers.handlers;
|
|
3266
|
+
}
|
|
3267
|
+
let targetRegion;
|
|
3268
|
+
if (isFirstInvocation) {
|
|
3269
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3270
|
+
} else {
|
|
3271
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3272
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3273
|
+
}
|
|
3274
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3275
|
+
if (!handler) {
|
|
3276
|
+
console.warn(
|
|
3277
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3278
|
+
);
|
|
3279
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3280
|
+
}
|
|
3281
|
+
return handler;
|
|
3282
|
+
};
|
|
3283
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3284
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3285
|
+
const client = new import_qstash10.Client({
|
|
3286
|
+
...clientOptions,
|
|
3287
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3288
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3289
|
+
});
|
|
3290
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3291
|
+
return { client, receiver };
|
|
3292
|
+
};
|
|
3293
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3294
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3295
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3296
|
+
return {
|
|
3297
|
+
isMultiRegion: true,
|
|
3298
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3299
|
+
clientOptions: qstashClientOption
|
|
3300
|
+
};
|
|
3301
|
+
} else {
|
|
3302
|
+
return { isMultiRegion: false };
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
var getQStashHandlers = ({
|
|
3306
|
+
environment,
|
|
3307
|
+
qstashClientOption,
|
|
3308
|
+
receiverConfig
|
|
3309
|
+
}) => {
|
|
3310
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3311
|
+
if (multiRegion.isMultiRegion) {
|
|
3312
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3313
|
+
const handlers = {};
|
|
3314
|
+
for (const region of regions) {
|
|
3315
|
+
try {
|
|
3316
|
+
handlers[region] = createRegionalHandler(
|
|
3317
|
+
environment,
|
|
3318
|
+
receiverConfig,
|
|
3319
|
+
region,
|
|
3320
|
+
multiRegion.clientOptions
|
|
3157
3321
|
);
|
|
3322
|
+
} catch (error) {
|
|
3323
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3158
3324
|
}
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3325
|
+
}
|
|
3326
|
+
return {
|
|
3327
|
+
mode: "multi-region",
|
|
3328
|
+
handlers,
|
|
3329
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3330
|
+
};
|
|
3331
|
+
} else {
|
|
3332
|
+
return {
|
|
3333
|
+
mode: "single-region",
|
|
3334
|
+
handlers: {
|
|
3335
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3336
|
+
...qstashClientOption,
|
|
3337
|
+
baseUrl: environment.QSTASH_URL,
|
|
3338
|
+
token: environment.QSTASH_TOKEN
|
|
3339
|
+
}),
|
|
3340
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3341
|
+
}
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
};
|
|
3345
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3346
|
+
if (typeof receiverConfig === "string") {
|
|
3347
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3348
|
+
return void 0;
|
|
3349
|
+
}
|
|
3350
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3351
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3352
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3353
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3354
|
+
}) : void 0;
|
|
3355
|
+
} else {
|
|
3356
|
+
return receiverConfig;
|
|
3357
|
+
}
|
|
3358
|
+
};
|
|
3359
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3360
|
+
const handlers = getQStashHandlers(...params);
|
|
3361
|
+
return {
|
|
3362
|
+
qstashHandlers: handlers,
|
|
3363
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3364
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3365
|
+
};
|
|
3366
|
+
};
|
|
3367
|
+
|
|
3368
|
+
// src/middleware/middleware.ts
|
|
3369
|
+
var WorkflowMiddleware = class {
|
|
3370
|
+
name;
|
|
3371
|
+
initCallbacks;
|
|
3372
|
+
/**
|
|
3373
|
+
* Callback functions
|
|
3374
|
+
*
|
|
3375
|
+
* Initially set to undefined, will be populated after init is called
|
|
3376
|
+
*/
|
|
3377
|
+
middlewareCallbacks = void 0;
|
|
3378
|
+
constructor(parameters) {
|
|
3379
|
+
this.name = parameters.name;
|
|
3380
|
+
if ("init" in parameters) {
|
|
3381
|
+
this.initCallbacks = parameters.init;
|
|
3382
|
+
} else {
|
|
3383
|
+
this.middlewareCallbacks = parameters.callbacks;
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
async ensureInit() {
|
|
3387
|
+
if (!this.middlewareCallbacks) {
|
|
3388
|
+
if (!this.initCallbacks) {
|
|
3389
|
+
throw new WorkflowError(`Middleware "${this.name}" has no callbacks or init defined.`);
|
|
3390
|
+
}
|
|
3391
|
+
this.middlewareCallbacks = await this.initCallbacks();
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
/**
|
|
3395
|
+
* Gets a callback function by name.
|
|
3396
|
+
*
|
|
3397
|
+
* @param callback name of the callback to retrieve
|
|
3398
|
+
*/
|
|
3399
|
+
getCallback(callback) {
|
|
3400
|
+
return this.middlewareCallbacks?.[callback];
|
|
3401
|
+
}
|
|
3402
|
+
};
|
|
3403
|
+
|
|
3404
|
+
// src/middleware/logging.ts
|
|
3405
|
+
var loggingMiddleware = new WorkflowMiddleware({
|
|
3406
|
+
name: "logging",
|
|
3407
|
+
callbacks: {
|
|
3408
|
+
afterExecution(params) {
|
|
3409
|
+
const { context, ...rest } = params;
|
|
3410
|
+
console.log(" [Upstash Workflow]: Step executed:", {
|
|
3411
|
+
workflowRunId: context.workflowRunId,
|
|
3412
|
+
...rest
|
|
3413
|
+
});
|
|
3414
|
+
},
|
|
3415
|
+
beforeExecution(params) {
|
|
3416
|
+
const { context, ...rest } = params;
|
|
3417
|
+
console.log(" [Upstash Workflow]: Step execution started:", {
|
|
3418
|
+
workflowRunId: context.workflowRunId,
|
|
3419
|
+
...rest
|
|
3164
3420
|
});
|
|
3165
3421
|
},
|
|
3422
|
+
runStarted(params) {
|
|
3423
|
+
const { context, ...rest } = params;
|
|
3424
|
+
console.log(" [Upstash Workflow]: Workflow run started:", {
|
|
3425
|
+
workflowRunId: context.workflowRunId,
|
|
3426
|
+
...rest
|
|
3427
|
+
});
|
|
3428
|
+
},
|
|
3429
|
+
runCompleted(params) {
|
|
3430
|
+
const { context, ...rest } = params;
|
|
3431
|
+
console.log(" [Upstash Workflow]: Workflow run completed:", {
|
|
3432
|
+
workflowRunId: context.workflowRunId,
|
|
3433
|
+
...rest
|
|
3434
|
+
});
|
|
3435
|
+
},
|
|
3436
|
+
onError: onErrorWithConsole,
|
|
3437
|
+
onWarning: onWarningWithConsole,
|
|
3438
|
+
onInfo: onInfoWithConsole
|
|
3439
|
+
}
|
|
3440
|
+
});
|
|
3441
|
+
|
|
3442
|
+
// src/serve/options.ts
|
|
3443
|
+
var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
3444
|
+
const baseHeaders = {
|
|
3445
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3446
|
+
"Upstash-workflow-sdk": VERSION
|
|
3447
|
+
};
|
|
3448
|
+
if (detailedFinishCondition?.condition === "auth-fail") {
|
|
3449
|
+
return {
|
|
3450
|
+
text: JSON.stringify({
|
|
3451
|
+
message: AUTH_FAIL_MESSAGE,
|
|
3452
|
+
workflowRunId
|
|
3453
|
+
}),
|
|
3454
|
+
status: 400,
|
|
3455
|
+
headers: baseHeaders
|
|
3456
|
+
};
|
|
3457
|
+
} else if (detailedFinishCondition?.condition === "non-retryable-error") {
|
|
3458
|
+
return {
|
|
3459
|
+
text: JSON.stringify(formatWorkflowError(detailedFinishCondition.result)),
|
|
3460
|
+
status: 489,
|
|
3461
|
+
headers: {
|
|
3462
|
+
...baseHeaders,
|
|
3463
|
+
"Upstash-NonRetryable-Error": "true"
|
|
3464
|
+
}
|
|
3465
|
+
};
|
|
3466
|
+
} else if (detailedFinishCondition?.condition === "retry-after-error") {
|
|
3467
|
+
return {
|
|
3468
|
+
text: JSON.stringify(formatWorkflowError(detailedFinishCondition.result)),
|
|
3469
|
+
status: 429,
|
|
3470
|
+
headers: {
|
|
3471
|
+
...baseHeaders,
|
|
3472
|
+
"Retry-After": detailedFinishCondition.result.retryAfter.toString()
|
|
3473
|
+
}
|
|
3474
|
+
};
|
|
3475
|
+
} else if (detailedFinishCondition?.condition === "failure-callback-executed") {
|
|
3476
|
+
return {
|
|
3477
|
+
text: JSON.stringify({ result: detailedFinishCondition.result ?? void 0 }),
|
|
3478
|
+
status: 200,
|
|
3479
|
+
headers: baseHeaders
|
|
3480
|
+
};
|
|
3481
|
+
} else if (detailedFinishCondition?.condition === "failure-callback-undefined") {
|
|
3482
|
+
return {
|
|
3483
|
+
text: JSON.stringify({
|
|
3484
|
+
workflowRunId,
|
|
3485
|
+
finishCondition: detailedFinishCondition.condition
|
|
3486
|
+
}),
|
|
3487
|
+
status: 200,
|
|
3488
|
+
headers: {
|
|
3489
|
+
...baseHeaders,
|
|
3490
|
+
"Upstash-Workflow-Failure-Callback-Notfound": "true"
|
|
3491
|
+
}
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3494
|
+
return {
|
|
3495
|
+
text: JSON.stringify({
|
|
3496
|
+
workflowRunId,
|
|
3497
|
+
finishCondition: detailedFinishCondition.condition
|
|
3498
|
+
}),
|
|
3499
|
+
status: 200,
|
|
3500
|
+
headers: baseHeaders
|
|
3501
|
+
};
|
|
3502
|
+
};
|
|
3503
|
+
var processOptions = (options, internalOptions) => {
|
|
3504
|
+
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3505
|
+
const {
|
|
3506
|
+
qstashHandlers,
|
|
3507
|
+
defaultClient: qstashClient,
|
|
3508
|
+
defaultReceiver: receiver
|
|
3509
|
+
} = getQStashHandlerOptions({
|
|
3510
|
+
environment,
|
|
3511
|
+
qstashClientOption: options?.qstashClient,
|
|
3512
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3513
|
+
});
|
|
3514
|
+
return {
|
|
3515
|
+
qstashClient,
|
|
3166
3516
|
initialPayloadParser: (initialRequest) => {
|
|
3167
3517
|
if (!initialRequest) {
|
|
3168
3518
|
return void 0;
|
|
@@ -3177,35 +3527,38 @@ var processOptions = (options) => {
|
|
|
3177
3527
|
throw error;
|
|
3178
3528
|
}
|
|
3179
3529
|
},
|
|
3180
|
-
receiver
|
|
3181
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3182
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3183
|
-
}) : void 0,
|
|
3530
|
+
receiver,
|
|
3184
3531
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3185
3532
|
env: environment,
|
|
3186
|
-
retries: DEFAULT_RETRIES,
|
|
3187
|
-
useJSONContent: false,
|
|
3188
3533
|
disableTelemetry: false,
|
|
3189
|
-
|
|
3190
|
-
|
|
3534
|
+
...options,
|
|
3535
|
+
// merge middlewares
|
|
3536
|
+
middlewares: [options?.middlewares ?? [], options?.verbose ? [loggingMiddleware] : []].flat(),
|
|
3537
|
+
internal: {
|
|
3538
|
+
generateResponse: internalOptions?.generateResponse ?? ((responseData) => {
|
|
3539
|
+
return new Response(responseData.text, {
|
|
3540
|
+
status: responseData.status,
|
|
3541
|
+
headers: responseData.headers
|
|
3542
|
+
});
|
|
3543
|
+
}),
|
|
3544
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3545
|
+
qstashHandlers
|
|
3546
|
+
}
|
|
3191
3547
|
};
|
|
3192
3548
|
};
|
|
3193
|
-
var determineUrls = async (request, url, baseUrl,
|
|
3549
|
+
var determineUrls = async (request, url, baseUrl, dispatchDebug) => {
|
|
3194
3550
|
const initialWorkflowUrl = url ?? request.url;
|
|
3195
3551
|
const workflowUrl = baseUrl ? initialWorkflowUrl.replace(/^(https?:\/\/[^/]+)(\/.*)?$/, (_, matchedBaseUrl, path) => {
|
|
3196
3552
|
return baseUrl + (path || "");
|
|
3197
3553
|
}) : initialWorkflowUrl;
|
|
3198
3554
|
if (workflowUrl !== initialWorkflowUrl) {
|
|
3199
|
-
await
|
|
3200
|
-
|
|
3201
|
-
originalURL: initialWorkflowUrl,
|
|
3202
|
-
updatedURL: workflowUrl
|
|
3555
|
+
await dispatchDebug("onInfo", {
|
|
3556
|
+
info: `The workflow URL's base URL has been replaced with the provided baseUrl. Original URL: ${initialWorkflowUrl}, New URL: ${workflowUrl}`
|
|
3203
3557
|
});
|
|
3204
3558
|
}
|
|
3205
|
-
const workflowFailureUrl = failureFunction ? workflowUrl : failureUrl;
|
|
3206
3559
|
if (workflowUrl.includes("localhost")) {
|
|
3207
|
-
await
|
|
3208
|
-
|
|
3560
|
+
await dispatchDebug("onInfo", {
|
|
3561
|
+
info: `Workflow URL contains localhost. This can happen in local development, but shouldn't happen in production unless you have a route which contains localhost. Received: ${workflowUrl}`
|
|
3209
3562
|
});
|
|
3210
3563
|
}
|
|
3211
3564
|
if (!(workflowUrl.startsWith("http://") || workflowUrl.startsWith("https://"))) {
|
|
@@ -3214,205 +3567,224 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
|
|
|
3214
3567
|
);
|
|
3215
3568
|
}
|
|
3216
3569
|
return {
|
|
3217
|
-
workflowUrl
|
|
3218
|
-
workflowFailureUrl
|
|
3570
|
+
workflowUrl
|
|
3219
3571
|
};
|
|
3220
3572
|
};
|
|
3221
3573
|
var AUTH_FAIL_MESSAGE = `Failed to authenticate Workflow request. If this is unexpected, see the caveat https://upstash.com/docs/workflow/basics/caveats#avoid-non-deterministic-code-outside-context-run`;
|
|
3222
3574
|
|
|
3223
3575
|
// src/serve/index.ts
|
|
3224
|
-
var serveBase = (routeFunction, telemetry, options) => {
|
|
3576
|
+
var serveBase = (routeFunction, telemetry, options, internalOptions) => {
|
|
3225
3577
|
const {
|
|
3226
|
-
qstashClient,
|
|
3227
|
-
onStepFinish,
|
|
3228
3578
|
initialPayloadParser,
|
|
3229
3579
|
url,
|
|
3230
|
-
verbose,
|
|
3231
|
-
receiver,
|
|
3232
|
-
failureUrl,
|
|
3233
3580
|
failureFunction,
|
|
3234
3581
|
baseUrl,
|
|
3235
3582
|
env,
|
|
3236
|
-
retries,
|
|
3237
|
-
retryDelay,
|
|
3238
|
-
useJSONContent,
|
|
3239
3583
|
disableTelemetry,
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
} = processOptions(options);
|
|
3584
|
+
middlewares,
|
|
3585
|
+
internal
|
|
3586
|
+
} = processOptions(options, internalOptions);
|
|
3243
3587
|
telemetry = disableTelemetry ? void 0 : telemetry;
|
|
3244
|
-
const
|
|
3245
|
-
const handler = async (request) => {
|
|
3246
|
-
await
|
|
3247
|
-
|
|
3588
|
+
const { generateResponse: responseGenerator, useJSONContent } = internal;
|
|
3589
|
+
const handler = async (request, middlewareManager) => {
|
|
3590
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3591
|
+
info: `Received request for workflow execution.`
|
|
3592
|
+
});
|
|
3593
|
+
const { workflowUrl } = await determineUrls(
|
|
3248
3594
|
request,
|
|
3249
3595
|
url,
|
|
3250
3596
|
baseUrl,
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3597
|
+
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3598
|
+
);
|
|
3599
|
+
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3600
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3601
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3602
|
+
internal.qstashHandlers,
|
|
3603
|
+
regionHeader,
|
|
3604
|
+
isFirstInvocation
|
|
3254
3605
|
);
|
|
3255
3606
|
const requestPayload = await getPayload(request) ?? "";
|
|
3256
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"),
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3607
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3608
|
+
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3609
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3610
|
+
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
3611
|
+
});
|
|
3612
|
+
const { rawInitialPayload, steps, isLastDuplicate, workflowRunEnded } = await parseRequest({
|
|
3260
3613
|
requestPayload,
|
|
3261
3614
|
isFirstInvocation,
|
|
3615
|
+
unknownSdk,
|
|
3262
3616
|
workflowRunId,
|
|
3263
|
-
|
|
3264
|
-
request.headers.get("upstash-message-id"),
|
|
3265
|
-
|
|
3266
|
-
);
|
|
3617
|
+
requester: regionalClient.http,
|
|
3618
|
+
messageId: request.headers.get("upstash-message-id"),
|
|
3619
|
+
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3620
|
+
});
|
|
3267
3621
|
if (workflowRunEnded) {
|
|
3268
|
-
return
|
|
3269
|
-
|
|
3270
|
-
|
|
3622
|
+
return responseGenerator(
|
|
3623
|
+
createResponseData(workflowRunId, {
|
|
3624
|
+
condition: "workflow-already-ended"
|
|
3625
|
+
})
|
|
3626
|
+
);
|
|
3271
3627
|
}
|
|
3272
3628
|
if (isLastDuplicate) {
|
|
3273
|
-
return
|
|
3274
|
-
|
|
3275
|
-
|
|
3629
|
+
return responseGenerator(
|
|
3630
|
+
createResponseData(workflowRunId, {
|
|
3631
|
+
condition: "duplicate-step"
|
|
3632
|
+
})
|
|
3633
|
+
);
|
|
3276
3634
|
}
|
|
3277
|
-
const failureCheck = await handleFailure(
|
|
3635
|
+
const failureCheck = await handleFailure({
|
|
3278
3636
|
request,
|
|
3279
3637
|
requestPayload,
|
|
3280
|
-
qstashClient,
|
|
3638
|
+
qstashClient: regionalClient,
|
|
3281
3639
|
initialPayloadParser,
|
|
3282
3640
|
routeFunction,
|
|
3283
3641
|
failureFunction,
|
|
3284
3642
|
env,
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
flowControl,
|
|
3288
|
-
debug
|
|
3289
|
-
);
|
|
3643
|
+
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3644
|
+
});
|
|
3290
3645
|
if (failureCheck.isErr()) {
|
|
3291
3646
|
throw failureCheck.error;
|
|
3292
|
-
} else if (failureCheck.value.result === "
|
|
3293
|
-
await
|
|
3294
|
-
|
|
3295
|
-
condition: "failure-callback",
|
|
3296
|
-
result: failureCheck.value.response
|
|
3647
|
+
} else if (failureCheck.value.result === "failure-function-executed") {
|
|
3648
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3649
|
+
info: `Handled failure callback.`
|
|
3297
3650
|
});
|
|
3651
|
+
return responseGenerator(
|
|
3652
|
+
createResponseData(workflowRunId, {
|
|
3653
|
+
condition: "failure-callback-executed",
|
|
3654
|
+
result: failureCheck.value.response
|
|
3655
|
+
})
|
|
3656
|
+
);
|
|
3657
|
+
} else if (failureCheck.value.result === "failure-function-undefined") {
|
|
3658
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3659
|
+
info: `Failure callback invoked but no failure function defined.`
|
|
3660
|
+
});
|
|
3661
|
+
return responseGenerator(
|
|
3662
|
+
createResponseData(workflowRunId, {
|
|
3663
|
+
condition: "failure-callback-undefined"
|
|
3664
|
+
})
|
|
3665
|
+
);
|
|
3298
3666
|
}
|
|
3299
3667
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3300
3668
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3301
3669
|
const workflowContext = new WorkflowContext({
|
|
3302
|
-
qstashClient,
|
|
3670
|
+
qstashClient: regionalClient,
|
|
3303
3671
|
workflowRunId,
|
|
3304
3672
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3305
3673
|
headers: recreateUserHeaders(request.headers),
|
|
3306
3674
|
steps,
|
|
3307
3675
|
url: workflowUrl,
|
|
3308
|
-
failureUrl: workflowFailureUrl,
|
|
3309
|
-
debug,
|
|
3310
3676
|
env,
|
|
3311
|
-
retries,
|
|
3312
|
-
retryDelay,
|
|
3313
3677
|
telemetry,
|
|
3314
3678
|
invokeCount,
|
|
3315
|
-
|
|
3316
|
-
|
|
3679
|
+
label,
|
|
3680
|
+
middlewareManager
|
|
3317
3681
|
});
|
|
3318
3682
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
3319
3683
|
routeFunction,
|
|
3320
3684
|
workflowContext
|
|
3321
3685
|
);
|
|
3322
3686
|
if (authCheck.isErr()) {
|
|
3323
|
-
await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
|
|
3324
3687
|
throw authCheck.error;
|
|
3325
3688
|
} else if (authCheck.value === "run-ended") {
|
|
3326
|
-
await
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3689
|
+
await middlewareManager.dispatchDebug("onError", {
|
|
3690
|
+
error: new Error(AUTH_FAIL_MESSAGE)
|
|
3691
|
+
});
|
|
3692
|
+
return responseGenerator(
|
|
3693
|
+
createResponseData(isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId, {
|
|
3694
|
+
condition: "auth-fail"
|
|
3695
|
+
})
|
|
3331
3696
|
);
|
|
3332
3697
|
}
|
|
3333
3698
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3334
3699
|
request,
|
|
3335
3700
|
requestPayload: rawInitialPayload,
|
|
3336
|
-
client:
|
|
3701
|
+
client: regionalClient,
|
|
3337
3702
|
workflowUrl,
|
|
3338
|
-
failureUrl: workflowFailureUrl,
|
|
3339
|
-
retries,
|
|
3340
|
-
retryDelay,
|
|
3341
|
-
flowControl,
|
|
3342
3703
|
telemetry,
|
|
3343
|
-
|
|
3704
|
+
middlewareManager
|
|
3344
3705
|
});
|
|
3345
3706
|
if (callReturnCheck.isErr()) {
|
|
3346
|
-
await debug?.log("ERROR", "SUBMIT_THIRD_PARTY_RESULT", {
|
|
3347
|
-
error: callReturnCheck.error.message
|
|
3348
|
-
});
|
|
3349
3707
|
throw callReturnCheck.error;
|
|
3350
3708
|
} else if (callReturnCheck.value === "continue-workflow") {
|
|
3351
3709
|
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3352
3710
|
workflowContext,
|
|
3353
3711
|
useJSONContent,
|
|
3354
3712
|
telemetry,
|
|
3355
|
-
|
|
3356
|
-
|
|
3713
|
+
invokeCount,
|
|
3714
|
+
middlewareManager,
|
|
3715
|
+
unknownSdk
|
|
3357
3716
|
}) : await triggerRouteFunction({
|
|
3358
|
-
onStep: async () =>
|
|
3717
|
+
onStep: async () => {
|
|
3718
|
+
if (steps.length === 1) {
|
|
3719
|
+
await middlewareManager.dispatchLifecycle("runStarted", {});
|
|
3720
|
+
}
|
|
3721
|
+
return await routeFunction(workflowContext);
|
|
3722
|
+
},
|
|
3359
3723
|
onCleanup: async (result2) => {
|
|
3360
|
-
await
|
|
3724
|
+
await middlewareManager.dispatchLifecycle("runCompleted", {
|
|
3725
|
+
result: result2
|
|
3726
|
+
});
|
|
3727
|
+
await triggerWorkflowDelete(
|
|
3728
|
+
workflowContext,
|
|
3729
|
+
result2,
|
|
3730
|
+
false,
|
|
3731
|
+
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3732
|
+
);
|
|
3361
3733
|
},
|
|
3362
3734
|
onCancel: async () => {
|
|
3363
3735
|
await makeCancelRequest(workflowContext.qstashClient.http, workflowRunId);
|
|
3364
3736
|
},
|
|
3365
|
-
|
|
3737
|
+
middlewareManager
|
|
3366
3738
|
});
|
|
3367
3739
|
if (result.isOk() && isInstanceOf(result.value, WorkflowNonRetryableError)) {
|
|
3368
|
-
return
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3740
|
+
return responseGenerator(
|
|
3741
|
+
createResponseData(workflowRunId, {
|
|
3742
|
+
condition: "non-retryable-error",
|
|
3743
|
+
result: result.value
|
|
3744
|
+
})
|
|
3745
|
+
);
|
|
3372
3746
|
}
|
|
3373
3747
|
if (result.isOk() && isInstanceOf(result.value, WorkflowRetryAfterError)) {
|
|
3374
|
-
return
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3748
|
+
return responseGenerator(
|
|
3749
|
+
createResponseData(workflowRunId, {
|
|
3750
|
+
condition: "retry-after-error",
|
|
3751
|
+
result: result.value
|
|
3752
|
+
})
|
|
3753
|
+
);
|
|
3378
3754
|
}
|
|
3379
3755
|
if (result.isErr()) {
|
|
3380
|
-
await debug?.log("ERROR", "ERROR", { error: result.error.message });
|
|
3381
3756
|
throw result.error;
|
|
3382
3757
|
}
|
|
3383
|
-
await
|
|
3384
|
-
|
|
3385
|
-
condition: "success"
|
|
3758
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3759
|
+
info: `Workflow endpoint execution completed successfully.`
|
|
3386
3760
|
});
|
|
3761
|
+
return responseGenerator(
|
|
3762
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
3763
|
+
condition: "success"
|
|
3764
|
+
})
|
|
3765
|
+
);
|
|
3387
3766
|
} else if (callReturnCheck.value === "workflow-ended") {
|
|
3388
|
-
return
|
|
3389
|
-
|
|
3390
|
-
|
|
3767
|
+
return responseGenerator(
|
|
3768
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
3769
|
+
condition: "workflow-already-ended"
|
|
3770
|
+
})
|
|
3771
|
+
);
|
|
3391
3772
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3773
|
+
return responseGenerator(
|
|
3774
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
3775
|
+
condition: "fromCallback"
|
|
3776
|
+
})
|
|
3777
|
+
);
|
|
3396
3778
|
};
|
|
3397
3779
|
const safeHandler = async (request) => {
|
|
3780
|
+
const middlewareManager = new MiddlewareManager(middlewares);
|
|
3398
3781
|
try {
|
|
3399
|
-
return await handler(request);
|
|
3782
|
+
return await handler(request, middlewareManager);
|
|
3400
3783
|
} catch (error) {
|
|
3401
3784
|
const formattedError = formatWorkflowError(error);
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
}
|
|
3405
|
-
const formattedOnErrorError = formatWorkflowError(onErrorError);
|
|
3406
|
-
const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
|
|
3407
|
-
Original error: '${formattedError.message}'`;
|
|
3408
|
-
console.error(errorMessage);
|
|
3409
|
-
return new Response(JSON.stringify({ error: errorMessage }), {
|
|
3410
|
-
status: 500,
|
|
3411
|
-
headers: {
|
|
3412
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3413
|
-
}
|
|
3414
|
-
});
|
|
3415
|
-
}
|
|
3785
|
+
await middlewareManager.dispatchDebug("onError", {
|
|
3786
|
+
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
3787
|
+
});
|
|
3416
3788
|
return new Response(JSON.stringify(formattedError), {
|
|
3417
3789
|
status: 500,
|
|
3418
3790
|
headers: {
|
|
@@ -3468,7 +3840,7 @@ var serveMany = (workflows, options) => {
|
|
|
3468
3840
|
};
|
|
3469
3841
|
};
|
|
3470
3842
|
var servePagesRouter = (routeFunction, options) => {
|
|
3471
|
-
const { handler: serveHandler } = serveBase(routeFunction, pagesTelemetry, options);
|
|
3843
|
+
const { handler: serveHandler } = serveBase(routeFunction, pagesTelemetry, options, void 0);
|
|
3472
3844
|
const handler = async (request_, res) => {
|
|
3473
3845
|
if (request_.method?.toUpperCase() !== "POST") {
|
|
3474
3846
|
res.status(405).json("Only POST requests are allowed in worklfows");
|