@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/h3.js
CHANGED
|
@@ -347,26 +347,36 @@ var WorkflowError = class extends import_qstash.QstashError {
|
|
|
347
347
|
}
|
|
348
348
|
};
|
|
349
349
|
var WorkflowAbort = class extends Error {
|
|
350
|
-
stepInfo;
|
|
351
350
|
stepName;
|
|
351
|
+
stepInfo;
|
|
352
352
|
/**
|
|
353
|
-
* whether workflow is to be canceled on abort
|
|
354
|
-
*/
|
|
355
|
-
cancelWorkflow;
|
|
356
|
-
/**
|
|
357
|
-
*
|
|
358
353
|
* @param stepName name of the aborting step
|
|
359
354
|
* @param stepInfo step information
|
|
360
|
-
* @param cancelWorkflow
|
|
361
355
|
*/
|
|
362
|
-
constructor(stepName, stepInfo
|
|
356
|
+
constructor(stepName, stepInfo) {
|
|
363
357
|
super(
|
|
364
358
|
`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}'.`
|
|
365
359
|
);
|
|
366
360
|
this.name = "WorkflowAbort";
|
|
367
361
|
this.stepName = stepName;
|
|
368
362
|
this.stepInfo = stepInfo;
|
|
369
|
-
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
var WorkflowAuthError = class extends WorkflowAbort {
|
|
366
|
+
/**
|
|
367
|
+
* @param stepName name of the step found during authorization
|
|
368
|
+
*/
|
|
369
|
+
constructor(stepName) {
|
|
370
|
+
super(stepName);
|
|
371
|
+
this.name = "WorkflowAuthError";
|
|
372
|
+
this.message = `This is an Upstash Workflow error thrown during authorization check. Found step '${stepName}' during dry-run.`;
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
var WorkflowCancelAbort = class extends WorkflowAbort {
|
|
376
|
+
constructor() {
|
|
377
|
+
super("cancel");
|
|
378
|
+
this.name = "WorkflowCancelAbort";
|
|
379
|
+
this.message = "Workflow has been canceled by user via context.cancel().";
|
|
370
380
|
}
|
|
371
381
|
};
|
|
372
382
|
var WorkflowNonRetryableError = class extends WorkflowAbort {
|
|
@@ -374,22 +384,22 @@ var WorkflowNonRetryableError = class extends WorkflowAbort {
|
|
|
374
384
|
* @param message error message to be displayed
|
|
375
385
|
*/
|
|
376
386
|
constructor(message) {
|
|
377
|
-
super("
|
|
387
|
+
super("non-retryable-error");
|
|
378
388
|
this.name = "WorkflowNonRetryableError";
|
|
379
|
-
|
|
389
|
+
this.message = message ?? "Workflow failed with non-retryable error.";
|
|
380
390
|
}
|
|
381
391
|
};
|
|
382
392
|
var WorkflowRetryAfterError = class extends WorkflowAbort {
|
|
383
393
|
retryAfter;
|
|
384
394
|
/**
|
|
385
|
-
* @param retryAfter time in seconds after which the workflow should be retried
|
|
386
395
|
* @param message error message to be displayed
|
|
396
|
+
* @param retryAfter time in seconds after which the workflow should be retried
|
|
387
397
|
*/
|
|
388
398
|
constructor(message, retryAfter) {
|
|
389
|
-
super("retry"
|
|
399
|
+
super("retry-after-error");
|
|
390
400
|
this.name = "WorkflowRetryAfterError";
|
|
401
|
+
this.message = message;
|
|
391
402
|
this.retryAfter = retryAfter;
|
|
392
|
-
if (message) this.message = message;
|
|
393
403
|
}
|
|
394
404
|
};
|
|
395
405
|
var formatWorkflowError = (error) => {
|
|
@@ -441,15 +451,21 @@ var makeCancelRequest = async (requester, workflowRunId) => {
|
|
|
441
451
|
});
|
|
442
452
|
return true;
|
|
443
453
|
};
|
|
444
|
-
var getSteps = async (requester, workflowRunId, messageId,
|
|
454
|
+
var getSteps = async (requester, workflowRunId, messageId, dispatchDebug) => {
|
|
445
455
|
try {
|
|
446
456
|
const steps = await requester.request({
|
|
447
457
|
path: ["v2", "workflows", "runs", workflowRunId],
|
|
448
458
|
parseResponseAsJson: true
|
|
449
459
|
});
|
|
460
|
+
if (steps.length === 1) {
|
|
461
|
+
return {
|
|
462
|
+
steps,
|
|
463
|
+
workflowRunEnded: false
|
|
464
|
+
};
|
|
465
|
+
}
|
|
450
466
|
if (!messageId) {
|
|
451
|
-
await
|
|
452
|
-
|
|
467
|
+
await dispatchDebug?.("onInfo", {
|
|
468
|
+
info: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
453
469
|
});
|
|
454
470
|
return { steps, workflowRunEnded: false };
|
|
455
471
|
} else {
|
|
@@ -458,16 +474,15 @@ var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
|
458
474
|
return { steps: [], workflowRunEnded: false };
|
|
459
475
|
}
|
|
460
476
|
const filteredSteps = steps.slice(0, index + 1);
|
|
461
|
-
await
|
|
462
|
-
|
|
477
|
+
await dispatchDebug?.("onInfo", {
|
|
478
|
+
info: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
|
|
463
479
|
});
|
|
464
480
|
return { steps: filteredSteps, workflowRunEnded: false };
|
|
465
481
|
}
|
|
466
482
|
} catch (error) {
|
|
467
483
|
if (isInstanceOf(error, import_qstash2.QstashError) && error.status === 404) {
|
|
468
|
-
await
|
|
469
|
-
|
|
470
|
-
error
|
|
484
|
+
await dispatchDebug?.("onWarning", {
|
|
485
|
+
warning: "Couldn't fetch workflow run steps. This can happen if the workflow run succesfully ends before some callback is executed."
|
|
471
486
|
});
|
|
472
487
|
return { steps: void 0, workflowRunEnded: true };
|
|
473
488
|
} else {
|
|
@@ -481,15 +496,18 @@ var WORKFLOW_ID_HEADER = "Upstash-Workflow-RunId";
|
|
|
481
496
|
var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
|
|
482
497
|
var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
|
|
483
498
|
var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
|
|
499
|
+
var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
|
|
484
500
|
var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
|
|
485
501
|
var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
|
|
486
502
|
var WORKFLOW_LABEL_HEADER = "Upstash-Label";
|
|
503
|
+
var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
|
|
504
|
+
var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
|
|
487
505
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
488
506
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
489
507
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
490
508
|
var NO_CONCURRENCY = 1;
|
|
491
509
|
var DEFAULT_RETRIES = 3;
|
|
492
|
-
var VERSION = "
|
|
510
|
+
var VERSION = "v1.0.0";
|
|
493
511
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
494
512
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
495
513
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -507,8 +525,8 @@ var NANOID_LENGTH = 21;
|
|
|
507
525
|
function getRandomInt() {
|
|
508
526
|
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
509
527
|
}
|
|
510
|
-
function nanoid() {
|
|
511
|
-
return Array.from({ length
|
|
528
|
+
function nanoid(length = NANOID_LENGTH) {
|
|
529
|
+
return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
|
|
512
530
|
}
|
|
513
531
|
function getWorkflowRunId(id) {
|
|
514
532
|
return `wfr_${id ?? nanoid()}`;
|
|
@@ -525,6 +543,46 @@ function decodeBase64(base64) {
|
|
|
525
543
|
return binString;
|
|
526
544
|
}
|
|
527
545
|
}
|
|
546
|
+
function getUserIdFromToken(qstashClient) {
|
|
547
|
+
try {
|
|
548
|
+
const token = qstashClient.token;
|
|
549
|
+
const decodedToken = decodeBase64(token);
|
|
550
|
+
const tokenPayload = JSON.parse(decodedToken);
|
|
551
|
+
const userId = tokenPayload.UserID;
|
|
552
|
+
if (!userId) {
|
|
553
|
+
throw new WorkflowError("QStash token payload does not contain userId");
|
|
554
|
+
}
|
|
555
|
+
return userId;
|
|
556
|
+
} catch (error) {
|
|
557
|
+
throw new WorkflowError(
|
|
558
|
+
`Failed to decode QStash token while running create webhook step: ${error.message}`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function getQStashUrl(qstashClient) {
|
|
563
|
+
try {
|
|
564
|
+
const requester = qstashClient.http;
|
|
565
|
+
const baseUrl = requester.baseUrl;
|
|
566
|
+
if (!baseUrl) {
|
|
567
|
+
throw new WorkflowError("QStash client does not have a baseUrl");
|
|
568
|
+
}
|
|
569
|
+
return baseUrl;
|
|
570
|
+
} catch (error) {
|
|
571
|
+
throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function getEventId() {
|
|
575
|
+
return `evt_${nanoid(15)}`;
|
|
576
|
+
}
|
|
577
|
+
function stringifyBody(body) {
|
|
578
|
+
if (body === void 0) {
|
|
579
|
+
return void 0;
|
|
580
|
+
}
|
|
581
|
+
if (typeof body === "string") {
|
|
582
|
+
return body;
|
|
583
|
+
}
|
|
584
|
+
return JSON.stringify(body);
|
|
585
|
+
}
|
|
528
586
|
|
|
529
587
|
// node_modules/neverthrow/dist/index.es.js
|
|
530
588
|
var defaultErrorConfig = {
|
|
@@ -950,7 +1008,9 @@ var StepTypes = [
|
|
|
950
1008
|
"Call",
|
|
951
1009
|
"Wait",
|
|
952
1010
|
"Notify",
|
|
953
|
-
"Invoke"
|
|
1011
|
+
"Invoke",
|
|
1012
|
+
"CreateWebhook",
|
|
1013
|
+
"WaitForWebhook"
|
|
954
1014
|
];
|
|
955
1015
|
|
|
956
1016
|
// src/workflow-requests.ts
|
|
@@ -966,23 +1026,26 @@ var triggerFirstInvocation = async (params) => {
|
|
|
966
1026
|
invokeCount,
|
|
967
1027
|
delay,
|
|
968
1028
|
notBefore,
|
|
969
|
-
|
|
1029
|
+
failureUrl,
|
|
1030
|
+
retries,
|
|
1031
|
+
retryDelay,
|
|
1032
|
+
flowControl,
|
|
1033
|
+
unknownSdk
|
|
970
1034
|
}) => {
|
|
971
1035
|
const { headers } = getHeaders({
|
|
972
1036
|
initHeaderValue: "true",
|
|
973
1037
|
workflowConfig: {
|
|
974
1038
|
workflowRunId: workflowContext.workflowRunId,
|
|
975
1039
|
workflowUrl: workflowContext.url,
|
|
976
|
-
failureUrl
|
|
977
|
-
retries
|
|
978
|
-
retryDelay
|
|
1040
|
+
failureUrl,
|
|
1041
|
+
retries,
|
|
1042
|
+
retryDelay,
|
|
979
1043
|
telemetry: telemetry2,
|
|
980
|
-
flowControl
|
|
1044
|
+
flowControl,
|
|
981
1045
|
useJSONContent: useJSONContent ?? false
|
|
982
1046
|
},
|
|
983
1047
|
invokeCount: invokeCount ?? 0,
|
|
984
|
-
userHeaders: workflowContext.headers
|
|
985
|
-
keepTriggerConfig
|
|
1048
|
+
userHeaders: workflowContext.headers
|
|
986
1049
|
});
|
|
987
1050
|
if (workflowContext.headers.get("content-type")) {
|
|
988
1051
|
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
@@ -990,6 +1053,9 @@ var triggerFirstInvocation = async (params) => {
|
|
|
990
1053
|
if (useJSONContent) {
|
|
991
1054
|
headers["content-type"] = "application/json";
|
|
992
1055
|
}
|
|
1056
|
+
if (unknownSdk) {
|
|
1057
|
+
headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
|
|
1058
|
+
}
|
|
993
1059
|
if (workflowContext.label) {
|
|
994
1060
|
headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
|
|
995
1061
|
}
|
|
@@ -1010,21 +1076,15 @@ var triggerFirstInvocation = async (params) => {
|
|
|
1010
1076
|
for (let i = 0; i < results.length; i++) {
|
|
1011
1077
|
const result = results[i];
|
|
1012
1078
|
const invocationParams = firstInvocationParams[i];
|
|
1079
|
+
invocationParams.middlewareManager?.assignContext(invocationParams.workflowContext);
|
|
1013
1080
|
if (result.deduplicated) {
|
|
1014
|
-
await invocationParams.
|
|
1015
|
-
|
|
1016
|
-
headers: invocationBatch[i].headers,
|
|
1017
|
-
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
1018
|
-
url: invocationParams.workflowContext.url,
|
|
1019
|
-
messageId: result.messageId
|
|
1081
|
+
await invocationParams.middlewareManager?.dispatchDebug("onWarning", {
|
|
1082
|
+
warning: `Workflow run ${invocationParams.workflowContext.workflowRunId} already exists. A new one isn't created.`
|
|
1020
1083
|
});
|
|
1021
1084
|
invocationStatuses.push("workflow-run-already-exists");
|
|
1022
1085
|
} else {
|
|
1023
|
-
await invocationParams.
|
|
1024
|
-
|
|
1025
|
-
requestPayload: invocationParams.workflowContext.requestPayload,
|
|
1026
|
-
url: invocationParams.workflowContext.url,
|
|
1027
|
-
messageId: result.messageId
|
|
1086
|
+
await invocationParams.middlewareManager?.dispatchDebug("onInfo", {
|
|
1087
|
+
info: `Workflow run started successfully with URL ${invocationParams.workflowContext.url}.`
|
|
1028
1088
|
});
|
|
1029
1089
|
invocationStatuses.push("success");
|
|
1030
1090
|
}
|
|
@@ -1046,7 +1106,7 @@ var triggerRouteFunction = async ({
|
|
|
1046
1106
|
onCleanup,
|
|
1047
1107
|
onStep,
|
|
1048
1108
|
onCancel,
|
|
1049
|
-
|
|
1109
|
+
middlewareManager
|
|
1050
1110
|
}) => {
|
|
1051
1111
|
try {
|
|
1052
1112
|
const result = await onStep();
|
|
@@ -1055,27 +1115,25 @@ var triggerRouteFunction = async ({
|
|
|
1055
1115
|
} catch (error) {
|
|
1056
1116
|
const error_ = error;
|
|
1057
1117
|
if (isInstanceOf(error, import_qstash3.QstashError) && error.status === 400) {
|
|
1058
|
-
await
|
|
1059
|
-
|
|
1060
|
-
name: error.name,
|
|
1061
|
-
errorMessage: error.message
|
|
1118
|
+
await middlewareManager?.dispatchDebug("onWarning", {
|
|
1119
|
+
warning: `Tried to append to a cancelled workflow. Exiting without publishing. Error: ${error.message}`
|
|
1062
1120
|
});
|
|
1063
1121
|
return ok("workflow-was-finished");
|
|
1064
1122
|
} else if (isInstanceOf(error_, WorkflowNonRetryableError) || isInstanceOf(error_, WorkflowRetryAfterError)) {
|
|
1065
1123
|
return ok(error_);
|
|
1066
|
-
} else if (
|
|
1067
|
-
return err(error_);
|
|
1068
|
-
} else if (error_.cancelWorkflow) {
|
|
1124
|
+
} else if (isInstanceOf(error_, WorkflowCancelAbort)) {
|
|
1069
1125
|
await onCancel();
|
|
1070
1126
|
return ok("workflow-finished");
|
|
1071
|
-
} else {
|
|
1127
|
+
} else if (isInstanceOf(error_, WorkflowAbort)) {
|
|
1072
1128
|
return ok("step-finished");
|
|
1129
|
+
} else {
|
|
1130
|
+
return err(error_);
|
|
1073
1131
|
}
|
|
1074
1132
|
}
|
|
1075
1133
|
};
|
|
1076
|
-
var triggerWorkflowDelete = async (workflowContext, result,
|
|
1077
|
-
await
|
|
1078
|
-
|
|
1134
|
+
var triggerWorkflowDelete = async (workflowContext, result, cancel = false, dispatchDebug) => {
|
|
1135
|
+
await dispatchDebug?.("onInfo", {
|
|
1136
|
+
info: `Deleting workflow run ${workflowContext.workflowRunId} from QStash` + (cancel ? " with cancel=true." : ".")
|
|
1079
1137
|
});
|
|
1080
1138
|
await workflowContext.qstashClient.http.request({
|
|
1081
1139
|
path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
|
|
@@ -1083,18 +1141,16 @@ var triggerWorkflowDelete = async (workflowContext, result, debug, cancel = fals
|
|
|
1083
1141
|
parseResponseAsJson: false,
|
|
1084
1142
|
body: JSON.stringify(result)
|
|
1085
1143
|
});
|
|
1086
|
-
await
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
`workflow run ${workflowContext.workflowRunId} deleted.`
|
|
1090
|
-
);
|
|
1144
|
+
await dispatchDebug?.("onInfo", {
|
|
1145
|
+
info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
|
|
1146
|
+
});
|
|
1091
1147
|
};
|
|
1092
1148
|
var recreateUserHeaders = (headers) => {
|
|
1093
1149
|
const filteredHeaders = new Headers();
|
|
1094
1150
|
const pairs = headers.entries();
|
|
1095
1151
|
for (const [header, value] of pairs) {
|
|
1096
1152
|
const headerLowerCase = header.toLowerCase();
|
|
1097
|
-
const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
1153
|
+
const isUserHeader = headerLowerCase !== "upstash-region" && !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
|
|
1098
1154
|
!headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
|
|
1099
1155
|
headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
|
|
1100
1156
|
headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
|
|
@@ -1109,12 +1165,8 @@ var handleThirdPartyCallResult = async ({
|
|
|
1109
1165
|
requestPayload,
|
|
1110
1166
|
client,
|
|
1111
1167
|
workflowUrl,
|
|
1112
|
-
failureUrl,
|
|
1113
|
-
retries,
|
|
1114
|
-
retryDelay,
|
|
1115
1168
|
telemetry: telemetry2,
|
|
1116
|
-
|
|
1117
|
-
debug
|
|
1169
|
+
middlewareManager
|
|
1118
1170
|
}) => {
|
|
1119
1171
|
try {
|
|
1120
1172
|
if (request.headers.get("Upstash-Workflow-Callback")) {
|
|
@@ -1131,7 +1183,7 @@ var handleThirdPartyCallResult = async ({
|
|
|
1131
1183
|
client.http,
|
|
1132
1184
|
workflowRunId2,
|
|
1133
1185
|
messageId,
|
|
1134
|
-
|
|
1186
|
+
middlewareManager?.dispatchDebug.bind(middlewareManager)
|
|
1135
1187
|
);
|
|
1136
1188
|
if (workflowRunEnded) {
|
|
1137
1189
|
return ok("workflow-ended");
|
|
@@ -1145,9 +1197,8 @@ var handleThirdPartyCallResult = async ({
|
|
|
1145
1197
|
}
|
|
1146
1198
|
const callbackMessage = JSON.parse(callbackPayload);
|
|
1147
1199
|
if (!(callbackMessage.status >= 200 && callbackMessage.status < 300) && callbackMessage.maxRetries && callbackMessage.retried !== callbackMessage.maxRetries) {
|
|
1148
|
-
await
|
|
1149
|
-
|
|
1150
|
-
body: atob(callbackMessage.body ?? "")
|
|
1200
|
+
await middlewareManager?.dispatchDebug("onWarning", {
|
|
1201
|
+
warning: `Third party call returned status ${callbackMessage.status}. Retrying (${callbackMessage.retried} out of ${callbackMessage.maxRetries}).`
|
|
1151
1202
|
});
|
|
1152
1203
|
console.warn(
|
|
1153
1204
|
`Workflow Warning: "context.call" failed with status ${callbackMessage.status} and will retry (retried ${callbackMessage.retried ?? 0} out of ${callbackMessage.maxRetries} times). Error Message:
|
|
@@ -1180,11 +1231,7 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
1180
1231
|
workflowConfig: {
|
|
1181
1232
|
workflowRunId,
|
|
1182
1233
|
workflowUrl,
|
|
1183
|
-
|
|
1184
|
-
retries,
|
|
1185
|
-
retryDelay,
|
|
1186
|
-
telemetry: telemetry2,
|
|
1187
|
-
flowControl
|
|
1234
|
+
telemetry: telemetry2
|
|
1188
1235
|
},
|
|
1189
1236
|
userHeaders,
|
|
1190
1237
|
invokeCount: Number(invokeCount)
|
|
@@ -1201,19 +1248,17 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
1201
1248
|
out: JSON.stringify(callResponse),
|
|
1202
1249
|
concurrent: Number(concurrentString)
|
|
1203
1250
|
};
|
|
1204
|
-
await
|
|
1205
|
-
|
|
1206
|
-
headers: requestHeaders,
|
|
1207
|
-
url: workflowUrl
|
|
1251
|
+
await middlewareManager?.dispatchDebug("onInfo", {
|
|
1252
|
+
info: `Submitting third party call result, step ${stepName} (${stepIdString}).`
|
|
1208
1253
|
});
|
|
1209
|
-
|
|
1254
|
+
await client.publishJSON({
|
|
1210
1255
|
headers: requestHeaders,
|
|
1211
1256
|
method: "POST",
|
|
1212
1257
|
body: callResultStep,
|
|
1213
1258
|
url: workflowUrl
|
|
1214
1259
|
});
|
|
1215
|
-
await
|
|
1216
|
-
|
|
1260
|
+
await middlewareManager?.dispatchDebug("onInfo", {
|
|
1261
|
+
info: `Third party call result submitted successfully, step ${stepName} (${stepIdString}).`
|
|
1217
1262
|
});
|
|
1218
1263
|
return ok("is-call-return");
|
|
1219
1264
|
} else {
|
|
@@ -1262,15 +1307,17 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
|
|
|
1262
1307
|
// src/context/steps.ts
|
|
1263
1308
|
var BaseLazyStep = class _BaseLazyStep {
|
|
1264
1309
|
stepName;
|
|
1265
|
-
|
|
1310
|
+
context;
|
|
1311
|
+
constructor(context, stepName) {
|
|
1312
|
+
this.context = context;
|
|
1266
1313
|
if (!stepName) {
|
|
1267
1314
|
throw new WorkflowError(
|
|
1268
1315
|
"A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
|
|
1269
1316
|
);
|
|
1270
1317
|
}
|
|
1271
1318
|
if (typeof stepName !== "string") {
|
|
1272
|
-
|
|
1273
|
-
|
|
1319
|
+
throw new WorkflowError(
|
|
1320
|
+
`A workflow step name must be a string. Received "${stepName}" (${typeof stepName}).`
|
|
1274
1321
|
);
|
|
1275
1322
|
}
|
|
1276
1323
|
this.stepName = stepName;
|
|
@@ -1280,13 +1327,14 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1280
1327
|
*
|
|
1281
1328
|
* will be called when returning the steps to the context from auto executor
|
|
1282
1329
|
*
|
|
1283
|
-
* @param
|
|
1330
|
+
* @param step step
|
|
1284
1331
|
* @returns parsed out field
|
|
1285
1332
|
*/
|
|
1286
|
-
parseOut(
|
|
1333
|
+
parseOut(step) {
|
|
1334
|
+
const out = step.out;
|
|
1287
1335
|
if (out === void 0) {
|
|
1288
1336
|
if (this.allowUndefinedOut) {
|
|
1289
|
-
return
|
|
1337
|
+
return this.handleUndefinedOut(step);
|
|
1290
1338
|
} else {
|
|
1291
1339
|
throw new WorkflowError(
|
|
1292
1340
|
`Error while parsing output of ${this.stepType} step. Expected a string, but got: undefined`
|
|
@@ -1294,27 +1342,26 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1294
1342
|
}
|
|
1295
1343
|
}
|
|
1296
1344
|
if (typeof out === "object") {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
return out;
|
|
1302
|
-
}
|
|
1303
|
-
return {
|
|
1304
|
-
...out,
|
|
1305
|
-
eventData: _BaseLazyStep.tryParsing(out.eventData)
|
|
1306
|
-
};
|
|
1345
|
+
console.warn(
|
|
1346
|
+
`Error while parsing ${this.stepType} step output. Expected a string, but got object. Please reach out to Upstash Support.`
|
|
1347
|
+
);
|
|
1348
|
+
return out;
|
|
1307
1349
|
}
|
|
1308
1350
|
if (typeof out !== "string") {
|
|
1309
1351
|
throw new WorkflowError(
|
|
1310
1352
|
`Error while parsing output of ${this.stepType} step. Expected a string or undefined, but got: ${typeof out}`
|
|
1311
1353
|
);
|
|
1312
1354
|
}
|
|
1313
|
-
return this.safeParseOut(out);
|
|
1355
|
+
return this.safeParseOut(out, step);
|
|
1314
1356
|
}
|
|
1315
|
-
|
|
1357
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1358
|
+
safeParseOut(out, step) {
|
|
1316
1359
|
return _BaseLazyStep.tryParsing(out);
|
|
1317
1360
|
}
|
|
1361
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1362
|
+
handleUndefinedOut(step) {
|
|
1363
|
+
return void 0;
|
|
1364
|
+
}
|
|
1318
1365
|
static tryParsing(stepOut) {
|
|
1319
1366
|
try {
|
|
1320
1367
|
return JSON.parse(stepOut);
|
|
@@ -1332,12 +1379,8 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1332
1379
|
workflowConfig: {
|
|
1333
1380
|
workflowRunId: context.workflowRunId,
|
|
1334
1381
|
workflowUrl: context.url,
|
|
1335
|
-
failureUrl: context.failureUrl,
|
|
1336
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1337
|
-
retryDelay: context.retryDelay,
|
|
1338
1382
|
useJSONContent: false,
|
|
1339
|
-
telemetry: telemetry2
|
|
1340
|
-
flowControl: context.flowControl
|
|
1383
|
+
telemetry: telemetry2
|
|
1341
1384
|
},
|
|
1342
1385
|
userHeaders: context.headers,
|
|
1343
1386
|
invokeCount,
|
|
@@ -1353,9 +1396,6 @@ var BaseLazyStep = class _BaseLazyStep {
|
|
|
1353
1396
|
body,
|
|
1354
1397
|
headers,
|
|
1355
1398
|
method: "POST",
|
|
1356
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1357
|
-
retryDelay: context.retryDelay,
|
|
1358
|
-
flowControl: context.flowControl,
|
|
1359
1399
|
url: context.url
|
|
1360
1400
|
}
|
|
1361
1401
|
]);
|
|
@@ -1365,8 +1405,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
|
|
|
1365
1405
|
stepFunction;
|
|
1366
1406
|
stepType = "Run";
|
|
1367
1407
|
allowUndefinedOut = true;
|
|
1368
|
-
constructor(stepName, stepFunction) {
|
|
1369
|
-
super(stepName);
|
|
1408
|
+
constructor(context, stepName, stepFunction) {
|
|
1409
|
+
super(context, stepName);
|
|
1370
1410
|
this.stepFunction = stepFunction;
|
|
1371
1411
|
}
|
|
1372
1412
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -1396,8 +1436,8 @@ var LazySleepStep = class extends BaseLazyStep {
|
|
|
1396
1436
|
sleep;
|
|
1397
1437
|
stepType = "SleepFor";
|
|
1398
1438
|
allowUndefinedOut = true;
|
|
1399
|
-
constructor(stepName, sleep) {
|
|
1400
|
-
super(stepName);
|
|
1439
|
+
constructor(context, stepName, sleep) {
|
|
1440
|
+
super(context, stepName);
|
|
1401
1441
|
this.sleep = sleep;
|
|
1402
1442
|
}
|
|
1403
1443
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -1426,9 +1466,6 @@ var LazySleepStep = class extends BaseLazyStep {
|
|
|
1426
1466
|
headers,
|
|
1427
1467
|
method: "POST",
|
|
1428
1468
|
url: context.url,
|
|
1429
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1430
|
-
retryDelay: context.retryDelay,
|
|
1431
|
-
flowControl: context.flowControl,
|
|
1432
1469
|
delay: isParallel ? void 0 : this.sleep
|
|
1433
1470
|
}
|
|
1434
1471
|
]);
|
|
@@ -1438,8 +1475,8 @@ var LazySleepUntilStep = class extends BaseLazyStep {
|
|
|
1438
1475
|
sleepUntil;
|
|
1439
1476
|
stepType = "SleepUntil";
|
|
1440
1477
|
allowUndefinedOut = true;
|
|
1441
|
-
constructor(stepName, sleepUntil) {
|
|
1442
|
-
super(stepName);
|
|
1478
|
+
constructor(context, stepName, sleepUntil) {
|
|
1479
|
+
super(context, stepName);
|
|
1443
1480
|
this.sleepUntil = sleepUntil;
|
|
1444
1481
|
}
|
|
1445
1482
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -1471,9 +1508,6 @@ var LazySleepUntilStep = class extends BaseLazyStep {
|
|
|
1471
1508
|
headers,
|
|
1472
1509
|
method: "POST",
|
|
1473
1510
|
url: context.url,
|
|
1474
|
-
retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
|
|
1475
|
-
retryDelay: context.retryDelay,
|
|
1476
|
-
flowControl: context.flowControl,
|
|
1477
1511
|
notBefore: isParallel ? void 0 : this.sleepUntil
|
|
1478
1512
|
}
|
|
1479
1513
|
]);
|
|
@@ -1488,20 +1522,18 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1488
1522
|
retryDelay;
|
|
1489
1523
|
timeout;
|
|
1490
1524
|
flowControl;
|
|
1491
|
-
stringifyBody;
|
|
1492
1525
|
stepType = "Call";
|
|
1493
1526
|
allowUndefinedOut = false;
|
|
1494
|
-
constructor(
|
|
1495
|
-
super(stepName);
|
|
1496
|
-
this.url = url;
|
|
1497
|
-
this.method = method;
|
|
1498
|
-
this.body = body;
|
|
1499
|
-
this.headers = headers;
|
|
1500
|
-
this.retries = retries;
|
|
1501
|
-
this.retryDelay = retryDelay;
|
|
1502
|
-
this.timeout = timeout;
|
|
1503
|
-
this.flowControl = flowControl;
|
|
1504
|
-
this.stringifyBody = stringifyBody;
|
|
1527
|
+
constructor(params) {
|
|
1528
|
+
super(params.context, params.stepName);
|
|
1529
|
+
this.url = params.url;
|
|
1530
|
+
this.method = params.method ?? "GET";
|
|
1531
|
+
this.body = params.body;
|
|
1532
|
+
this.headers = params.headers ?? {};
|
|
1533
|
+
this.retries = params.retries ?? 0;
|
|
1534
|
+
this.retryDelay = params.retryDelay;
|
|
1535
|
+
this.timeout = params.timeout;
|
|
1536
|
+
this.flowControl = params.flowControl;
|
|
1505
1537
|
}
|
|
1506
1538
|
getPlanStep(concurrent, targetStep) {
|
|
1507
1539
|
return {
|
|
@@ -1598,7 +1630,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1598
1630
|
"Upstash-Callback-Workflow-CallType": "fromCallback",
|
|
1599
1631
|
"Upstash-Callback-Workflow-Init": "false",
|
|
1600
1632
|
"Upstash-Callback-Workflow-Url": context.url,
|
|
1601
|
-
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger",
|
|
1633
|
+
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
|
|
1602
1634
|
"Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
|
|
1603
1635
|
"Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
|
|
1604
1636
|
"Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
|
|
@@ -1611,22 +1643,10 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1611
1643
|
};
|
|
1612
1644
|
}
|
|
1613
1645
|
async submitStep({ context, headers }) {
|
|
1614
|
-
let callBody;
|
|
1615
|
-
if (this.stringifyBody) {
|
|
1616
|
-
callBody = JSON.stringify(this.body);
|
|
1617
|
-
} else {
|
|
1618
|
-
if (typeof this.body === "string") {
|
|
1619
|
-
callBody = this.body;
|
|
1620
|
-
} else {
|
|
1621
|
-
throw new WorkflowError(
|
|
1622
|
-
"When stringifyBody is false, body must be a string. Please check the body type of your call step."
|
|
1623
|
-
);
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
1646
|
return await context.qstashClient.batch([
|
|
1627
1647
|
{
|
|
1628
1648
|
headers,
|
|
1629
|
-
body:
|
|
1649
|
+
body: this.body,
|
|
1630
1650
|
method: this.method,
|
|
1631
1651
|
url: this.url,
|
|
1632
1652
|
retries: DEFAULT_RETRIES === this.retries ? void 0 : this.retries,
|
|
@@ -1636,13 +1656,12 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
|
|
|
1636
1656
|
]);
|
|
1637
1657
|
}
|
|
1638
1658
|
};
|
|
1639
|
-
var
|
|
1659
|
+
var LazyWaitEventStep = class extends BaseLazyStep {
|
|
1640
1660
|
eventId;
|
|
1641
1661
|
timeout;
|
|
1642
|
-
stepType = "Wait";
|
|
1643
1662
|
allowUndefinedOut = false;
|
|
1644
|
-
constructor(stepName, eventId, timeout) {
|
|
1645
|
-
super(stepName);
|
|
1663
|
+
constructor(context, stepName, eventId, timeout) {
|
|
1664
|
+
super(context, stepName);
|
|
1646
1665
|
this.eventId = eventId;
|
|
1647
1666
|
this.timeout = timeout;
|
|
1648
1667
|
}
|
|
@@ -1667,13 +1686,6 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1667
1686
|
concurrent
|
|
1668
1687
|
});
|
|
1669
1688
|
}
|
|
1670
|
-
safeParseOut(out) {
|
|
1671
|
-
const result = JSON.parse(out);
|
|
1672
|
-
return {
|
|
1673
|
-
...result,
|
|
1674
|
-
eventData: BaseLazyStep.tryParsing(result.eventData)
|
|
1675
|
-
};
|
|
1676
|
-
}
|
|
1677
1689
|
getHeaders({ context, telemetry: telemetry2, invokeCount, step }) {
|
|
1678
1690
|
const headers = super.getHeaders({ context, telemetry: telemetry2, invokeCount, step });
|
|
1679
1691
|
headers.headers["Upstash-Workflow-CallType"] = "step";
|
|
@@ -1707,7 +1719,7 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1707
1719
|
timeoutHeaders,
|
|
1708
1720
|
step: {
|
|
1709
1721
|
stepId: step.stepId,
|
|
1710
|
-
stepType:
|
|
1722
|
+
stepType: this.stepType,
|
|
1711
1723
|
stepName: step.stepName,
|
|
1712
1724
|
concurrent: step.concurrent,
|
|
1713
1725
|
targetStep: step.targetStep
|
|
@@ -1728,8 +1740,8 @@ var LazyWaitForEventStep = class extends BaseLazyStep {
|
|
|
1728
1740
|
};
|
|
1729
1741
|
var LazyNotifyStep = class extends LazyFunctionStep {
|
|
1730
1742
|
stepType = "Notify";
|
|
1731
|
-
constructor(stepName, eventId, eventData, requester) {
|
|
1732
|
-
super(stepName, async () => {
|
|
1743
|
+
constructor(context, stepName, eventId, eventData, requester) {
|
|
1744
|
+
super(context, stepName, async () => {
|
|
1733
1745
|
const notifyResponse = await makeNotifyRequest(requester, eventId, eventData);
|
|
1734
1746
|
return {
|
|
1735
1747
|
eventId,
|
|
@@ -1754,28 +1766,10 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1754
1766
|
* workflow id of the invoked workflow
|
|
1755
1767
|
*/
|
|
1756
1768
|
workflowId;
|
|
1757
|
-
constructor(stepName, {
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
workflowRunId,
|
|
1762
|
-
retries,
|
|
1763
|
-
retryDelay,
|
|
1764
|
-
flowControl,
|
|
1765
|
-
stringifyBody = true
|
|
1766
|
-
}) {
|
|
1767
|
-
super(stepName);
|
|
1768
|
-
this.params = {
|
|
1769
|
-
workflow,
|
|
1770
|
-
body,
|
|
1771
|
-
headers,
|
|
1772
|
-
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
1773
|
-
retries,
|
|
1774
|
-
retryDelay,
|
|
1775
|
-
flowControl,
|
|
1776
|
-
stringifyBody
|
|
1777
|
-
};
|
|
1778
|
-
const { workflowId } = workflow;
|
|
1769
|
+
constructor(context, stepName, params) {
|
|
1770
|
+
super(context, stepName);
|
|
1771
|
+
this.params = params;
|
|
1772
|
+
const { workflowId } = params.workflow;
|
|
1779
1773
|
if (!workflowId) {
|
|
1780
1774
|
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1781
1775
|
}
|
|
@@ -1815,31 +1809,18 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1815
1809
|
workflowConfig: {
|
|
1816
1810
|
workflowRunId: context.workflowRunId,
|
|
1817
1811
|
workflowUrl: context.url,
|
|
1818
|
-
failureUrl: context.failureUrl,
|
|
1819
|
-
retries: context.retries,
|
|
1820
|
-
retryDelay: context.retryDelay,
|
|
1821
1812
|
telemetry: telemetry2,
|
|
1822
|
-
flowControl: context.flowControl,
|
|
1823
1813
|
useJSONContent: false
|
|
1824
1814
|
},
|
|
1825
1815
|
userHeaders: context.headers,
|
|
1826
1816
|
invokeCount
|
|
1827
1817
|
});
|
|
1818
|
+
context.qstashClient.http.headers?.forEach((value, key) => {
|
|
1819
|
+
invokerHeaders[key] = value;
|
|
1820
|
+
});
|
|
1828
1821
|
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1829
|
-
let invokeBody;
|
|
1830
|
-
if (this.params.stringifyBody) {
|
|
1831
|
-
invokeBody = JSON.stringify(this.params.body);
|
|
1832
|
-
} else {
|
|
1833
|
-
if (typeof this.params.body === "string") {
|
|
1834
|
-
invokeBody = this.params.body;
|
|
1835
|
-
} else {
|
|
1836
|
-
throw new WorkflowError(
|
|
1837
|
-
"When stringifyBody is false, body must be a string. Please check the body type of your invoke step."
|
|
1838
|
-
);
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
1822
|
const request = {
|
|
1842
|
-
body:
|
|
1823
|
+
body: stringifyBody(this.params.body),
|
|
1843
1824
|
headers: Object.fromEntries(
|
|
1844
1825
|
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1845
1826
|
),
|
|
@@ -1850,34 +1831,19 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1850
1831
|
return JSON.stringify(request);
|
|
1851
1832
|
}
|
|
1852
1833
|
getHeaders({ context, telemetry: telemetry2, invokeCount }) {
|
|
1853
|
-
const {
|
|
1854
|
-
workflow,
|
|
1855
|
-
headers = {},
|
|
1856
|
-
workflowRunId = getWorkflowRunId(),
|
|
1857
|
-
retries,
|
|
1858
|
-
retryDelay,
|
|
1859
|
-
flowControl
|
|
1860
|
-
} = this.params;
|
|
1834
|
+
const { workflow, headers = {}, workflowRunId, retries, retryDelay, flowControl } = this.params;
|
|
1861
1835
|
const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
|
|
1862
|
-
const {
|
|
1863
|
-
retries: workflowRetries,
|
|
1864
|
-
retryDelay: workflowRetryDelay,
|
|
1865
|
-
failureFunction,
|
|
1866
|
-
failureUrl,
|
|
1867
|
-
useJSONContent,
|
|
1868
|
-
flowControl: workflowFlowControl
|
|
1869
|
-
} = workflow.options;
|
|
1870
1836
|
const { headers: triggerHeaders, contentType } = getHeaders({
|
|
1871
1837
|
initHeaderValue: "true",
|
|
1872
1838
|
workflowConfig: {
|
|
1873
|
-
workflowRunId,
|
|
1839
|
+
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
1874
1840
|
workflowUrl: newUrl,
|
|
1875
|
-
retries
|
|
1876
|
-
retryDelay
|
|
1841
|
+
retries,
|
|
1842
|
+
retryDelay,
|
|
1877
1843
|
telemetry: telemetry2,
|
|
1878
|
-
failureUrl:
|
|
1879
|
-
flowControl
|
|
1880
|
-
useJSONContent: useJSONContent ?? false
|
|
1844
|
+
failureUrl: newUrl,
|
|
1845
|
+
flowControl,
|
|
1846
|
+
useJSONContent: workflow.useJSONContent ?? false
|
|
1881
1847
|
},
|
|
1882
1848
|
invokeCount: invokeCount + 1,
|
|
1883
1849
|
userHeaders: new Headers(headers)
|
|
@@ -1896,6 +1862,88 @@ var LazyInvokeStep = class extends BaseLazyStep {
|
|
|
1896
1862
|
return [result];
|
|
1897
1863
|
}
|
|
1898
1864
|
};
|
|
1865
|
+
var LazyCreateWebhookStep = class extends BaseLazyStep {
|
|
1866
|
+
stepType = "CreateWebhook";
|
|
1867
|
+
allowUndefinedOut = false;
|
|
1868
|
+
getPlanStep(concurrent, targetStep) {
|
|
1869
|
+
return {
|
|
1870
|
+
stepId: 0,
|
|
1871
|
+
stepName: this.stepName,
|
|
1872
|
+
stepType: this.stepType,
|
|
1873
|
+
concurrent,
|
|
1874
|
+
targetStep
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
async getResultStep(concurrent, stepId) {
|
|
1878
|
+
return {
|
|
1879
|
+
stepId,
|
|
1880
|
+
stepName: this.stepName,
|
|
1881
|
+
stepType: this.stepType,
|
|
1882
|
+
out: void 0,
|
|
1883
|
+
concurrent
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
getBody({ step, context }) {
|
|
1887
|
+
const userId = getUserIdFromToken(context.qstashClient);
|
|
1888
|
+
const workflowRunId = context.workflowRunId;
|
|
1889
|
+
const eventId = getEventId();
|
|
1890
|
+
const qstashUrl = getQStashUrl(this.context.qstashClient);
|
|
1891
|
+
return JSON.stringify({
|
|
1892
|
+
...step,
|
|
1893
|
+
out: JSON.stringify({
|
|
1894
|
+
webhookUrl: `${qstashUrl}/v2/workflows/hooks/${userId}/${workflowRunId}/${eventId}`,
|
|
1895
|
+
eventId
|
|
1896
|
+
})
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
var LazyWaitForWebhookStep = class extends LazyWaitEventStep {
|
|
1901
|
+
stepType = "WaitForWebhook";
|
|
1902
|
+
allowUndefinedOut = true;
|
|
1903
|
+
constructor(context, stepName, webhook, timeout) {
|
|
1904
|
+
super(context, stepName, webhook.eventId, timeout);
|
|
1905
|
+
}
|
|
1906
|
+
safeParseOut(out) {
|
|
1907
|
+
const eventData = decodeBase64(out);
|
|
1908
|
+
const parsedEventData = BaseLazyStep.tryParsing(eventData);
|
|
1909
|
+
const body = parsedEventData.body;
|
|
1910
|
+
const parsedBody = typeof body === "string" ? decodeBase64(body) : void 0;
|
|
1911
|
+
const request = new Request(
|
|
1912
|
+
`${parsedEventData.proto}://${parsedEventData.host}${parsedEventData.url}`,
|
|
1913
|
+
{
|
|
1914
|
+
method: parsedEventData.method,
|
|
1915
|
+
headers: parsedEventData.header,
|
|
1916
|
+
body: parsedBody
|
|
1917
|
+
}
|
|
1918
|
+
);
|
|
1919
|
+
return {
|
|
1920
|
+
request,
|
|
1921
|
+
timeout: false
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
handleUndefinedOut() {
|
|
1925
|
+
return {
|
|
1926
|
+
timeout: true,
|
|
1927
|
+
request: void 0
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
var LazyWaitForEventStep = class extends LazyWaitEventStep {
|
|
1932
|
+
stepType = "Wait";
|
|
1933
|
+
allowUndefinedOut = true;
|
|
1934
|
+
parseWaitForEventOut(out, waitTimeout) {
|
|
1935
|
+
return {
|
|
1936
|
+
eventData: out ? BaseLazyStep.tryParsing(decodeBase64(out)) : void 0,
|
|
1937
|
+
timeout: waitTimeout ?? false
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
safeParseOut(out, step) {
|
|
1941
|
+
return this.parseWaitForEventOut(out, step.waitTimeout);
|
|
1942
|
+
}
|
|
1943
|
+
handleUndefinedOut(step) {
|
|
1944
|
+
return this.parseWaitForEventOut(void 0, step.waitTimeout);
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1899
1947
|
|
|
1900
1948
|
// src/qstash/headers.ts
|
|
1901
1949
|
var WorkflowHeaders = class {
|
|
@@ -1905,14 +1953,15 @@ var WorkflowHeaders = class {
|
|
|
1905
1953
|
initHeaderValue;
|
|
1906
1954
|
stepInfo;
|
|
1907
1955
|
headers;
|
|
1908
|
-
|
|
1956
|
+
/**
|
|
1957
|
+
* @param params workflow header parameters
|
|
1958
|
+
*/
|
|
1909
1959
|
constructor({
|
|
1910
1960
|
userHeaders,
|
|
1911
1961
|
workflowConfig,
|
|
1912
1962
|
invokeCount,
|
|
1913
1963
|
initHeaderValue,
|
|
1914
|
-
stepInfo
|
|
1915
|
-
keepTriggerConfig
|
|
1964
|
+
stepInfo
|
|
1916
1965
|
}) {
|
|
1917
1966
|
this.userHeaders = userHeaders;
|
|
1918
1967
|
this.workflowConfig = workflowConfig;
|
|
@@ -1924,7 +1973,6 @@ var WorkflowHeaders = class {
|
|
|
1924
1973
|
workflowHeaders: {},
|
|
1925
1974
|
failureHeaders: {}
|
|
1926
1975
|
};
|
|
1927
|
-
this.keepTriggerConfig = keepTriggerConfig;
|
|
1928
1976
|
}
|
|
1929
1977
|
getHeaders() {
|
|
1930
1978
|
this.addBaseHeaders();
|
|
@@ -1943,7 +1991,7 @@ var WorkflowHeaders = class {
|
|
|
1943
1991
|
[WORKFLOW_INIT_HEADER]: this.initHeaderValue,
|
|
1944
1992
|
[WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
|
|
1945
1993
|
[WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
|
|
1946
|
-
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger
|
|
1994
|
+
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
|
|
1947
1995
|
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
1948
1996
|
...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
|
|
1949
1997
|
};
|
|
@@ -2013,12 +2061,12 @@ var WorkflowHeaders = class {
|
|
|
2013
2061
|
}
|
|
2014
2062
|
this.headers.workflowHeaders["Failure-Callback"] = this.workflowConfig.failureUrl;
|
|
2015
2063
|
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
2016
|
-
this.headers.failureHeaders[`Forward
|
|
2064
|
+
this.headers.failureHeaders[`Forward-${WORKFLOW_FAILURE_CALLBACK_HEADER}`] = "true";
|
|
2017
2065
|
this.headers.failureHeaders["Workflow-Runid"] = this.workflowConfig.workflowRunId;
|
|
2018
2066
|
this.headers.failureHeaders["Workflow-Init"] = "false";
|
|
2019
2067
|
this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
|
|
2020
2068
|
this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
|
|
2021
|
-
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger";
|
|
2069
|
+
this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
|
|
2022
2070
|
if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
|
|
2023
2071
|
this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
|
|
2024
2072
|
}
|
|
@@ -2088,14 +2136,13 @@ var submitParallelSteps = async ({
|
|
|
2088
2136
|
initialStepCount,
|
|
2089
2137
|
invokeCount,
|
|
2090
2138
|
telemetry: telemetry2,
|
|
2091
|
-
|
|
2139
|
+
dispatchDebug
|
|
2092
2140
|
}) => {
|
|
2093
2141
|
const planSteps = steps.map(
|
|
2094
2142
|
(step, index) => step.getPlanStep(steps.length, initialStepCount + index)
|
|
2095
2143
|
);
|
|
2096
|
-
await
|
|
2097
|
-
|
|
2098
|
-
steps: planSteps
|
|
2144
|
+
await dispatchDebug("onInfo", {
|
|
2145
|
+
info: `Submitting ${planSteps.length} parallel steps.`
|
|
2099
2146
|
});
|
|
2100
2147
|
const result = await context.qstashClient.batch(
|
|
2101
2148
|
planSteps.map((planStep) => {
|
|
@@ -2104,10 +2151,6 @@ var submitParallelSteps = async ({
|
|
|
2104
2151
|
workflowConfig: {
|
|
2105
2152
|
workflowRunId: context.workflowRunId,
|
|
2106
2153
|
workflowUrl: context.url,
|
|
2107
|
-
failureUrl: context.failureUrl,
|
|
2108
|
-
retries: context.retries,
|
|
2109
|
-
retryDelay: context.retryDelay,
|
|
2110
|
-
flowControl: context.flowControl,
|
|
2111
2154
|
telemetry: telemetry2
|
|
2112
2155
|
},
|
|
2113
2156
|
userHeaders: context.headers,
|
|
@@ -2123,13 +2166,11 @@ var submitParallelSteps = async ({
|
|
|
2123
2166
|
};
|
|
2124
2167
|
})
|
|
2125
2168
|
);
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
})
|
|
2132
|
-
});
|
|
2169
|
+
if (result && result.length > 0) {
|
|
2170
|
+
await dispatchDebug("onInfo", {
|
|
2171
|
+
info: `Submitted ${planSteps.length} parallel steps. messageIds: ${result.filter((r) => r).map((r) => r.messageId).join(", ")}.`
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2133
2174
|
throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
|
|
2134
2175
|
};
|
|
2135
2176
|
var submitSingleStep = async ({
|
|
@@ -2139,14 +2180,13 @@ var submitSingleStep = async ({
|
|
|
2139
2180
|
invokeCount,
|
|
2140
2181
|
concurrency,
|
|
2141
2182
|
telemetry: telemetry2,
|
|
2142
|
-
|
|
2183
|
+
dispatchDebug,
|
|
2184
|
+
dispatchLifecycle
|
|
2143
2185
|
}) => {
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
fromRequest: false,
|
|
2147
|
-
step: resultStep,
|
|
2148
|
-
stepCount: stepId
|
|
2186
|
+
await dispatchLifecycle("beforeExecution", {
|
|
2187
|
+
stepName: lazyStep.stepName
|
|
2149
2188
|
});
|
|
2189
|
+
const resultStep = await lazyStep.getResultStep(concurrency, stepId);
|
|
2150
2190
|
const { headers } = lazyStep.getHeaders({
|
|
2151
2191
|
context,
|
|
2152
2192
|
step: resultStep,
|
|
@@ -2160,10 +2200,6 @@ var submitSingleStep = async ({
|
|
|
2160
2200
|
invokeCount,
|
|
2161
2201
|
telemetry: telemetry2
|
|
2162
2202
|
});
|
|
2163
|
-
await debug?.log("SUBMIT", "SUBMIT_STEP", {
|
|
2164
|
-
length: 1,
|
|
2165
|
-
steps: [resultStep]
|
|
2166
|
-
});
|
|
2167
2203
|
const submitResult = await lazyStep.submitStep({
|
|
2168
2204
|
context,
|
|
2169
2205
|
body,
|
|
@@ -2173,13 +2209,11 @@ var submitSingleStep = async ({
|
|
|
2173
2209
|
step: resultStep,
|
|
2174
2210
|
telemetry: telemetry2
|
|
2175
2211
|
});
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
})
|
|
2182
|
-
});
|
|
2212
|
+
if (submitResult && submitResult[0]) {
|
|
2213
|
+
await dispatchDebug("onInfo", {
|
|
2214
|
+
info: `Submitted step "${resultStep.stepName}" with messageId: ${submitResult[0].messageId}.`
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2183
2217
|
return resultStep;
|
|
2184
2218
|
};
|
|
2185
2219
|
|
|
@@ -2188,21 +2222,31 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2188
2222
|
context;
|
|
2189
2223
|
promises = /* @__PURE__ */ new WeakMap();
|
|
2190
2224
|
activeLazyStepList;
|
|
2191
|
-
debug;
|
|
2192
2225
|
nonPlanStepCount;
|
|
2193
2226
|
steps;
|
|
2194
2227
|
indexInCurrentList = 0;
|
|
2195
2228
|
invokeCount;
|
|
2196
2229
|
telemetry;
|
|
2230
|
+
dispatchDebug;
|
|
2231
|
+
dispatchLifecycle;
|
|
2197
2232
|
stepCount = 0;
|
|
2198
2233
|
planStepCount = 0;
|
|
2199
2234
|
executingStep = false;
|
|
2200
|
-
|
|
2235
|
+
/**
|
|
2236
|
+
* @param context workflow context
|
|
2237
|
+
* @param steps list of steps
|
|
2238
|
+
* @param dispatchDebug debug event dispatcher
|
|
2239
|
+
* @param dispatchLifecycle lifecycle event dispatcher
|
|
2240
|
+
* @param telemetry optional telemetry information
|
|
2241
|
+
* @param invokeCount optional invoke count
|
|
2242
|
+
*/
|
|
2243
|
+
constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry2, invokeCount) {
|
|
2201
2244
|
this.context = context;
|
|
2202
2245
|
this.steps = steps;
|
|
2246
|
+
this.dispatchDebug = dispatchDebug;
|
|
2247
|
+
this.dispatchLifecycle = dispatchLifecycle;
|
|
2203
2248
|
this.telemetry = telemetry2;
|
|
2204
2249
|
this.invokeCount = invokeCount ?? 0;
|
|
2205
|
-
this.debug = debug;
|
|
2206
2250
|
this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
|
|
2207
2251
|
}
|
|
2208
2252
|
/**
|
|
@@ -2270,7 +2314,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2270
2314
|
/**
|
|
2271
2315
|
* Executes a step:
|
|
2272
2316
|
* - If the step result is available in the steps, returns the result
|
|
2273
|
-
* - If the result is not
|
|
2317
|
+
* - If the result is not available, runs the function
|
|
2274
2318
|
* - Sends the result to QStash
|
|
2275
2319
|
*
|
|
2276
2320
|
* @param lazyStep lazy step to execute
|
|
@@ -2280,12 +2324,15 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2280
2324
|
if (this.stepCount < this.nonPlanStepCount) {
|
|
2281
2325
|
const step = this.steps[this.stepCount + this.planStepCount];
|
|
2282
2326
|
validateStep(lazyStep, step);
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2327
|
+
const parsedOut = lazyStep.parseOut(step);
|
|
2328
|
+
const isLastMemoized = this.stepCount + 1 === this.nonPlanStepCount && this.steps.at(-1).stepId !== 0;
|
|
2329
|
+
if (isLastMemoized) {
|
|
2330
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2331
|
+
stepName: lazyStep.stepName,
|
|
2332
|
+
result: parsedOut
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
return parsedOut;
|
|
2289
2336
|
}
|
|
2290
2337
|
const resultStep = await submitSingleStep({
|
|
2291
2338
|
context: this.context,
|
|
@@ -2294,15 +2341,15 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2294
2341
|
invokeCount: this.invokeCount,
|
|
2295
2342
|
concurrency: 1,
|
|
2296
2343
|
telemetry: this.telemetry,
|
|
2297
|
-
|
|
2344
|
+
dispatchDebug: this.dispatchDebug,
|
|
2345
|
+
dispatchLifecycle: this.dispatchLifecycle
|
|
2298
2346
|
});
|
|
2299
2347
|
throw new WorkflowAbort(lazyStep.stepName, resultStep);
|
|
2300
2348
|
}
|
|
2301
2349
|
/**
|
|
2302
2350
|
* Runs steps in parallel.
|
|
2303
2351
|
*
|
|
2304
|
-
* @param
|
|
2305
|
-
* @param stepFunctions list of async functions to run in parallel
|
|
2352
|
+
* @param parallelSteps list of lazy steps to run in parallel
|
|
2306
2353
|
* @returns results of the functions run in parallel
|
|
2307
2354
|
*/
|
|
2308
2355
|
async runParallel(parallelSteps) {
|
|
@@ -2315,12 +2362,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2315
2362
|
`Incompatible number of parallel steps when call state was '${parallelCallState}'. Expected ${parallelSteps.length}, got ${plannedParallelStepCount} from the request.`
|
|
2316
2363
|
);
|
|
2317
2364
|
}
|
|
2318
|
-
await this.
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2365
|
+
await this.dispatchDebug("onInfo", {
|
|
2366
|
+
info: `Executing parallel steps with: ` + JSON.stringify({
|
|
2367
|
+
parallelCallState,
|
|
2368
|
+
initialStepCount,
|
|
2369
|
+
plannedParallelStepCount,
|
|
2370
|
+
stepCount: this.stepCount,
|
|
2371
|
+
planStepCount: this.planStepCount
|
|
2372
|
+
})
|
|
2324
2373
|
});
|
|
2325
2374
|
switch (parallelCallState) {
|
|
2326
2375
|
case "first": {
|
|
@@ -2330,7 +2379,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2330
2379
|
initialStepCount,
|
|
2331
2380
|
invokeCount: this.invokeCount,
|
|
2332
2381
|
telemetry: this.telemetry,
|
|
2333
|
-
|
|
2382
|
+
dispatchDebug: this.dispatchDebug
|
|
2334
2383
|
});
|
|
2335
2384
|
break;
|
|
2336
2385
|
}
|
|
@@ -2352,7 +2401,8 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2352
2401
|
invokeCount: this.invokeCount,
|
|
2353
2402
|
concurrency: parallelSteps.length,
|
|
2354
2403
|
telemetry: this.telemetry,
|
|
2355
|
-
|
|
2404
|
+
dispatchDebug: this.dispatchDebug,
|
|
2405
|
+
dispatchLifecycle: this.dispatchLifecycle
|
|
2356
2406
|
});
|
|
2357
2407
|
throw new WorkflowAbort(parallelStep.stepName, resultStep);
|
|
2358
2408
|
} catch (error) {
|
|
@@ -2366,13 +2416,34 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2366
2416
|
break;
|
|
2367
2417
|
}
|
|
2368
2418
|
case "discard": {
|
|
2419
|
+
const resultStep = this.steps.at(-1);
|
|
2420
|
+
const lazyStep = parallelSteps.find(
|
|
2421
|
+
(planStep, index) => resultStep.stepId - index === initialStepCount
|
|
2422
|
+
);
|
|
2423
|
+
if (lazyStep) {
|
|
2424
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2425
|
+
stepName: lazyStep.stepName,
|
|
2426
|
+
result: lazyStep.parseOut(resultStep)
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2369
2429
|
throw new WorkflowAbort("discarded parallel");
|
|
2370
2430
|
}
|
|
2371
2431
|
case "last": {
|
|
2372
2432
|
const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
|
|
2373
2433
|
validateParallelSteps(parallelSteps, parallelResultSteps);
|
|
2434
|
+
const isLastMemoized = this.stepCount + 1 === this.nonPlanStepCount && this.steps.at(-1).stepId !== 0;
|
|
2435
|
+
if (isLastMemoized) {
|
|
2436
|
+
const resultStep = this.steps.at(-1);
|
|
2437
|
+
const lazyStep = parallelSteps.find(
|
|
2438
|
+
(planStep, index) => resultStep.stepId - index === initialStepCount
|
|
2439
|
+
);
|
|
2440
|
+
await this.dispatchLifecycle("afterExecution", {
|
|
2441
|
+
stepName: lazyStep.stepName,
|
|
2442
|
+
result: lazyStep.parseOut(resultStep)
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2374
2445
|
return parallelResultSteps.map(
|
|
2375
|
-
(step, index) => parallelSteps[index].parseOut(step
|
|
2446
|
+
(step, index) => parallelSteps[index].parseOut(step)
|
|
2376
2447
|
);
|
|
2377
2448
|
}
|
|
2378
2449
|
}
|
|
@@ -2428,7 +2499,6 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
2428
2499
|
* @param index index of the current step
|
|
2429
2500
|
* @returns result[index] if lazyStepList > 1, otherwise result
|
|
2430
2501
|
*/
|
|
2431
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
2432
2502
|
static getResult(lazyStepList, result, index) {
|
|
2433
2503
|
if (lazyStepList.length === 1) {
|
|
2434
2504
|
return result;
|
|
@@ -2515,15 +2585,18 @@ var getProviderInfo = (api) => {
|
|
|
2515
2585
|
// src/context/api/base.ts
|
|
2516
2586
|
var BaseWorkflowApi = class {
|
|
2517
2587
|
context;
|
|
2588
|
+
/**
|
|
2589
|
+
* @param context workflow context
|
|
2590
|
+
*/
|
|
2518
2591
|
constructor({ context }) {
|
|
2519
2592
|
this.context = context;
|
|
2520
2593
|
}
|
|
2521
2594
|
/**
|
|
2522
2595
|
* context.call which uses a QStash API
|
|
2523
2596
|
*
|
|
2524
|
-
* @param stepName
|
|
2525
|
-
* @param settings
|
|
2526
|
-
* @returns
|
|
2597
|
+
* @param stepName name of the step
|
|
2598
|
+
* @param settings call settings including api configuration
|
|
2599
|
+
* @returns call response
|
|
2527
2600
|
*/
|
|
2528
2601
|
async callApi(stepName, settings) {
|
|
2529
2602
|
const { url, appendHeaders, method } = getProviderInfo(settings.api);
|
|
@@ -2531,7 +2604,7 @@ var BaseWorkflowApi = class {
|
|
|
2531
2604
|
return await this.context.call(stepName, {
|
|
2532
2605
|
url,
|
|
2533
2606
|
method: userMethod ?? method,
|
|
2534
|
-
body,
|
|
2607
|
+
body: typeof body === "string" ? body : JSON.stringify(body),
|
|
2535
2608
|
headers: {
|
|
2536
2609
|
...appendHeaders,
|
|
2537
2610
|
...headers
|
|
@@ -2683,6 +2756,129 @@ var getNewUrlFromWorkflowId = (url, workflowId) => {
|
|
|
2683
2756
|
return url.replace(/[^/]+$/, workflowId);
|
|
2684
2757
|
};
|
|
2685
2758
|
|
|
2759
|
+
// src/middleware/default-callbacks.ts
|
|
2760
|
+
var onErrorWithConsole = async ({ workflowRunId, error }) => {
|
|
2761
|
+
console.error(` [Upstash Workflow]: Error in workflow run ${workflowRunId}: ` + error);
|
|
2762
|
+
};
|
|
2763
|
+
var onWarningWithConsole = async ({ workflowRunId, warning }) => {
|
|
2764
|
+
console.warn(` [Upstash Workflow]: Warning in workflow run ${workflowRunId}: ` + warning);
|
|
2765
|
+
};
|
|
2766
|
+
var onInfoWithConsole = async ({
|
|
2767
|
+
workflowRunId,
|
|
2768
|
+
info
|
|
2769
|
+
}) => {
|
|
2770
|
+
console.info(` [Upstash Workflow]: Info in workflow run ${workflowRunId}: ` + info);
|
|
2771
|
+
};
|
|
2772
|
+
|
|
2773
|
+
// src/middleware/manager.ts
|
|
2774
|
+
var MiddlewareManager = class {
|
|
2775
|
+
middlewares;
|
|
2776
|
+
workflowRunId;
|
|
2777
|
+
context;
|
|
2778
|
+
/**
|
|
2779
|
+
* @param middlewares list of workflow middlewares
|
|
2780
|
+
*/
|
|
2781
|
+
constructor(middlewares = []) {
|
|
2782
|
+
this.middlewares = middlewares;
|
|
2783
|
+
}
|
|
2784
|
+
/**
|
|
2785
|
+
* Assign workflow run ID - will be passed to debug events
|
|
2786
|
+
*
|
|
2787
|
+
* @param workflowRunId workflow run id to assign
|
|
2788
|
+
*/
|
|
2789
|
+
assignWorkflowRunId(workflowRunId) {
|
|
2790
|
+
this.workflowRunId = workflowRunId;
|
|
2791
|
+
}
|
|
2792
|
+
/**
|
|
2793
|
+
* Assign context - required for lifecycle events
|
|
2794
|
+
*
|
|
2795
|
+
* also assigns workflowRunId from context
|
|
2796
|
+
*
|
|
2797
|
+
* @param context workflow context to assign
|
|
2798
|
+
*/
|
|
2799
|
+
assignContext(context) {
|
|
2800
|
+
this.context = context;
|
|
2801
|
+
this.workflowRunId = context.workflowRunId;
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Internal method to execute middlewares with common error handling logic
|
|
2805
|
+
*
|
|
2806
|
+
* @param event event name to dispatch
|
|
2807
|
+
* @param params event parameters
|
|
2808
|
+
*/
|
|
2809
|
+
async executeMiddlewares(event, params) {
|
|
2810
|
+
await Promise.all(this.middlewares.map((m) => m.ensureInit()));
|
|
2811
|
+
await Promise.all(
|
|
2812
|
+
this.middlewares.map(async (middleware) => {
|
|
2813
|
+
const callback = middleware.getCallback(event);
|
|
2814
|
+
if (callback) {
|
|
2815
|
+
try {
|
|
2816
|
+
await callback(params);
|
|
2817
|
+
} catch (error) {
|
|
2818
|
+
try {
|
|
2819
|
+
const onErrorCallback = middleware.getCallback("onError") ?? onErrorWithConsole;
|
|
2820
|
+
await onErrorCallback({
|
|
2821
|
+
workflowRunId: this.workflowRunId,
|
|
2822
|
+
error
|
|
2823
|
+
});
|
|
2824
|
+
} catch (onErrorError) {
|
|
2825
|
+
console.error(
|
|
2826
|
+
`Failed while executing "onError" of middleware "${middleware.name}", falling back to logging the error to console. Error: ${onErrorError}`
|
|
2827
|
+
);
|
|
2828
|
+
onErrorWithConsole({
|
|
2829
|
+
workflowRunId: this.workflowRunId,
|
|
2830
|
+
error
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
})
|
|
2836
|
+
);
|
|
2837
|
+
if (event === "onError") {
|
|
2838
|
+
onErrorWithConsole({
|
|
2839
|
+
workflowRunId: this.workflowRunId,
|
|
2840
|
+
...params
|
|
2841
|
+
});
|
|
2842
|
+
} else if (event === "onWarning") {
|
|
2843
|
+
onWarningWithConsole({
|
|
2844
|
+
workflowRunId: this.workflowRunId,
|
|
2845
|
+
...params
|
|
2846
|
+
});
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Dispatch a debug event (onError, onWarning, onInfo)
|
|
2851
|
+
*
|
|
2852
|
+
* @param event debug event name
|
|
2853
|
+
* @param params event parameters
|
|
2854
|
+
*/
|
|
2855
|
+
async dispatchDebug(event, params) {
|
|
2856
|
+
const paramsWithRunId = {
|
|
2857
|
+
...params,
|
|
2858
|
+
workflowRunId: this.workflowRunId
|
|
2859
|
+
};
|
|
2860
|
+
await this.executeMiddlewares(event, paramsWithRunId);
|
|
2861
|
+
}
|
|
2862
|
+
/**
|
|
2863
|
+
* Dispatch a lifecycle event (beforeExecution, afterExecution, runStarted, runCompleted)
|
|
2864
|
+
*
|
|
2865
|
+
* @param event lifecycle event name
|
|
2866
|
+
* @param params event parameters
|
|
2867
|
+
*/
|
|
2868
|
+
async dispatchLifecycle(event, params) {
|
|
2869
|
+
if (!this.context) {
|
|
2870
|
+
throw new WorkflowError(
|
|
2871
|
+
`Something went wrong while calling middlewares. Lifecycle event "${event}" was called before assignContext.`
|
|
2872
|
+
);
|
|
2873
|
+
}
|
|
2874
|
+
const paramsWithContext = {
|
|
2875
|
+
...params,
|
|
2876
|
+
context: this.context
|
|
2877
|
+
};
|
|
2878
|
+
await this.executeMiddlewares(event, paramsWithContext);
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
|
|
2686
2882
|
// src/context/context.ts
|
|
2687
2883
|
var WorkflowContext = class {
|
|
2688
2884
|
executor;
|
|
@@ -2728,32 +2924,13 @@ var WorkflowContext = class {
|
|
|
2728
2924
|
*/
|
|
2729
2925
|
url;
|
|
2730
2926
|
/**
|
|
2731
|
-
*
|
|
2732
|
-
*
|
|
2733
|
-
* https://upstash.com/docs/qstash/features/callbacks#what-is-a-failure-callback
|
|
2927
|
+
* Payload of the request which started the workflow.
|
|
2734
2928
|
*
|
|
2735
|
-
*
|
|
2929
|
+
* To specify its type, you can define `serve` as follows:
|
|
2736
2930
|
*
|
|
2737
2931
|
* ```ts
|
|
2738
|
-
*
|
|
2739
|
-
*
|
|
2740
|
-
* ...
|
|
2741
|
-
* },
|
|
2742
|
-
* {
|
|
2743
|
-
* failureUrl: "new-url-value"
|
|
2744
|
-
* }
|
|
2745
|
-
* )
|
|
2746
|
-
* ```
|
|
2747
|
-
*/
|
|
2748
|
-
failureUrl;
|
|
2749
|
-
/**
|
|
2750
|
-
* Payload of the request which started the workflow.
|
|
2751
|
-
*
|
|
2752
|
-
* To specify its type, you can define `serve` as follows:
|
|
2753
|
-
*
|
|
2754
|
-
* ```ts
|
|
2755
|
-
* // set requestPayload type to MyPayload:
|
|
2756
|
-
* export const POST = serve<MyPayload>(
|
|
2932
|
+
* // set requestPayload type to MyPayload:
|
|
2933
|
+
* export const POST = serve<MyPayload>(
|
|
2757
2934
|
* async (context) => {
|
|
2758
2935
|
* ...
|
|
2759
2936
|
* }
|
|
@@ -2801,46 +2978,6 @@ var WorkflowContext = class {
|
|
|
2801
2978
|
* Default value is set to `process.env`.
|
|
2802
2979
|
*/
|
|
2803
2980
|
env;
|
|
2804
|
-
/**
|
|
2805
|
-
* Number of retries
|
|
2806
|
-
*/
|
|
2807
|
-
retries;
|
|
2808
|
-
/**
|
|
2809
|
-
* Delay between retries.
|
|
2810
|
-
*
|
|
2811
|
-
* By default, the `retryDelay` is exponential backoff.
|
|
2812
|
-
* More details can be found in: https://upstash.com/docs/qstash/features/retry.
|
|
2813
|
-
*
|
|
2814
|
-
* The `retryDelay` option allows you to customize the delay (in milliseconds) between retry attempts when message delivery fails.
|
|
2815
|
-
*
|
|
2816
|
-
* You can use mathematical expressions and the following built-in functions to calculate the delay dynamically.
|
|
2817
|
-
* The special variable `retried` represents the current retry attempt count (starting from 0).
|
|
2818
|
-
*
|
|
2819
|
-
* Supported functions:
|
|
2820
|
-
* - `pow`
|
|
2821
|
-
* - `sqrt`
|
|
2822
|
-
* - `abs`
|
|
2823
|
-
* - `exp`
|
|
2824
|
-
* - `floor`
|
|
2825
|
-
* - `ceil`
|
|
2826
|
-
* - `round`
|
|
2827
|
-
* - `min`
|
|
2828
|
-
* - `max`
|
|
2829
|
-
*
|
|
2830
|
-
* Examples of valid `retryDelay` values:
|
|
2831
|
-
* ```ts
|
|
2832
|
-
* 1000 // 1 second
|
|
2833
|
-
* 1000 * (1 + retried) // 1 second multiplied by the current retry attempt
|
|
2834
|
-
* pow(2, retried) // 2 to the power of the current retry attempt
|
|
2835
|
-
* max(10, pow(2, retried)) // The greater of 10 or 2^retried
|
|
2836
|
-
* ```
|
|
2837
|
-
*/
|
|
2838
|
-
retryDelay;
|
|
2839
|
-
/**
|
|
2840
|
-
* Settings for controlling the number of active requests
|
|
2841
|
-
* and number of requests per second with the same key.
|
|
2842
|
-
*/
|
|
2843
|
-
flowControl;
|
|
2844
2981
|
/**
|
|
2845
2982
|
* Label to apply to the workflow run.
|
|
2846
2983
|
*
|
|
@@ -2863,30 +3000,31 @@ var WorkflowContext = class {
|
|
|
2863
3000
|
headers,
|
|
2864
3001
|
steps,
|
|
2865
3002
|
url,
|
|
2866
|
-
failureUrl,
|
|
2867
|
-
debug,
|
|
2868
3003
|
initialPayload,
|
|
2869
3004
|
env,
|
|
2870
|
-
retries,
|
|
2871
|
-
retryDelay,
|
|
2872
3005
|
telemetry: telemetry2,
|
|
2873
3006
|
invokeCount,
|
|
2874
|
-
|
|
2875
|
-
|
|
3007
|
+
label,
|
|
3008
|
+
middlewareManager
|
|
2876
3009
|
}) {
|
|
2877
3010
|
this.qstashClient = qstashClient;
|
|
2878
3011
|
this.workflowRunId = workflowRunId;
|
|
2879
3012
|
this.steps = steps;
|
|
2880
3013
|
this.url = url;
|
|
2881
|
-
this.failureUrl = failureUrl;
|
|
2882
3014
|
this.headers = headers;
|
|
2883
3015
|
this.requestPayload = initialPayload;
|
|
2884
3016
|
this.env = env ?? {};
|
|
2885
|
-
this.retries = retries ?? DEFAULT_RETRIES;
|
|
2886
|
-
this.retryDelay = retryDelay;
|
|
2887
|
-
this.flowControl = flowControl;
|
|
2888
3017
|
this.label = label;
|
|
2889
|
-
|
|
3018
|
+
const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
|
|
3019
|
+
middlewareManagerInstance.assignContext(this);
|
|
3020
|
+
this.executor = new AutoExecutor(
|
|
3021
|
+
this,
|
|
3022
|
+
this.steps,
|
|
3023
|
+
middlewareManagerInstance.dispatchDebug.bind(middlewareManagerInstance),
|
|
3024
|
+
middlewareManagerInstance.dispatchLifecycle.bind(middlewareManagerInstance),
|
|
3025
|
+
telemetry2,
|
|
3026
|
+
invokeCount
|
|
3027
|
+
);
|
|
2890
3028
|
}
|
|
2891
3029
|
/**
|
|
2892
3030
|
* Executes a workflow step
|
|
@@ -2917,7 +3055,7 @@ var WorkflowContext = class {
|
|
|
2917
3055
|
*/
|
|
2918
3056
|
async run(stepName, stepFunction) {
|
|
2919
3057
|
const wrappedStepFunction = (() => this.executor.wrapStep(stepName, stepFunction));
|
|
2920
|
-
return await this.addStep(new LazyFunctionStep(stepName, wrappedStepFunction));
|
|
3058
|
+
return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
|
|
2921
3059
|
}
|
|
2922
3060
|
/**
|
|
2923
3061
|
* Stops the execution for the duration provided.
|
|
@@ -2931,7 +3069,7 @@ var WorkflowContext = class {
|
|
|
2931
3069
|
* @returns undefined
|
|
2932
3070
|
*/
|
|
2933
3071
|
async sleep(stepName, duration) {
|
|
2934
|
-
await this.addStep(new LazySleepStep(stepName, duration));
|
|
3072
|
+
await this.addStep(new LazySleepStep(this, stepName, duration));
|
|
2935
3073
|
}
|
|
2936
3074
|
/**
|
|
2937
3075
|
* Stops the execution until the date time provided.
|
|
@@ -2953,48 +3091,38 @@ var WorkflowContext = class {
|
|
|
2953
3091
|
datetime = typeof datetime === "string" ? new Date(datetime) : datetime;
|
|
2954
3092
|
time = Math.round(datetime.getTime() / 1e3);
|
|
2955
3093
|
}
|
|
2956
|
-
await this.addStep(new LazySleepUntilStep(stepName, time));
|
|
3094
|
+
await this.addStep(new LazySleepUntilStep(this, stepName, time));
|
|
2957
3095
|
}
|
|
2958
3096
|
async call(stepName, settings) {
|
|
2959
3097
|
let callStep;
|
|
2960
3098
|
if ("workflow" in settings) {
|
|
2961
3099
|
const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
|
|
2962
|
-
|
|
3100
|
+
const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
|
|
3101
|
+
callStep = new LazyCallStep({
|
|
3102
|
+
context: this,
|
|
2963
3103
|
stepName,
|
|
2964
3104
|
url,
|
|
2965
|
-
"POST",
|
|
2966
|
-
|
|
2967
|
-
settings.headers || {},
|
|
2968
|
-
settings.retries || 0,
|
|
2969
|
-
settings.retryDelay,
|
|
2970
|
-
settings.timeout,
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
);
|
|
3105
|
+
method: "POST",
|
|
3106
|
+
body: stringBody,
|
|
3107
|
+
headers: settings.headers || {},
|
|
3108
|
+
retries: settings.retries || 0,
|
|
3109
|
+
retryDelay: settings.retryDelay,
|
|
3110
|
+
timeout: settings.timeout,
|
|
3111
|
+
flowControl: settings.flowControl
|
|
3112
|
+
});
|
|
2974
3113
|
} else {
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
method = "GET",
|
|
2978
|
-
body,
|
|
2979
|
-
headers = {},
|
|
2980
|
-
retries = 0,
|
|
2981
|
-
retryDelay,
|
|
2982
|
-
timeout,
|
|
2983
|
-
flowControl,
|
|
2984
|
-
stringifyBody = true
|
|
2985
|
-
} = settings;
|
|
2986
|
-
callStep = new LazyCallStep(
|
|
3114
|
+
callStep = new LazyCallStep({
|
|
3115
|
+
context: this,
|
|
2987
3116
|
stepName,
|
|
2988
|
-
url,
|
|
2989
|
-
method,
|
|
2990
|
-
body,
|
|
2991
|
-
headers,
|
|
2992
|
-
retries,
|
|
2993
|
-
retryDelay,
|
|
2994
|
-
timeout,
|
|
2995
|
-
flowControl
|
|
2996
|
-
|
|
2997
|
-
);
|
|
3117
|
+
url: settings.url,
|
|
3118
|
+
method: settings.method ?? "GET",
|
|
3119
|
+
body: settings.body,
|
|
3120
|
+
headers: settings.headers ?? {},
|
|
3121
|
+
retries: settings.retries ?? 0,
|
|
3122
|
+
retryDelay: settings.retryDelay,
|
|
3123
|
+
timeout: settings.timeout,
|
|
3124
|
+
flowControl: settings.flowControl
|
|
3125
|
+
});
|
|
2998
3126
|
}
|
|
2999
3127
|
return await this.addStep(callStep);
|
|
3000
3128
|
}
|
|
@@ -3035,7 +3163,9 @@ var WorkflowContext = class {
|
|
|
3035
3163
|
async waitForEvent(stepName, eventId, options = {}) {
|
|
3036
3164
|
const { timeout = "7d" } = options;
|
|
3037
3165
|
const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
|
|
3038
|
-
return await this.addStep(
|
|
3166
|
+
return await this.addStep(
|
|
3167
|
+
new LazyWaitForEventStep(this, stepName, eventId, timeoutStr)
|
|
3168
|
+
);
|
|
3039
3169
|
}
|
|
3040
3170
|
/**
|
|
3041
3171
|
* Notify workflow runs waiting for an event
|
|
@@ -3060,20 +3190,28 @@ var WorkflowContext = class {
|
|
|
3060
3190
|
*/
|
|
3061
3191
|
async notify(stepName, eventId, eventData) {
|
|
3062
3192
|
return await this.addStep(
|
|
3063
|
-
new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
|
|
3193
|
+
new LazyNotifyStep(this, stepName, eventId, eventData, this.qstashClient.http)
|
|
3064
3194
|
);
|
|
3065
3195
|
}
|
|
3066
3196
|
async invoke(stepName, settings) {
|
|
3067
|
-
return await this.addStep(
|
|
3197
|
+
return await this.addStep(
|
|
3198
|
+
new LazyInvokeStep(this, stepName, settings)
|
|
3199
|
+
);
|
|
3200
|
+
}
|
|
3201
|
+
async createWebhook(stepName) {
|
|
3202
|
+
return await this.addStep(new LazyCreateWebhookStep(this, stepName));
|
|
3203
|
+
}
|
|
3204
|
+
async waitForWebhook(stepName, webhook, timeout) {
|
|
3205
|
+
return await this.addStep(new LazyWaitForWebhookStep(this, stepName, webhook, timeout));
|
|
3068
3206
|
}
|
|
3069
3207
|
/**
|
|
3070
3208
|
* Cancel the current workflow run
|
|
3071
3209
|
*
|
|
3072
|
-
* Will throw
|
|
3210
|
+
* Will throw WorkflowCancelAbort to stop workflow execution.
|
|
3073
3211
|
* Shouldn't be inside try/catch.
|
|
3074
3212
|
*/
|
|
3075
3213
|
async cancel() {
|
|
3076
|
-
throw new
|
|
3214
|
+
throw new WorkflowCancelAbort();
|
|
3077
3215
|
}
|
|
3078
3216
|
/**
|
|
3079
3217
|
* Adds steps to the executor. Needed so that it can be overwritten in
|
|
@@ -3089,74 +3227,25 @@ var WorkflowContext = class {
|
|
|
3089
3227
|
}
|
|
3090
3228
|
};
|
|
3091
3229
|
|
|
3092
|
-
// src/logger.ts
|
|
3093
|
-
var LOG_LEVELS = ["DEBUG", "INFO", "SUBMIT", "WARN", "ERROR"];
|
|
3094
|
-
var WorkflowLogger = class _WorkflowLogger {
|
|
3095
|
-
logs = [];
|
|
3096
|
-
options;
|
|
3097
|
-
workflowRunId = void 0;
|
|
3098
|
-
constructor(options) {
|
|
3099
|
-
this.options = options;
|
|
3100
|
-
}
|
|
3101
|
-
async log(level, eventType, details) {
|
|
3102
|
-
if (this.shouldLog(level)) {
|
|
3103
|
-
const timestamp = Date.now();
|
|
3104
|
-
const logEntry = {
|
|
3105
|
-
timestamp,
|
|
3106
|
-
workflowRunId: this.workflowRunId ?? "",
|
|
3107
|
-
logLevel: level,
|
|
3108
|
-
eventType,
|
|
3109
|
-
details
|
|
3110
|
-
};
|
|
3111
|
-
this.logs.push(logEntry);
|
|
3112
|
-
if (this.options.logOutput === "console") {
|
|
3113
|
-
this.writeToConsole(logEntry);
|
|
3114
|
-
}
|
|
3115
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3116
|
-
}
|
|
3117
|
-
}
|
|
3118
|
-
setWorkflowRunId(workflowRunId) {
|
|
3119
|
-
this.workflowRunId = workflowRunId;
|
|
3120
|
-
}
|
|
3121
|
-
writeToConsole(logEntry) {
|
|
3122
|
-
const JSON_SPACING = 2;
|
|
3123
|
-
const logMethod = logEntry.logLevel === "ERROR" ? console.error : logEntry.logLevel === "WARN" ? console.warn : console.log;
|
|
3124
|
-
logMethod(JSON.stringify(logEntry, void 0, JSON_SPACING));
|
|
3125
|
-
}
|
|
3126
|
-
shouldLog(level) {
|
|
3127
|
-
return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.options.logLevel);
|
|
3128
|
-
}
|
|
3129
|
-
static getLogger(verbose) {
|
|
3130
|
-
if (typeof verbose === "object") {
|
|
3131
|
-
return verbose;
|
|
3132
|
-
} else {
|
|
3133
|
-
return verbose ? new _WorkflowLogger({
|
|
3134
|
-
logLevel: "INFO",
|
|
3135
|
-
logOutput: "console"
|
|
3136
|
-
}) : void 0;
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
};
|
|
3140
|
-
|
|
3141
3230
|
// src/serve/authorization.ts
|
|
3142
3231
|
var import_qstash9 = require("@upstash/qstash");
|
|
3143
3232
|
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
3144
3233
|
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
3145
3234
|
disabled = true;
|
|
3146
3235
|
/**
|
|
3147
|
-
* overwrite the WorkflowContext.addStep method to always raise
|
|
3236
|
+
* overwrite the WorkflowContext.addStep method to always raise WorkflowAuthError
|
|
3148
3237
|
* error in order to stop the execution whenever we encounter a step.
|
|
3149
3238
|
*
|
|
3150
3239
|
* @param _step
|
|
3151
3240
|
*/
|
|
3152
3241
|
async addStep(_step) {
|
|
3153
|
-
throw new
|
|
3242
|
+
throw new WorkflowAuthError(_DisabledWorkflowContext.disabledMessage);
|
|
3154
3243
|
}
|
|
3155
3244
|
/**
|
|
3156
|
-
* overwrite cancel method to throw
|
|
3245
|
+
* overwrite cancel method to throw WorkflowAuthError with the disabledMessage
|
|
3157
3246
|
*/
|
|
3158
3247
|
async cancel() {
|
|
3159
|
-
throw new
|
|
3248
|
+
throw new WorkflowAuthError(_DisabledWorkflowContext.disabledMessage);
|
|
3160
3249
|
}
|
|
3161
3250
|
/**
|
|
3162
3251
|
* copies the passed context to create a DisabledWorkflowContext. Then, runs the
|
|
@@ -3179,18 +3268,14 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
3179
3268
|
headers: context.headers,
|
|
3180
3269
|
steps: [],
|
|
3181
3270
|
url: context.url,
|
|
3182
|
-
failureUrl: context.failureUrl,
|
|
3183
3271
|
initialPayload: context.requestPayload,
|
|
3184
3272
|
env: context.env,
|
|
3185
|
-
retries: context.retries,
|
|
3186
|
-
retryDelay: context.retryDelay,
|
|
3187
|
-
flowControl: context.flowControl,
|
|
3188
3273
|
label: context.label
|
|
3189
3274
|
});
|
|
3190
3275
|
try {
|
|
3191
3276
|
await routeFunction(disabledContext);
|
|
3192
3277
|
} catch (error) {
|
|
3193
|
-
if (isInstanceOf(error,
|
|
3278
|
+
if (isInstanceOf(error, WorkflowAuthError) && error.stepName === this.disabledMessage || isInstanceOf(error, WorkflowNonRetryableError) || isInstanceOf(error, WorkflowRetryAfterError)) {
|
|
3194
3279
|
return ok("step-found");
|
|
3195
3280
|
}
|
|
3196
3281
|
console.warn(
|
|
@@ -3223,13 +3308,6 @@ var processRawSteps = (rawSteps) => {
|
|
|
3223
3308
|
const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
|
|
3224
3309
|
const otherSteps = stepsToDecode.map((rawStep) => {
|
|
3225
3310
|
const step = JSON.parse(decodeBase64(rawStep.body));
|
|
3226
|
-
if (step.waitEventId) {
|
|
3227
|
-
const newOut = {
|
|
3228
|
-
eventData: step.out ? decodeBase64(step.out) : void 0,
|
|
3229
|
-
timeout: step.waitTimeout ?? false
|
|
3230
|
-
};
|
|
3231
|
-
step.out = newOut;
|
|
3232
|
-
}
|
|
3233
3311
|
return step;
|
|
3234
3312
|
});
|
|
3235
3313
|
const steps = [initialStep, ...otherSteps];
|
|
@@ -3257,7 +3335,7 @@ var deduplicateSteps = (steps) => {
|
|
|
3257
3335
|
}
|
|
3258
3336
|
return deduplicatedSteps;
|
|
3259
3337
|
};
|
|
3260
|
-
var checkIfLastOneIsDuplicate = async (steps,
|
|
3338
|
+
var checkIfLastOneIsDuplicate = async (steps, dispatchDebug) => {
|
|
3261
3339
|
if (steps.length < 2) {
|
|
3262
3340
|
return false;
|
|
3263
3341
|
}
|
|
@@ -3268,14 +3346,41 @@ var checkIfLastOneIsDuplicate = async (steps, debug) => {
|
|
|
3268
3346
|
const step = steps[index];
|
|
3269
3347
|
if (step.stepId === lastStepId && step.targetStep === lastTargetStepId) {
|
|
3270
3348
|
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.`;
|
|
3271
|
-
await
|
|
3272
|
-
|
|
3349
|
+
await dispatchDebug?.("onWarning", {
|
|
3350
|
+
warning: message
|
|
3351
|
+
});
|
|
3273
3352
|
return true;
|
|
3274
3353
|
}
|
|
3275
3354
|
}
|
|
3276
3355
|
return false;
|
|
3277
3356
|
};
|
|
3278
3357
|
var validateRequest = (request) => {
|
|
3358
|
+
if (request.headers.get(WORKFLOW_UNKOWN_SDK_VERSION_HEADER)) {
|
|
3359
|
+
const workflowRunId2 = request.headers.get(WORKFLOW_ID_HEADER);
|
|
3360
|
+
if (!workflowRunId2) {
|
|
3361
|
+
throw new WorkflowError(
|
|
3362
|
+
"Couldn't get workflow id from header when handling unknown sdk request"
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
return {
|
|
3366
|
+
unknownSdk: true,
|
|
3367
|
+
isFirstInvocation: true,
|
|
3368
|
+
workflowRunId: workflowRunId2
|
|
3369
|
+
};
|
|
3370
|
+
}
|
|
3371
|
+
if (request.headers.get(WORKFLOW_FAILURE_CALLBACK_HEADER)) {
|
|
3372
|
+
const workflowRunId2 = request.headers.get(WORKFLOW_ID_HEADER);
|
|
3373
|
+
if (!workflowRunId2) {
|
|
3374
|
+
throw new WorkflowError(
|
|
3375
|
+
"Couldn't get workflow id from header when handling failure callback request"
|
|
3376
|
+
);
|
|
3377
|
+
}
|
|
3378
|
+
return {
|
|
3379
|
+
unknownSdk: false,
|
|
3380
|
+
isFirstInvocation: true,
|
|
3381
|
+
workflowRunId: workflowRunId2
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3279
3384
|
const versionHeader = request.headers.get(WORKFLOW_PROTOCOL_VERSION_HEADER);
|
|
3280
3385
|
const isFirstInvocation = !versionHeader;
|
|
3281
3386
|
if (!isFirstInvocation && versionHeader !== WORKFLOW_PROTOCOL_VERSION) {
|
|
@@ -3289,11 +3394,20 @@ var validateRequest = (request) => {
|
|
|
3289
3394
|
}
|
|
3290
3395
|
return {
|
|
3291
3396
|
isFirstInvocation,
|
|
3292
|
-
workflowRunId
|
|
3397
|
+
workflowRunId,
|
|
3398
|
+
unknownSdk: false
|
|
3293
3399
|
};
|
|
3294
3400
|
};
|
|
3295
|
-
var parseRequest = async (
|
|
3296
|
-
|
|
3401
|
+
var parseRequest = async ({
|
|
3402
|
+
requestPayload,
|
|
3403
|
+
isFirstInvocation,
|
|
3404
|
+
unknownSdk,
|
|
3405
|
+
workflowRunId,
|
|
3406
|
+
requester,
|
|
3407
|
+
messageId,
|
|
3408
|
+
dispatchDebug
|
|
3409
|
+
}) => {
|
|
3410
|
+
if (isFirstInvocation && !unknownSdk) {
|
|
3297
3411
|
return {
|
|
3298
3412
|
rawInitialPayload: requestPayload ?? "",
|
|
3299
3413
|
steps: [],
|
|
@@ -3303,16 +3417,14 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3303
3417
|
} else {
|
|
3304
3418
|
let rawSteps;
|
|
3305
3419
|
if (!requestPayload) {
|
|
3306
|
-
await
|
|
3307
|
-
"
|
|
3308
|
-
|
|
3309
|
-
"request payload is empty, steps will be fetched from QStash."
|
|
3310
|
-
);
|
|
3420
|
+
await dispatchDebug?.("onInfo", {
|
|
3421
|
+
info: "request payload is empty, steps will be fetched from QStash."
|
|
3422
|
+
});
|
|
3311
3423
|
const { steps: fetchedSteps, workflowRunEnded } = await getSteps(
|
|
3312
3424
|
requester,
|
|
3313
3425
|
workflowRunId,
|
|
3314
3426
|
messageId,
|
|
3315
|
-
|
|
3427
|
+
dispatchDebug
|
|
3316
3428
|
);
|
|
3317
3429
|
if (workflowRunEnded) {
|
|
3318
3430
|
return {
|
|
@@ -3327,7 +3439,7 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3327
3439
|
rawSteps = JSON.parse(requestPayload);
|
|
3328
3440
|
}
|
|
3329
3441
|
const { rawInitialPayload, steps } = processRawSteps(rawSteps);
|
|
3330
|
-
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps,
|
|
3442
|
+
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps, dispatchDebug);
|
|
3331
3443
|
const deduplicatedSteps = deduplicateSteps(steps);
|
|
3332
3444
|
return {
|
|
3333
3445
|
rawInitialPayload,
|
|
@@ -3337,16 +3449,21 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
3337
3449
|
};
|
|
3338
3450
|
}
|
|
3339
3451
|
};
|
|
3340
|
-
var handleFailure = async (
|
|
3341
|
-
|
|
3452
|
+
var handleFailure = async ({
|
|
3453
|
+
request,
|
|
3454
|
+
requestPayload,
|
|
3455
|
+
qstashClient,
|
|
3456
|
+
initialPayloadParser,
|
|
3457
|
+
routeFunction,
|
|
3458
|
+
failureFunction,
|
|
3459
|
+
env,
|
|
3460
|
+
dispatchDebug
|
|
3461
|
+
}) => {
|
|
3462
|
+
if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true" && !request.headers.get(WORKFLOW_FAILURE_CALLBACK_HEADER)) {
|
|
3342
3463
|
return ok({ result: "not-failure-callback" });
|
|
3343
3464
|
}
|
|
3344
3465
|
if (!failureFunction) {
|
|
3345
|
-
return
|
|
3346
|
-
new WorkflowError(
|
|
3347
|
-
"Workflow endpoint is called to handle a failure, but a failureFunction is not provided in serve options. Either provide a failureUrl or a failureFunction."
|
|
3348
|
-
)
|
|
3349
|
-
);
|
|
3466
|
+
return ok({ result: "failure-function-undefined" });
|
|
3350
3467
|
}
|
|
3351
3468
|
try {
|
|
3352
3469
|
const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
|
|
@@ -3374,23 +3491,21 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
3374
3491
|
headers: userHeaders,
|
|
3375
3492
|
steps: [],
|
|
3376
3493
|
url,
|
|
3377
|
-
failureUrl: url,
|
|
3378
|
-
debug,
|
|
3379
3494
|
env,
|
|
3380
|
-
retries,
|
|
3381
|
-
retryDelay,
|
|
3382
|
-
flowControl,
|
|
3383
3495
|
telemetry: void 0,
|
|
3384
3496
|
// not going to make requests in authentication check
|
|
3385
|
-
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0
|
|
3497
|
+
label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
|
|
3498
|
+
middlewareManager: void 0
|
|
3386
3499
|
});
|
|
3387
3500
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
3388
3501
|
routeFunction,
|
|
3389
3502
|
workflowContext
|
|
3390
3503
|
);
|
|
3391
3504
|
if (authCheck.isErr()) {
|
|
3392
|
-
await
|
|
3393
|
-
|
|
3505
|
+
await dispatchDebug?.("onError", {
|
|
3506
|
+
error: authCheck.error
|
|
3507
|
+
});
|
|
3508
|
+
return err(authCheck.error);
|
|
3394
3509
|
} else if (authCheck.value === "run-ended") {
|
|
3395
3510
|
return err(new WorkflowError("Not authorized to run the failure function."));
|
|
3396
3511
|
}
|
|
@@ -3401,74 +3516,309 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
3401
3516
|
failHeaders: header,
|
|
3402
3517
|
failStack
|
|
3403
3518
|
});
|
|
3404
|
-
return ok({ result: "
|
|
3519
|
+
return ok({ result: "failure-function-executed", response: failureResponse });
|
|
3405
3520
|
} catch (error) {
|
|
3406
3521
|
return err(error);
|
|
3407
3522
|
}
|
|
3408
3523
|
};
|
|
3409
3524
|
|
|
3410
|
-
// src/serve/
|
|
3525
|
+
// src/serve/multi-region/handlers.ts
|
|
3411
3526
|
var import_qstash10 = require("@upstash/qstash");
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3527
|
+
|
|
3528
|
+
// src/serve/multi-region/utils.ts
|
|
3529
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
3530
|
+
var getRegionFromEnvironment = (environment) => {
|
|
3531
|
+
const region = environment.QSTASH_REGION;
|
|
3532
|
+
return normalizeRegionHeader(region);
|
|
3533
|
+
};
|
|
3534
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
3535
|
+
const result = {};
|
|
3536
|
+
for (const variable of environmentVariables) {
|
|
3537
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
3538
|
+
result[variable] = environment[key];
|
|
3539
|
+
}
|
|
3540
|
+
return result;
|
|
3541
|
+
}
|
|
3542
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
3543
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
3544
|
+
}
|
|
3545
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
3546
|
+
return readEnvironmentVariables(
|
|
3547
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
3548
|
+
environment,
|
|
3549
|
+
region
|
|
3417
3550
|
);
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3551
|
+
}
|
|
3552
|
+
function normalizeRegionHeader(region) {
|
|
3553
|
+
if (!region) {
|
|
3554
|
+
return void 0;
|
|
3555
|
+
}
|
|
3556
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
3557
|
+
if (VALID_REGIONS.includes(region)) {
|
|
3558
|
+
return region;
|
|
3559
|
+
}
|
|
3560
|
+
console.warn(
|
|
3561
|
+
`[Upstash Workflow] Invalid UPSTASH-REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
3562
|
+
", "
|
|
3563
|
+
)}.`
|
|
3564
|
+
);
|
|
3565
|
+
return void 0;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
// src/serve/multi-region/handlers.ts
|
|
3569
|
+
var getHandlersForRequest = (qstashHandlers, regionHeader, isFirstInvocation) => {
|
|
3570
|
+
if (qstashHandlers.mode === "single-region") {
|
|
3571
|
+
return qstashHandlers.handlers;
|
|
3572
|
+
}
|
|
3573
|
+
let targetRegion;
|
|
3574
|
+
if (isFirstInvocation) {
|
|
3575
|
+
targetRegion = qstashHandlers.defaultRegion;
|
|
3576
|
+
} else {
|
|
3577
|
+
const normalizedRegion = regionHeader ? normalizeRegionHeader(regionHeader) : void 0;
|
|
3578
|
+
targetRegion = normalizedRegion ?? qstashHandlers.defaultRegion;
|
|
3579
|
+
}
|
|
3580
|
+
const handler = qstashHandlers.handlers[targetRegion];
|
|
3581
|
+
if (!handler) {
|
|
3582
|
+
console.warn(
|
|
3583
|
+
`[Upstash Workflow] No handler found for region "${targetRegion}". Falling back to default region.`
|
|
3584
|
+
);
|
|
3585
|
+
return qstashHandlers.handlers[qstashHandlers.defaultRegion];
|
|
3586
|
+
}
|
|
3587
|
+
return handler;
|
|
3588
|
+
};
|
|
3589
|
+
var createRegionalHandler = (environment, receiverConfig, region, clientOptions) => {
|
|
3590
|
+
const clientEnv = readClientEnvironmentVariables(environment, region);
|
|
3591
|
+
const client = new import_qstash10.Client({
|
|
3592
|
+
...clientOptions,
|
|
3593
|
+
baseUrl: clientEnv.QSTASH_URL,
|
|
3594
|
+
token: clientEnv.QSTASH_TOKEN
|
|
3595
|
+
});
|
|
3596
|
+
const receiver = getReceiver(environment, receiverConfig, region);
|
|
3597
|
+
return { client, receiver };
|
|
3598
|
+
};
|
|
3599
|
+
var shouldUseMultiRegionMode = (environment, qstashClientOption) => {
|
|
3600
|
+
const hasRegionEnv = Boolean(getRegionFromEnvironment(environment));
|
|
3601
|
+
if (hasRegionEnv && (!qstashClientOption || !("http" in qstashClientOption))) {
|
|
3602
|
+
return {
|
|
3603
|
+
isMultiRegion: true,
|
|
3604
|
+
defaultRegion: getRegionFromEnvironment(environment),
|
|
3605
|
+
clientOptions: qstashClientOption
|
|
3606
|
+
};
|
|
3607
|
+
} else {
|
|
3608
|
+
return { isMultiRegion: false };
|
|
3609
|
+
}
|
|
3610
|
+
};
|
|
3611
|
+
var getQStashHandlers = ({
|
|
3612
|
+
environment,
|
|
3613
|
+
qstashClientOption,
|
|
3614
|
+
receiverConfig
|
|
3615
|
+
}) => {
|
|
3616
|
+
const multiRegion = shouldUseMultiRegionMode(environment, qstashClientOption);
|
|
3617
|
+
if (multiRegion.isMultiRegion) {
|
|
3618
|
+
const regions = ["US_EAST_1", "EU_CENTRAL_1"];
|
|
3619
|
+
const handlers = {};
|
|
3620
|
+
for (const region of regions) {
|
|
3621
|
+
try {
|
|
3622
|
+
handlers[region] = createRegionalHandler(
|
|
3623
|
+
environment,
|
|
3624
|
+
receiverConfig,
|
|
3625
|
+
region,
|
|
3626
|
+
multiRegion.clientOptions
|
|
3463
3627
|
);
|
|
3628
|
+
} catch (error) {
|
|
3629
|
+
console.warn(`[Upstash Workflow] Failed to create handler for region ${region}:`, error);
|
|
3464
3630
|
}
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3631
|
+
}
|
|
3632
|
+
return {
|
|
3633
|
+
mode: "multi-region",
|
|
3634
|
+
handlers,
|
|
3635
|
+
defaultRegion: multiRegion.defaultRegion
|
|
3636
|
+
};
|
|
3637
|
+
} else {
|
|
3638
|
+
return {
|
|
3639
|
+
mode: "single-region",
|
|
3640
|
+
handlers: {
|
|
3641
|
+
client: qstashClientOption && "http" in qstashClientOption ? qstashClientOption : new import_qstash10.Client({
|
|
3642
|
+
...qstashClientOption,
|
|
3643
|
+
baseUrl: environment.QSTASH_URL,
|
|
3644
|
+
token: environment.QSTASH_TOKEN
|
|
3645
|
+
}),
|
|
3646
|
+
receiver: getReceiver(environment, receiverConfig)
|
|
3647
|
+
}
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
};
|
|
3651
|
+
var getReceiver = (environment, receiverConfig, region) => {
|
|
3652
|
+
if (typeof receiverConfig === "string") {
|
|
3653
|
+
if (receiverConfig === "set-to-undefined") {
|
|
3654
|
+
return void 0;
|
|
3655
|
+
}
|
|
3656
|
+
const receiverEnv = readReceiverEnvironmentVariables(environment, region);
|
|
3657
|
+
return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash10.Receiver({
|
|
3658
|
+
currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
|
|
3659
|
+
nextSigningKey: receiverEnv.QSTASH_NEXT_SIGNING_KEY
|
|
3660
|
+
}) : void 0;
|
|
3661
|
+
} else {
|
|
3662
|
+
return receiverConfig;
|
|
3663
|
+
}
|
|
3664
|
+
};
|
|
3665
|
+
var getQStashHandlerOptions = (...params) => {
|
|
3666
|
+
const handlers = getQStashHandlers(...params);
|
|
3667
|
+
return {
|
|
3668
|
+
qstashHandlers: handlers,
|
|
3669
|
+
defaultReceiver: handlers.mode === "single-region" ? handlers.handlers.receiver : handlers.handlers[handlers.defaultRegion].receiver,
|
|
3670
|
+
defaultClient: handlers.mode === "single-region" ? handlers.handlers.client : handlers.handlers[handlers.defaultRegion].client
|
|
3671
|
+
};
|
|
3672
|
+
};
|
|
3673
|
+
|
|
3674
|
+
// src/middleware/middleware.ts
|
|
3675
|
+
var WorkflowMiddleware = class {
|
|
3676
|
+
name;
|
|
3677
|
+
initCallbacks;
|
|
3678
|
+
/**
|
|
3679
|
+
* Callback functions
|
|
3680
|
+
*
|
|
3681
|
+
* Initially set to undefined, will be populated after init is called
|
|
3682
|
+
*/
|
|
3683
|
+
middlewareCallbacks = void 0;
|
|
3684
|
+
constructor(parameters) {
|
|
3685
|
+
this.name = parameters.name;
|
|
3686
|
+
if ("init" in parameters) {
|
|
3687
|
+
this.initCallbacks = parameters.init;
|
|
3688
|
+
} else {
|
|
3689
|
+
this.middlewareCallbacks = parameters.callbacks;
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
async ensureInit() {
|
|
3693
|
+
if (!this.middlewareCallbacks) {
|
|
3694
|
+
if (!this.initCallbacks) {
|
|
3695
|
+
throw new WorkflowError(`Middleware "${this.name}" has no callbacks or init defined.`);
|
|
3696
|
+
}
|
|
3697
|
+
this.middlewareCallbacks = await this.initCallbacks();
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
/**
|
|
3701
|
+
* Gets a callback function by name.
|
|
3702
|
+
*
|
|
3703
|
+
* @param callback name of the callback to retrieve
|
|
3704
|
+
*/
|
|
3705
|
+
getCallback(callback) {
|
|
3706
|
+
return this.middlewareCallbacks?.[callback];
|
|
3707
|
+
}
|
|
3708
|
+
};
|
|
3709
|
+
|
|
3710
|
+
// src/middleware/logging.ts
|
|
3711
|
+
var loggingMiddleware = new WorkflowMiddleware({
|
|
3712
|
+
name: "logging",
|
|
3713
|
+
callbacks: {
|
|
3714
|
+
afterExecution(params) {
|
|
3715
|
+
const { context, ...rest } = params;
|
|
3716
|
+
console.log(" [Upstash Workflow]: Step executed:", {
|
|
3717
|
+
workflowRunId: context.workflowRunId,
|
|
3718
|
+
...rest
|
|
3719
|
+
});
|
|
3720
|
+
},
|
|
3721
|
+
beforeExecution(params) {
|
|
3722
|
+
const { context, ...rest } = params;
|
|
3723
|
+
console.log(" [Upstash Workflow]: Step execution started:", {
|
|
3724
|
+
workflowRunId: context.workflowRunId,
|
|
3725
|
+
...rest
|
|
3470
3726
|
});
|
|
3471
3727
|
},
|
|
3728
|
+
runStarted(params) {
|
|
3729
|
+
const { context, ...rest } = params;
|
|
3730
|
+
console.log(" [Upstash Workflow]: Workflow run started:", {
|
|
3731
|
+
workflowRunId: context.workflowRunId,
|
|
3732
|
+
...rest
|
|
3733
|
+
});
|
|
3734
|
+
},
|
|
3735
|
+
runCompleted(params) {
|
|
3736
|
+
const { context, ...rest } = params;
|
|
3737
|
+
console.log(" [Upstash Workflow]: Workflow run completed:", {
|
|
3738
|
+
workflowRunId: context.workflowRunId,
|
|
3739
|
+
...rest
|
|
3740
|
+
});
|
|
3741
|
+
},
|
|
3742
|
+
onError: onErrorWithConsole,
|
|
3743
|
+
onWarning: onWarningWithConsole,
|
|
3744
|
+
onInfo: onInfoWithConsole
|
|
3745
|
+
}
|
|
3746
|
+
});
|
|
3747
|
+
|
|
3748
|
+
// src/serve/options.ts
|
|
3749
|
+
var createResponseData = (workflowRunId, detailedFinishCondition) => {
|
|
3750
|
+
const baseHeaders = {
|
|
3751
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
3752
|
+
"Upstash-workflow-sdk": VERSION
|
|
3753
|
+
};
|
|
3754
|
+
if (detailedFinishCondition?.condition === "auth-fail") {
|
|
3755
|
+
return {
|
|
3756
|
+
text: JSON.stringify({
|
|
3757
|
+
message: AUTH_FAIL_MESSAGE,
|
|
3758
|
+
workflowRunId
|
|
3759
|
+
}),
|
|
3760
|
+
status: 400,
|
|
3761
|
+
headers: baseHeaders
|
|
3762
|
+
};
|
|
3763
|
+
} else if (detailedFinishCondition?.condition === "non-retryable-error") {
|
|
3764
|
+
return {
|
|
3765
|
+
text: JSON.stringify(formatWorkflowError(detailedFinishCondition.result)),
|
|
3766
|
+
status: 489,
|
|
3767
|
+
headers: {
|
|
3768
|
+
...baseHeaders,
|
|
3769
|
+
"Upstash-NonRetryable-Error": "true"
|
|
3770
|
+
}
|
|
3771
|
+
};
|
|
3772
|
+
} else if (detailedFinishCondition?.condition === "retry-after-error") {
|
|
3773
|
+
return {
|
|
3774
|
+
text: JSON.stringify(formatWorkflowError(detailedFinishCondition.result)),
|
|
3775
|
+
status: 429,
|
|
3776
|
+
headers: {
|
|
3777
|
+
...baseHeaders,
|
|
3778
|
+
"Retry-After": detailedFinishCondition.result.retryAfter.toString()
|
|
3779
|
+
}
|
|
3780
|
+
};
|
|
3781
|
+
} else if (detailedFinishCondition?.condition === "failure-callback-executed") {
|
|
3782
|
+
return {
|
|
3783
|
+
text: JSON.stringify({ result: detailedFinishCondition.result ?? void 0 }),
|
|
3784
|
+
status: 200,
|
|
3785
|
+
headers: baseHeaders
|
|
3786
|
+
};
|
|
3787
|
+
} else if (detailedFinishCondition?.condition === "failure-callback-undefined") {
|
|
3788
|
+
return {
|
|
3789
|
+
text: JSON.stringify({
|
|
3790
|
+
workflowRunId,
|
|
3791
|
+
finishCondition: detailedFinishCondition.condition
|
|
3792
|
+
}),
|
|
3793
|
+
status: 200,
|
|
3794
|
+
headers: {
|
|
3795
|
+
...baseHeaders,
|
|
3796
|
+
"Upstash-Workflow-Failure-Callback-Notfound": "true"
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3799
|
+
}
|
|
3800
|
+
return {
|
|
3801
|
+
text: JSON.stringify({
|
|
3802
|
+
workflowRunId,
|
|
3803
|
+
finishCondition: detailedFinishCondition.condition
|
|
3804
|
+
}),
|
|
3805
|
+
status: 200,
|
|
3806
|
+
headers: baseHeaders
|
|
3807
|
+
};
|
|
3808
|
+
};
|
|
3809
|
+
var processOptions = (options, internalOptions) => {
|
|
3810
|
+
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
3811
|
+
const {
|
|
3812
|
+
qstashHandlers,
|
|
3813
|
+
defaultClient: qstashClient,
|
|
3814
|
+
defaultReceiver: receiver
|
|
3815
|
+
} = getQStashHandlerOptions({
|
|
3816
|
+
environment,
|
|
3817
|
+
qstashClientOption: options?.qstashClient,
|
|
3818
|
+
receiverConfig: options && "receiver" in options ? options.receiver ? options.receiver : "set-to-undefined" : "not-set"
|
|
3819
|
+
});
|
|
3820
|
+
return {
|
|
3821
|
+
qstashClient,
|
|
3472
3822
|
initialPayloadParser: (initialRequest) => {
|
|
3473
3823
|
if (!initialRequest) {
|
|
3474
3824
|
return void 0;
|
|
@@ -3483,35 +3833,38 @@ var processOptions = (options) => {
|
|
|
3483
3833
|
throw error;
|
|
3484
3834
|
}
|
|
3485
3835
|
},
|
|
3486
|
-
receiver
|
|
3487
|
-
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
3488
|
-
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
3489
|
-
}) : void 0,
|
|
3836
|
+
receiver,
|
|
3490
3837
|
baseUrl: environment.UPSTASH_WORKFLOW_URL,
|
|
3491
3838
|
env: environment,
|
|
3492
|
-
retries: DEFAULT_RETRIES,
|
|
3493
|
-
useJSONContent: false,
|
|
3494
3839
|
disableTelemetry: false,
|
|
3495
|
-
|
|
3496
|
-
|
|
3840
|
+
...options,
|
|
3841
|
+
// merge middlewares
|
|
3842
|
+
middlewares: [options?.middlewares ?? [], options?.verbose ? [loggingMiddleware] : []].flat(),
|
|
3843
|
+
internal: {
|
|
3844
|
+
generateResponse: internalOptions?.generateResponse ?? ((responseData) => {
|
|
3845
|
+
return new Response(responseData.text, {
|
|
3846
|
+
status: responseData.status,
|
|
3847
|
+
headers: responseData.headers
|
|
3848
|
+
});
|
|
3849
|
+
}),
|
|
3850
|
+
useJSONContent: internalOptions?.useJSONContent ?? false,
|
|
3851
|
+
qstashHandlers
|
|
3852
|
+
}
|
|
3497
3853
|
};
|
|
3498
3854
|
};
|
|
3499
|
-
var determineUrls = async (request, url, baseUrl,
|
|
3855
|
+
var determineUrls = async (request, url, baseUrl, dispatchDebug) => {
|
|
3500
3856
|
const initialWorkflowUrl = url ?? request.url;
|
|
3501
3857
|
const workflowUrl = baseUrl ? initialWorkflowUrl.replace(/^(https?:\/\/[^/]+)(\/.*)?$/, (_, matchedBaseUrl, path) => {
|
|
3502
3858
|
return baseUrl + (path || "");
|
|
3503
3859
|
}) : initialWorkflowUrl;
|
|
3504
3860
|
if (workflowUrl !== initialWorkflowUrl) {
|
|
3505
|
-
await
|
|
3506
|
-
|
|
3507
|
-
originalURL: initialWorkflowUrl,
|
|
3508
|
-
updatedURL: workflowUrl
|
|
3861
|
+
await dispatchDebug("onInfo", {
|
|
3862
|
+
info: `The workflow URL's base URL has been replaced with the provided baseUrl. Original URL: ${initialWorkflowUrl}, New URL: ${workflowUrl}`
|
|
3509
3863
|
});
|
|
3510
3864
|
}
|
|
3511
|
-
const workflowFailureUrl = failureFunction ? workflowUrl : failureUrl;
|
|
3512
3865
|
if (workflowUrl.includes("localhost")) {
|
|
3513
|
-
await
|
|
3514
|
-
|
|
3866
|
+
await dispatchDebug("onInfo", {
|
|
3867
|
+
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}`
|
|
3515
3868
|
});
|
|
3516
3869
|
}
|
|
3517
3870
|
if (!(workflowUrl.startsWith("http://") || workflowUrl.startsWith("https://"))) {
|
|
@@ -3520,205 +3873,224 @@ var determineUrls = async (request, url, baseUrl, failureFunction, failureUrl, d
|
|
|
3520
3873
|
);
|
|
3521
3874
|
}
|
|
3522
3875
|
return {
|
|
3523
|
-
workflowUrl
|
|
3524
|
-
workflowFailureUrl
|
|
3876
|
+
workflowUrl
|
|
3525
3877
|
};
|
|
3526
3878
|
};
|
|
3527
3879
|
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`;
|
|
3528
3880
|
|
|
3529
3881
|
// src/serve/index.ts
|
|
3530
|
-
var serveBase = (routeFunction, telemetry2, options) => {
|
|
3882
|
+
var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
|
|
3531
3883
|
const {
|
|
3532
|
-
qstashClient,
|
|
3533
|
-
onStepFinish,
|
|
3534
3884
|
initialPayloadParser,
|
|
3535
3885
|
url,
|
|
3536
|
-
verbose,
|
|
3537
|
-
receiver,
|
|
3538
|
-
failureUrl,
|
|
3539
3886
|
failureFunction,
|
|
3540
3887
|
baseUrl,
|
|
3541
3888
|
env,
|
|
3542
|
-
retries,
|
|
3543
|
-
retryDelay,
|
|
3544
|
-
useJSONContent,
|
|
3545
3889
|
disableTelemetry,
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
} = processOptions(options);
|
|
3890
|
+
middlewares,
|
|
3891
|
+
internal
|
|
3892
|
+
} = processOptions(options, internalOptions);
|
|
3549
3893
|
telemetry2 = disableTelemetry ? void 0 : telemetry2;
|
|
3550
|
-
const
|
|
3551
|
-
const handler = async (request) => {
|
|
3552
|
-
await
|
|
3553
|
-
|
|
3894
|
+
const { generateResponse: responseGenerator, useJSONContent } = internal;
|
|
3895
|
+
const handler = async (request, middlewareManager) => {
|
|
3896
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3897
|
+
info: `Received request for workflow execution.`
|
|
3898
|
+
});
|
|
3899
|
+
const { workflowUrl } = await determineUrls(
|
|
3554
3900
|
request,
|
|
3555
3901
|
url,
|
|
3556
3902
|
baseUrl,
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3903
|
+
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3904
|
+
);
|
|
3905
|
+
const { isFirstInvocation, workflowRunId, unknownSdk } = validateRequest(request);
|
|
3906
|
+
const regionHeader = request.headers.get("upstash-region");
|
|
3907
|
+
const { client: regionalClient, receiver: regionalReceiver } = getHandlersForRequest(
|
|
3908
|
+
internal.qstashHandlers,
|
|
3909
|
+
regionHeader,
|
|
3910
|
+
isFirstInvocation
|
|
3560
3911
|
);
|
|
3561
3912
|
const requestPayload = await getPayload(request) ?? "";
|
|
3562
|
-
await verifyRequest(requestPayload, request.headers.get("upstash-signature"),
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3913
|
+
await verifyRequest(requestPayload, request.headers.get("upstash-signature"), regionalReceiver);
|
|
3914
|
+
middlewareManager.assignWorkflowRunId(workflowRunId);
|
|
3915
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3916
|
+
info: `Run id identified. isFirstInvocation: ${isFirstInvocation}, unknownSdk: ${unknownSdk}`
|
|
3917
|
+
});
|
|
3918
|
+
const { rawInitialPayload, steps, isLastDuplicate, workflowRunEnded } = await parseRequest({
|
|
3566
3919
|
requestPayload,
|
|
3567
3920
|
isFirstInvocation,
|
|
3921
|
+
unknownSdk,
|
|
3568
3922
|
workflowRunId,
|
|
3569
|
-
|
|
3570
|
-
request.headers.get("upstash-message-id"),
|
|
3571
|
-
|
|
3572
|
-
);
|
|
3923
|
+
requester: regionalClient.http,
|
|
3924
|
+
messageId: request.headers.get("upstash-message-id"),
|
|
3925
|
+
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3926
|
+
});
|
|
3573
3927
|
if (workflowRunEnded) {
|
|
3574
|
-
return
|
|
3575
|
-
|
|
3576
|
-
|
|
3928
|
+
return responseGenerator(
|
|
3929
|
+
createResponseData(workflowRunId, {
|
|
3930
|
+
condition: "workflow-already-ended"
|
|
3931
|
+
})
|
|
3932
|
+
);
|
|
3577
3933
|
}
|
|
3578
3934
|
if (isLastDuplicate) {
|
|
3579
|
-
return
|
|
3580
|
-
|
|
3581
|
-
|
|
3935
|
+
return responseGenerator(
|
|
3936
|
+
createResponseData(workflowRunId, {
|
|
3937
|
+
condition: "duplicate-step"
|
|
3938
|
+
})
|
|
3939
|
+
);
|
|
3582
3940
|
}
|
|
3583
|
-
const failureCheck = await handleFailure(
|
|
3941
|
+
const failureCheck = await handleFailure({
|
|
3584
3942
|
request,
|
|
3585
3943
|
requestPayload,
|
|
3586
|
-
qstashClient,
|
|
3944
|
+
qstashClient: regionalClient,
|
|
3587
3945
|
initialPayloadParser,
|
|
3588
3946
|
routeFunction,
|
|
3589
3947
|
failureFunction,
|
|
3590
3948
|
env,
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
flowControl,
|
|
3594
|
-
debug
|
|
3595
|
-
);
|
|
3949
|
+
dispatchDebug: middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
3950
|
+
});
|
|
3596
3951
|
if (failureCheck.isErr()) {
|
|
3597
3952
|
throw failureCheck.error;
|
|
3598
|
-
} else if (failureCheck.value.result === "
|
|
3599
|
-
await
|
|
3600
|
-
|
|
3601
|
-
condition: "failure-callback",
|
|
3602
|
-
result: failureCheck.value.response
|
|
3953
|
+
} else if (failureCheck.value.result === "failure-function-executed") {
|
|
3954
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3955
|
+
info: `Handled failure callback.`
|
|
3603
3956
|
});
|
|
3957
|
+
return responseGenerator(
|
|
3958
|
+
createResponseData(workflowRunId, {
|
|
3959
|
+
condition: "failure-callback-executed",
|
|
3960
|
+
result: failureCheck.value.response
|
|
3961
|
+
})
|
|
3962
|
+
);
|
|
3963
|
+
} else if (failureCheck.value.result === "failure-function-undefined") {
|
|
3964
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
3965
|
+
info: `Failure callback invoked but no failure function defined.`
|
|
3966
|
+
});
|
|
3967
|
+
return responseGenerator(
|
|
3968
|
+
createResponseData(workflowRunId, {
|
|
3969
|
+
condition: "failure-callback-undefined"
|
|
3970
|
+
})
|
|
3971
|
+
);
|
|
3604
3972
|
}
|
|
3605
3973
|
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
3606
3974
|
const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
|
|
3607
3975
|
const workflowContext = new WorkflowContext({
|
|
3608
|
-
qstashClient,
|
|
3976
|
+
qstashClient: regionalClient,
|
|
3609
3977
|
workflowRunId,
|
|
3610
3978
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
3611
3979
|
headers: recreateUserHeaders(request.headers),
|
|
3612
3980
|
steps,
|
|
3613
3981
|
url: workflowUrl,
|
|
3614
|
-
failureUrl: workflowFailureUrl,
|
|
3615
|
-
debug,
|
|
3616
3982
|
env,
|
|
3617
|
-
retries,
|
|
3618
|
-
retryDelay,
|
|
3619
3983
|
telemetry: telemetry2,
|
|
3620
3984
|
invokeCount,
|
|
3621
|
-
|
|
3622
|
-
|
|
3985
|
+
label,
|
|
3986
|
+
middlewareManager
|
|
3623
3987
|
});
|
|
3624
3988
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
3625
3989
|
routeFunction,
|
|
3626
3990
|
workflowContext
|
|
3627
3991
|
);
|
|
3628
3992
|
if (authCheck.isErr()) {
|
|
3629
|
-
await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
|
|
3630
3993
|
throw authCheck.error;
|
|
3631
3994
|
} else if (authCheck.value === "run-ended") {
|
|
3632
|
-
await
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3995
|
+
await middlewareManager.dispatchDebug("onError", {
|
|
3996
|
+
error: new Error(AUTH_FAIL_MESSAGE)
|
|
3997
|
+
});
|
|
3998
|
+
return responseGenerator(
|
|
3999
|
+
createResponseData(isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId, {
|
|
4000
|
+
condition: "auth-fail"
|
|
4001
|
+
})
|
|
3637
4002
|
);
|
|
3638
4003
|
}
|
|
3639
4004
|
const callReturnCheck = await handleThirdPartyCallResult({
|
|
3640
4005
|
request,
|
|
3641
4006
|
requestPayload: rawInitialPayload,
|
|
3642
|
-
client:
|
|
4007
|
+
client: regionalClient,
|
|
3643
4008
|
workflowUrl,
|
|
3644
|
-
failureUrl: workflowFailureUrl,
|
|
3645
|
-
retries,
|
|
3646
|
-
retryDelay,
|
|
3647
|
-
flowControl,
|
|
3648
4009
|
telemetry: telemetry2,
|
|
3649
|
-
|
|
4010
|
+
middlewareManager
|
|
3650
4011
|
});
|
|
3651
4012
|
if (callReturnCheck.isErr()) {
|
|
3652
|
-
await debug?.log("ERROR", "SUBMIT_THIRD_PARTY_RESULT", {
|
|
3653
|
-
error: callReturnCheck.error.message
|
|
3654
|
-
});
|
|
3655
4013
|
throw callReturnCheck.error;
|
|
3656
4014
|
} else if (callReturnCheck.value === "continue-workflow") {
|
|
3657
4015
|
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3658
4016
|
workflowContext,
|
|
3659
4017
|
useJSONContent,
|
|
3660
4018
|
telemetry: telemetry2,
|
|
3661
|
-
|
|
3662
|
-
|
|
4019
|
+
invokeCount,
|
|
4020
|
+
middlewareManager,
|
|
4021
|
+
unknownSdk
|
|
3663
4022
|
}) : await triggerRouteFunction({
|
|
3664
|
-
onStep: async () =>
|
|
4023
|
+
onStep: async () => {
|
|
4024
|
+
if (steps.length === 1) {
|
|
4025
|
+
await middlewareManager.dispatchLifecycle("runStarted", {});
|
|
4026
|
+
}
|
|
4027
|
+
return await routeFunction(workflowContext);
|
|
4028
|
+
},
|
|
3665
4029
|
onCleanup: async (result2) => {
|
|
3666
|
-
await
|
|
4030
|
+
await middlewareManager.dispatchLifecycle("runCompleted", {
|
|
4031
|
+
result: result2
|
|
4032
|
+
});
|
|
4033
|
+
await triggerWorkflowDelete(
|
|
4034
|
+
workflowContext,
|
|
4035
|
+
result2,
|
|
4036
|
+
false,
|
|
4037
|
+
middlewareManager.dispatchDebug.bind(middlewareManager)
|
|
4038
|
+
);
|
|
3667
4039
|
},
|
|
3668
4040
|
onCancel: async () => {
|
|
3669
4041
|
await makeCancelRequest(workflowContext.qstashClient.http, workflowRunId);
|
|
3670
4042
|
},
|
|
3671
|
-
|
|
4043
|
+
middlewareManager
|
|
3672
4044
|
});
|
|
3673
4045
|
if (result.isOk() && isInstanceOf(result.value, WorkflowNonRetryableError)) {
|
|
3674
|
-
return
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
4046
|
+
return responseGenerator(
|
|
4047
|
+
createResponseData(workflowRunId, {
|
|
4048
|
+
condition: "non-retryable-error",
|
|
4049
|
+
result: result.value
|
|
4050
|
+
})
|
|
4051
|
+
);
|
|
3678
4052
|
}
|
|
3679
4053
|
if (result.isOk() && isInstanceOf(result.value, WorkflowRetryAfterError)) {
|
|
3680
|
-
return
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
4054
|
+
return responseGenerator(
|
|
4055
|
+
createResponseData(workflowRunId, {
|
|
4056
|
+
condition: "retry-after-error",
|
|
4057
|
+
result: result.value
|
|
4058
|
+
})
|
|
4059
|
+
);
|
|
3684
4060
|
}
|
|
3685
4061
|
if (result.isErr()) {
|
|
3686
|
-
await debug?.log("ERROR", "ERROR", { error: result.error.message });
|
|
3687
4062
|
throw result.error;
|
|
3688
4063
|
}
|
|
3689
|
-
await
|
|
3690
|
-
|
|
3691
|
-
condition: "success"
|
|
4064
|
+
await middlewareManager.dispatchDebug("onInfo", {
|
|
4065
|
+
info: `Workflow endpoint execution completed successfully.`
|
|
3692
4066
|
});
|
|
4067
|
+
return responseGenerator(
|
|
4068
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
4069
|
+
condition: "success"
|
|
4070
|
+
})
|
|
4071
|
+
);
|
|
3693
4072
|
} else if (callReturnCheck.value === "workflow-ended") {
|
|
3694
|
-
return
|
|
3695
|
-
|
|
3696
|
-
|
|
4073
|
+
return responseGenerator(
|
|
4074
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
4075
|
+
condition: "workflow-already-ended"
|
|
4076
|
+
})
|
|
4077
|
+
);
|
|
3697
4078
|
}
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
4079
|
+
return responseGenerator(
|
|
4080
|
+
createResponseData(workflowContext.workflowRunId, {
|
|
4081
|
+
condition: "fromCallback"
|
|
4082
|
+
})
|
|
4083
|
+
);
|
|
3702
4084
|
};
|
|
3703
4085
|
const safeHandler = async (request) => {
|
|
4086
|
+
const middlewareManager = new MiddlewareManager(middlewares);
|
|
3704
4087
|
try {
|
|
3705
|
-
return await handler(request);
|
|
4088
|
+
return await handler(request, middlewareManager);
|
|
3706
4089
|
} catch (error) {
|
|
3707
4090
|
const formattedError = formatWorkflowError(error);
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
}
|
|
3711
|
-
const formattedOnErrorError = formatWorkflowError(onErrorError);
|
|
3712
|
-
const errorMessage = `Error while running onError callback: '${formattedOnErrorError.message}'.
|
|
3713
|
-
Original error: '${formattedError.message}'`;
|
|
3714
|
-
console.error(errorMessage);
|
|
3715
|
-
return new Response(JSON.stringify({ error: errorMessage }), {
|
|
3716
|
-
status: 500,
|
|
3717
|
-
headers: {
|
|
3718
|
-
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
|
|
3719
|
-
}
|
|
3720
|
-
});
|
|
3721
|
-
}
|
|
4091
|
+
await middlewareManager.dispatchDebug("onError", {
|
|
4092
|
+
error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
|
|
4093
|
+
});
|
|
3722
4094
|
return new Response(JSON.stringify(formattedError), {
|
|
3723
4095
|
status: 500,
|
|
3724
4096
|
headers: {
|
|
@@ -3765,7 +4137,11 @@ var serve = (routeFunction, options) => {
|
|
|
3765
4137
|
body: await readRawBody(event),
|
|
3766
4138
|
method: "POST"
|
|
3767
4139
|
});
|
|
3768
|
-
const { handler: serveHandler } = serveBase(
|
|
4140
|
+
const { handler: serveHandler } = serveBase(
|
|
4141
|
+
routeFunction,
|
|
4142
|
+
telemetry,
|
|
4143
|
+
options
|
|
4144
|
+
);
|
|
3769
4145
|
return await serveHandler(request);
|
|
3770
4146
|
});
|
|
3771
4147
|
return { handler };
|