@upstash/workflow 0.1.5 → 0.2.0
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 +1 -1
- package/astro.d.ts +1 -1
- package/astro.js +344 -179
- package/astro.mjs +1 -1
- package/{chunk-OJZEI7LO.mjs → chunk-5R2BFC3N.mjs} +415 -192
- package/cloudflare.d.mts +1 -1
- package/cloudflare.d.ts +1 -1
- package/cloudflare.js +344 -179
- package/cloudflare.mjs +1 -1
- package/express.d.mts +1 -1
- package/express.d.ts +1 -1
- package/express.js +360 -182
- package/express.mjs +17 -4
- package/h3.d.mts +1 -1
- package/h3.d.ts +1 -1
- package/h3.js +344 -179
- package/h3.mjs +1 -1
- package/hono.d.mts +1 -1
- package/hono.d.ts +1 -1
- package/hono.js +344 -179
- package/hono.mjs +1 -1
- package/index.d.mts +74 -21
- package/index.d.ts +74 -21
- package/index.js +422 -199
- package/index.mjs +5 -5
- package/nextjs.d.mts +1 -1
- package/nextjs.d.ts +1 -1
- package/nextjs.js +344 -179
- package/nextjs.mjs +1 -1
- package/package.json +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +344 -179
- package/solidjs.mjs +1 -1
- package/svelte.d.mts +1 -1
- package/svelte.d.ts +1 -1
- package/svelte.js +344 -179
- package/svelte.mjs +1 -1
- package/{types-CQuc-j8n.d.mts → types-Cki_MHrh.d.mts} +85 -31
- package/{types-CQuc-j8n.d.ts → types-Cki_MHrh.d.ts} +85 -31
package/astro.js
CHANGED
|
@@ -26,22 +26,33 @@ module.exports = __toCommonJS(astro_exports);
|
|
|
26
26
|
|
|
27
27
|
// src/error.ts
|
|
28
28
|
var import_qstash = require("@upstash/qstash");
|
|
29
|
-
var
|
|
29
|
+
var WorkflowError = class extends import_qstash.QstashError {
|
|
30
30
|
constructor(message) {
|
|
31
31
|
super(message);
|
|
32
|
-
this.name = "
|
|
32
|
+
this.name = "WorkflowError";
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
|
-
var
|
|
35
|
+
var WorkflowAbort = class extends Error {
|
|
36
36
|
stepInfo;
|
|
37
37
|
stepName;
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* whether workflow is to be canceled on abort
|
|
40
|
+
*/
|
|
41
|
+
cancelWorkflow;
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @param stepName name of the aborting step
|
|
45
|
+
* @param stepInfo step information
|
|
46
|
+
* @param cancelWorkflow
|
|
47
|
+
*/
|
|
48
|
+
constructor(stepName, stepInfo, cancelWorkflow = false) {
|
|
39
49
|
super(
|
|
40
50
|
`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}'.`
|
|
41
51
|
);
|
|
42
|
-
this.name = "
|
|
52
|
+
this.name = "WorkflowAbort";
|
|
43
53
|
this.stepName = stepName;
|
|
44
54
|
this.stepInfo = stepInfo;
|
|
55
|
+
this.cancelWorkflow = cancelWorkflow;
|
|
45
56
|
}
|
|
46
57
|
};
|
|
47
58
|
var formatWorkflowError = (error) => {
|
|
@@ -63,6 +74,44 @@ var makeNotifyRequest = async (requester, eventId, eventData) => {
|
|
|
63
74
|
});
|
|
64
75
|
return result;
|
|
65
76
|
};
|
|
77
|
+
var makeCancelRequest = async (requester, workflowRunId) => {
|
|
78
|
+
await requester.request({
|
|
79
|
+
path: ["v2", "workflows", "runs", `${workflowRunId}?cancel=true`],
|
|
80
|
+
method: "DELETE",
|
|
81
|
+
parseResponseAsJson: false
|
|
82
|
+
});
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
85
|
+
var getSteps = async (requester, workflowRunId, messageId, debug) => {
|
|
86
|
+
try {
|
|
87
|
+
const steps = await requester.request({
|
|
88
|
+
path: ["v2", "workflows", "runs", workflowRunId],
|
|
89
|
+
parseResponseAsJson: true
|
|
90
|
+
});
|
|
91
|
+
if (!messageId) {
|
|
92
|
+
await debug?.log("INFO", "ENDPOINT_START", {
|
|
93
|
+
message: `Pulled ${steps.length} steps from QStashand returned them without filtering with messageId.`
|
|
94
|
+
});
|
|
95
|
+
return steps;
|
|
96
|
+
} else {
|
|
97
|
+
const index = steps.findIndex((item) => item.messageId === messageId);
|
|
98
|
+
if (index === -1) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
const filteredSteps = steps.slice(0, index + 1);
|
|
102
|
+
await debug?.log("INFO", "ENDPOINT_START", {
|
|
103
|
+
message: `Pulled ${steps.length} steps from QStash and filtered them to ${filteredSteps.length} using messageId.`
|
|
104
|
+
});
|
|
105
|
+
return filteredSteps;
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
await debug?.log("ERROR", "ERROR", {
|
|
109
|
+
message: "failed while fetching steps.",
|
|
110
|
+
error
|
|
111
|
+
});
|
|
112
|
+
throw new WorkflowError(`Failed while pulling steps. ${error}`);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
66
115
|
|
|
67
116
|
// src/context/steps.ts
|
|
68
117
|
var BaseLazyStep = class {
|
|
@@ -677,6 +726,7 @@ var StepTypes = [
|
|
|
677
726
|
];
|
|
678
727
|
|
|
679
728
|
// src/workflow-requests.ts
|
|
729
|
+
var import_qstash2 = require("@upstash/qstash");
|
|
680
730
|
var triggerFirstInvocation = async (workflowContext, retries, debug) => {
|
|
681
731
|
const { headers } = getHeaders(
|
|
682
732
|
"true",
|
|
@@ -687,20 +737,32 @@ var triggerFirstInvocation = async (workflowContext, retries, debug) => {
|
|
|
687
737
|
workflowContext.failureUrl,
|
|
688
738
|
retries
|
|
689
739
|
);
|
|
690
|
-
await debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
|
|
691
|
-
headers,
|
|
692
|
-
requestPayload: workflowContext.requestPayload,
|
|
693
|
-
url: workflowContext.url
|
|
694
|
-
});
|
|
695
740
|
try {
|
|
696
741
|
const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
|
|
697
|
-
await workflowContext.qstashClient.publish({
|
|
742
|
+
const result = await workflowContext.qstashClient.publish({
|
|
698
743
|
headers,
|
|
699
744
|
method: "POST",
|
|
700
745
|
body,
|
|
701
746
|
url: workflowContext.url
|
|
702
747
|
});
|
|
703
|
-
|
|
748
|
+
if (result.deduplicated) {
|
|
749
|
+
await debug?.log("WARN", "SUBMIT_FIRST_INVOCATION", {
|
|
750
|
+
message: `Workflow run ${workflowContext.workflowRunId} already exists. A new one isn't created.`,
|
|
751
|
+
headers,
|
|
752
|
+
requestPayload: workflowContext.requestPayload,
|
|
753
|
+
url: workflowContext.url,
|
|
754
|
+
messageId: result.messageId
|
|
755
|
+
});
|
|
756
|
+
return ok("workflow-run-already-exists");
|
|
757
|
+
} else {
|
|
758
|
+
await debug?.log("SUBMIT", "SUBMIT_FIRST_INVOCATION", {
|
|
759
|
+
headers,
|
|
760
|
+
requestPayload: workflowContext.requestPayload,
|
|
761
|
+
url: workflowContext.url,
|
|
762
|
+
messageId: result.messageId
|
|
763
|
+
});
|
|
764
|
+
return ok("success");
|
|
765
|
+
}
|
|
704
766
|
} catch (error) {
|
|
705
767
|
const error_ = error;
|
|
706
768
|
return err(error_);
|
|
@@ -708,7 +770,9 @@ var triggerFirstInvocation = async (workflowContext, retries, debug) => {
|
|
|
708
770
|
};
|
|
709
771
|
var triggerRouteFunction = async ({
|
|
710
772
|
onCleanup,
|
|
711
|
-
onStep
|
|
773
|
+
onStep,
|
|
774
|
+
onCancel,
|
|
775
|
+
debug
|
|
712
776
|
}) => {
|
|
713
777
|
try {
|
|
714
778
|
await onStep();
|
|
@@ -716,19 +780,50 @@ var triggerRouteFunction = async ({
|
|
|
716
780
|
return ok("workflow-finished");
|
|
717
781
|
} catch (error) {
|
|
718
782
|
const error_ = error;
|
|
719
|
-
|
|
783
|
+
if (error instanceof import_qstash2.QstashError && error.status === 400) {
|
|
784
|
+
await debug?.log("WARN", "RESPONSE_WORKFLOW", {
|
|
785
|
+
message: `tried to append to a cancelled workflow. exiting without publishing.`,
|
|
786
|
+
name: error.name,
|
|
787
|
+
errorMessage: error.message
|
|
788
|
+
});
|
|
789
|
+
return ok("workflow-was-finished");
|
|
790
|
+
} else if (!(error_ instanceof WorkflowAbort)) {
|
|
791
|
+
return err(error_);
|
|
792
|
+
} else if (error_.cancelWorkflow) {
|
|
793
|
+
await onCancel();
|
|
794
|
+
return ok("workflow-finished");
|
|
795
|
+
} else {
|
|
796
|
+
return ok("step-finished");
|
|
797
|
+
}
|
|
720
798
|
}
|
|
721
799
|
};
|
|
722
800
|
var triggerWorkflowDelete = async (workflowContext, debug, cancel = false) => {
|
|
723
801
|
await debug?.log("SUBMIT", "SUBMIT_CLEANUP", {
|
|
724
802
|
deletedWorkflowRunId: workflowContext.workflowRunId
|
|
725
803
|
});
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
804
|
+
try {
|
|
805
|
+
await workflowContext.qstashClient.http.request({
|
|
806
|
+
path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
|
|
807
|
+
method: "DELETE",
|
|
808
|
+
parseResponseAsJson: false
|
|
809
|
+
});
|
|
810
|
+
await debug?.log(
|
|
811
|
+
"SUBMIT",
|
|
812
|
+
"SUBMIT_CLEANUP",
|
|
813
|
+
`workflow run ${workflowContext.workflowRunId} deleted.`
|
|
814
|
+
);
|
|
815
|
+
return { deleted: true };
|
|
816
|
+
} catch (error) {
|
|
817
|
+
if (error instanceof import_qstash2.QstashError && error.status === 404) {
|
|
818
|
+
await debug?.log("WARN", "SUBMIT_CLEANUP", {
|
|
819
|
+
message: `Failed to remove workflow run ${workflowContext.workflowRunId} as it doesn't exist.`,
|
|
820
|
+
name: error.name,
|
|
821
|
+
errorMessage: error.message
|
|
822
|
+
});
|
|
823
|
+
return { deleted: false };
|
|
824
|
+
}
|
|
825
|
+
throw error;
|
|
826
|
+
}
|
|
732
827
|
};
|
|
733
828
|
var recreateUserHeaders = (headers) => {
|
|
734
829
|
const filteredHeaders = new Headers();
|
|
@@ -744,15 +839,32 @@ var recreateUserHeaders = (headers) => {
|
|
|
744
839
|
var handleThirdPartyCallResult = async (request, requestPayload, client, workflowUrl, failureUrl, retries, debug) => {
|
|
745
840
|
try {
|
|
746
841
|
if (request.headers.get("Upstash-Workflow-Callback")) {
|
|
747
|
-
|
|
842
|
+
let callbackPayload;
|
|
843
|
+
if (requestPayload) {
|
|
844
|
+
callbackPayload = requestPayload;
|
|
845
|
+
} else {
|
|
846
|
+
const workflowRunId2 = request.headers.get("upstash-workflow-runid");
|
|
847
|
+
const messageId = request.headers.get("upstash-message-id");
|
|
848
|
+
if (!workflowRunId2)
|
|
849
|
+
throw new WorkflowError("workflow run id missing in context.call lazy fetch.");
|
|
850
|
+
if (!messageId) throw new WorkflowError("message id missing in context.call lazy fetch.");
|
|
851
|
+
const steps = await getSteps(client.http, workflowRunId2, messageId, debug);
|
|
852
|
+
const failingStep = steps.find((step) => step.messageId === messageId);
|
|
853
|
+
if (!failingStep)
|
|
854
|
+
throw new WorkflowError(
|
|
855
|
+
"Failed to submit the context.call." + (steps.length === 0 ? "No steps found." : `No step was found with matching messageId ${messageId} out of ${steps.length} steps.`)
|
|
856
|
+
);
|
|
857
|
+
callbackPayload = atob(failingStep.body);
|
|
858
|
+
}
|
|
859
|
+
const callbackMessage = JSON.parse(callbackPayload);
|
|
748
860
|
if (!(callbackMessage.status >= 200 && callbackMessage.status < 300) && callbackMessage.maxRetries && callbackMessage.retried !== callbackMessage.maxRetries) {
|
|
749
861
|
await debug?.log("WARN", "SUBMIT_THIRD_PARTY_RESULT", {
|
|
750
862
|
status: callbackMessage.status,
|
|
751
|
-
body: atob(callbackMessage.body)
|
|
863
|
+
body: atob(callbackMessage.body ?? "")
|
|
752
864
|
});
|
|
753
865
|
console.warn(
|
|
754
866
|
`Workflow Warning: "context.call" failed with status ${callbackMessage.status} and will retry (retried ${callbackMessage.retried ?? 0} out of ${callbackMessage.maxRetries} times). Error Message:
|
|
755
|
-
${atob(callbackMessage.body)}`
|
|
867
|
+
${atob(callbackMessage.body ?? "")}`
|
|
756
868
|
);
|
|
757
869
|
return ok("call-will-retry");
|
|
758
870
|
}
|
|
@@ -786,7 +898,7 @@ ${atob(callbackMessage.body)}`
|
|
|
786
898
|
);
|
|
787
899
|
const callResponse = {
|
|
788
900
|
status: callbackMessage.status,
|
|
789
|
-
body: atob(callbackMessage.body),
|
|
901
|
+
body: atob(callbackMessage.body ?? ""),
|
|
790
902
|
header: callbackMessage.header
|
|
791
903
|
};
|
|
792
904
|
const callResultStep = {
|
|
@@ -817,9 +929,7 @@ ${atob(callbackMessage.body)}`
|
|
|
817
929
|
} catch (error) {
|
|
818
930
|
const isCallReturn = request.headers.get("Upstash-Workflow-Callback");
|
|
819
931
|
return err(
|
|
820
|
-
new
|
|
821
|
-
`Error when handling call return (isCallReturn=${isCallReturn}): ${error}`
|
|
822
|
-
)
|
|
932
|
+
new WorkflowError(`Error when handling call return (isCallReturn=${isCallReturn}): ${error}`)
|
|
823
933
|
);
|
|
824
934
|
}
|
|
825
935
|
};
|
|
@@ -827,7 +937,8 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
|
|
|
827
937
|
const baseHeaders = {
|
|
828
938
|
[WORKFLOW_INIT_HEADER]: initHeaderValue,
|
|
829
939
|
[WORKFLOW_ID_HEADER]: workflowRunId,
|
|
830
|
-
[WORKFLOW_URL_HEADER]: workflowUrl
|
|
940
|
+
[WORKFLOW_URL_HEADER]: workflowUrl,
|
|
941
|
+
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody"
|
|
831
942
|
};
|
|
832
943
|
if (!step?.callUrl) {
|
|
833
944
|
baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
@@ -840,8 +951,8 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
|
|
|
840
951
|
}
|
|
841
952
|
if (step?.callUrl) {
|
|
842
953
|
baseHeaders["Upstash-Retries"] = callRetries?.toString() ?? "0";
|
|
843
|
-
baseHeaders[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete";
|
|
844
|
-
if (retries) {
|
|
954
|
+
baseHeaders[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
|
|
955
|
+
if (retries !== void 0) {
|
|
845
956
|
baseHeaders["Upstash-Callback-Retries"] = retries.toString();
|
|
846
957
|
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
847
958
|
}
|
|
@@ -876,6 +987,7 @@ var getHeaders = (initHeaderValue, workflowRunId, workflowUrl, userHeaders, step
|
|
|
876
987
|
"Upstash-Callback-Workflow-CallType": "fromCallback",
|
|
877
988
|
"Upstash-Callback-Workflow-Init": "false",
|
|
878
989
|
"Upstash-Callback-Workflow-Url": workflowUrl,
|
|
990
|
+
"Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
|
|
879
991
|
"Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
|
|
880
992
|
"Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
|
|
881
993
|
"Upstash-Callback-Forward-Upstash-Workflow-StepName": step.stepName,
|
|
@@ -924,7 +1036,7 @@ var verifyRequest = async (body, signature, verifier) => {
|
|
|
924
1036
|
throw new Error("Signature in `Upstash-Signature` header is not valid");
|
|
925
1037
|
}
|
|
926
1038
|
} catch (error) {
|
|
927
|
-
throw new
|
|
1039
|
+
throw new WorkflowError(
|
|
928
1040
|
`Failed to verify that the Workflow request comes from QStash: ${error}
|
|
929
1041
|
|
|
930
1042
|
If signature is missing, trigger the workflow endpoint by publishing your request to QStash instead of calling it directly.
|
|
@@ -964,14 +1076,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
964
1076
|
*
|
|
965
1077
|
* If a function is already executing (this.executingStep), this
|
|
966
1078
|
* means that there is a nested step which is not allowed. In this
|
|
967
|
-
* case, addStep throws
|
|
1079
|
+
* case, addStep throws WorkflowError.
|
|
968
1080
|
*
|
|
969
1081
|
* @param stepInfo step plan to add
|
|
970
1082
|
* @returns result of the step function
|
|
971
1083
|
*/
|
|
972
1084
|
async addStep(stepInfo) {
|
|
973
1085
|
if (this.executingStep) {
|
|
974
|
-
throw new
|
|
1086
|
+
throw new WorkflowError(
|
|
975
1087
|
`A step can not be run inside another step. Tried to run '${stepInfo.stepName}' inside '${this.executingStep}'`
|
|
976
1088
|
);
|
|
977
1089
|
}
|
|
@@ -1056,7 +1168,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1056
1168
|
const sortedSteps = sortSteps(this.steps);
|
|
1057
1169
|
const plannedParallelStepCount = sortedSteps[initialStepCount + this.planStepCount]?.concurrent;
|
|
1058
1170
|
if (parallelCallState !== "first" && plannedParallelStepCount !== parallelSteps.length) {
|
|
1059
|
-
throw new
|
|
1171
|
+
throw new WorkflowError(
|
|
1060
1172
|
`Incompatible number of parallel steps when call state was '${parallelCallState}'. Expected ${parallelSteps.length}, got ${plannedParallelStepCount} from the request.`
|
|
1061
1173
|
);
|
|
1062
1174
|
}
|
|
@@ -1078,7 +1190,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1078
1190
|
case "partial": {
|
|
1079
1191
|
const planStep = this.steps.at(-1);
|
|
1080
1192
|
if (!planStep || planStep.targetStep === void 0) {
|
|
1081
|
-
throw new
|
|
1193
|
+
throw new WorkflowError(
|
|
1082
1194
|
`There must be a last step and it should have targetStep larger than 0.Received: ${JSON.stringify(planStep)}`
|
|
1083
1195
|
);
|
|
1084
1196
|
}
|
|
@@ -1092,17 +1204,17 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1092
1204
|
);
|
|
1093
1205
|
await this.submitStepsToQStash([resultStep], [parallelStep]);
|
|
1094
1206
|
} catch (error) {
|
|
1095
|
-
if (error instanceof
|
|
1207
|
+
if (error instanceof WorkflowAbort) {
|
|
1096
1208
|
throw error;
|
|
1097
1209
|
}
|
|
1098
|
-
throw new
|
|
1210
|
+
throw new WorkflowError(
|
|
1099
1211
|
`Error submitting steps to QStash in partial parallel step execution: ${error}`
|
|
1100
1212
|
);
|
|
1101
1213
|
}
|
|
1102
1214
|
break;
|
|
1103
1215
|
}
|
|
1104
1216
|
case "discard": {
|
|
1105
|
-
throw new
|
|
1217
|
+
throw new WorkflowAbort("discarded parallel");
|
|
1106
1218
|
}
|
|
1107
1219
|
case "last": {
|
|
1108
1220
|
const parallelResultSteps = sortedSteps.filter((step) => step.stepId >= initialStepCount).slice(0, parallelSteps.length);
|
|
@@ -1153,7 +1265,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1153
1265
|
*/
|
|
1154
1266
|
async submitStepsToQStash(steps, lazySteps) {
|
|
1155
1267
|
if (steps.length === 0) {
|
|
1156
|
-
throw new
|
|
1268
|
+
throw new WorkflowError(
|
|
1157
1269
|
`Unable to submit steps to QStash. Provided list is empty. Current step: ${this.stepCount}`
|
|
1158
1270
|
);
|
|
1159
1271
|
}
|
|
@@ -1193,7 +1305,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1193
1305
|
method: "POST",
|
|
1194
1306
|
parseResponseAsJson: false
|
|
1195
1307
|
});
|
|
1196
|
-
throw new
|
|
1308
|
+
throw new WorkflowAbort(steps[0].stepName, steps[0]);
|
|
1197
1309
|
}
|
|
1198
1310
|
const result = await this.context.qstashClient.batchJSON(
|
|
1199
1311
|
steps.map((singleStep, index) => {
|
|
@@ -1245,7 +1357,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1245
1357
|
};
|
|
1246
1358
|
})
|
|
1247
1359
|
});
|
|
1248
|
-
throw new
|
|
1360
|
+
throw new WorkflowAbort(steps[0].stepName, steps[0]);
|
|
1249
1361
|
}
|
|
1250
1362
|
/**
|
|
1251
1363
|
* Get the promise by executing the lazt steps list. If there is a single
|
|
@@ -1270,7 +1382,7 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1270
1382
|
} else if (Array.isArray(result) && lazyStepList.length === result.length && index < lazyStepList.length) {
|
|
1271
1383
|
return result[index];
|
|
1272
1384
|
} else {
|
|
1273
|
-
throw new
|
|
1385
|
+
throw new WorkflowError(
|
|
1274
1386
|
`Unexpected parallel call result while executing step ${index}: '${result}'. Expected ${lazyStepList.length} many items`
|
|
1275
1387
|
);
|
|
1276
1388
|
}
|
|
@@ -1282,12 +1394,12 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1282
1394
|
};
|
|
1283
1395
|
var validateStep = (lazyStep, stepFromRequest) => {
|
|
1284
1396
|
if (lazyStep.stepName !== stepFromRequest.stepName) {
|
|
1285
|
-
throw new
|
|
1397
|
+
throw new WorkflowError(
|
|
1286
1398
|
`Incompatible step name. Expected '${lazyStep.stepName}', got '${stepFromRequest.stepName}' from the request`
|
|
1287
1399
|
);
|
|
1288
1400
|
}
|
|
1289
1401
|
if (lazyStep.stepType !== stepFromRequest.stepType) {
|
|
1290
|
-
throw new
|
|
1402
|
+
throw new WorkflowError(
|
|
1291
1403
|
`Incompatible step type. Expected '${lazyStep.stepType}', got '${stepFromRequest.stepType}' from the request`
|
|
1292
1404
|
);
|
|
1293
1405
|
}
|
|
@@ -1298,12 +1410,12 @@ var validateParallelSteps = (lazySteps, stepsFromRequest) => {
|
|
|
1298
1410
|
validateStep(lazySteps[index], stepFromRequest);
|
|
1299
1411
|
}
|
|
1300
1412
|
} catch (error) {
|
|
1301
|
-
if (error instanceof
|
|
1413
|
+
if (error instanceof WorkflowError) {
|
|
1302
1414
|
const lazyStepNames = lazySteps.map((lazyStep) => lazyStep.stepName);
|
|
1303
1415
|
const lazyStepTypes = lazySteps.map((lazyStep) => lazyStep.stepType);
|
|
1304
1416
|
const requestStepNames = stepsFromRequest.map((step) => step.stepName);
|
|
1305
1417
|
const requestStepTypes = stepsFromRequest.map((step) => step.stepType);
|
|
1306
|
-
throw new
|
|
1418
|
+
throw new WorkflowError(
|
|
1307
1419
|
`Incompatible steps detected in parallel execution: ${error.message}
|
|
1308
1420
|
> Step Names from the request: ${JSON.stringify(requestStepNames)}
|
|
1309
1421
|
Step Types from the request: ${JSON.stringify(requestStepTypes)}
|
|
@@ -1416,10 +1528,6 @@ var WorkflowContext = class {
|
|
|
1416
1528
|
* headers of the initial request
|
|
1417
1529
|
*/
|
|
1418
1530
|
headers;
|
|
1419
|
-
/**
|
|
1420
|
-
* initial payload as a raw string
|
|
1421
|
-
*/
|
|
1422
|
-
rawInitialPayload;
|
|
1423
1531
|
/**
|
|
1424
1532
|
* Map of environment variables and their values.
|
|
1425
1533
|
*
|
|
@@ -1454,7 +1562,6 @@ var WorkflowContext = class {
|
|
|
1454
1562
|
failureUrl,
|
|
1455
1563
|
debug,
|
|
1456
1564
|
initialPayload,
|
|
1457
|
-
rawInitialPayload,
|
|
1458
1565
|
env,
|
|
1459
1566
|
retries
|
|
1460
1567
|
}) {
|
|
@@ -1465,7 +1572,6 @@ var WorkflowContext = class {
|
|
|
1465
1572
|
this.failureUrl = failureUrl;
|
|
1466
1573
|
this.headers = headers;
|
|
1467
1574
|
this.requestPayload = initialPayload;
|
|
1468
|
-
this.rawInitialPayload = rawInitialPayload ?? JSON.stringify(this.requestPayload);
|
|
1469
1575
|
this.env = env ?? {};
|
|
1470
1576
|
this.retries = retries ?? DEFAULT_RETRIES;
|
|
1471
1577
|
this.executor = new AutoExecutor(this, this.steps, debug);
|
|
@@ -1486,7 +1592,7 @@ var WorkflowContext = class {
|
|
|
1486
1592
|
* const [result1, result2] = await Promise.all([
|
|
1487
1593
|
* context.run("step 1", () => {
|
|
1488
1594
|
* return "result1"
|
|
1489
|
-
* })
|
|
1595
|
+
* }),
|
|
1490
1596
|
* context.run("step 2", async () => {
|
|
1491
1597
|
* return await fetchResults()
|
|
1492
1598
|
* })
|
|
@@ -1504,6 +1610,10 @@ var WorkflowContext = class {
|
|
|
1504
1610
|
/**
|
|
1505
1611
|
* Stops the execution for the duration provided.
|
|
1506
1612
|
*
|
|
1613
|
+
* ```typescript
|
|
1614
|
+
* await context.sleep('sleep1', 3) // wait for three seconds
|
|
1615
|
+
* ```
|
|
1616
|
+
*
|
|
1507
1617
|
* @param stepName
|
|
1508
1618
|
* @param duration sleep duration in seconds
|
|
1509
1619
|
* @returns undefined
|
|
@@ -1514,6 +1624,10 @@ var WorkflowContext = class {
|
|
|
1514
1624
|
/**
|
|
1515
1625
|
* Stops the execution until the date time provided.
|
|
1516
1626
|
*
|
|
1627
|
+
* ```typescript
|
|
1628
|
+
* await context.sleepUntil('sleep1', Date.now() / 1000 + 3) // wait for three seconds
|
|
1629
|
+
* ```
|
|
1630
|
+
*
|
|
1517
1631
|
* @param stepName
|
|
1518
1632
|
* @param datetime time to sleep until. Can be provided as a number (in unix seconds),
|
|
1519
1633
|
* as a Date object or a string (passed to `new Date(datetimeString)`)
|
|
@@ -1537,7 +1651,7 @@ var WorkflowContext = class {
|
|
|
1537
1651
|
* const { status, body } = await context.call<string>(
|
|
1538
1652
|
* "post call step",
|
|
1539
1653
|
* {
|
|
1540
|
-
* url:
|
|
1654
|
+
* url: "https://www.some-endpoint.com/api",
|
|
1541
1655
|
* method: "POST",
|
|
1542
1656
|
* body: "my-payload"
|
|
1543
1657
|
* }
|
|
@@ -1591,45 +1705,43 @@ var WorkflowContext = class {
|
|
|
1591
1705
|
}
|
|
1592
1706
|
}
|
|
1593
1707
|
/**
|
|
1594
|
-
*
|
|
1595
|
-
* timeout ends
|
|
1708
|
+
* Pauses workflow execution until a specific event occurs or a timeout is reached.
|
|
1596
1709
|
*
|
|
1597
|
-
|
|
1598
|
-
* const
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
1601
|
-
|
|
1602
|
-
* );
|
|
1603
|
-
* ```
|
|
1710
|
+
*```ts
|
|
1711
|
+
* const result = await workflow.waitForEvent("payment-confirmed", {
|
|
1712
|
+
* timeout: "5m"
|
|
1713
|
+
* });
|
|
1714
|
+
*```
|
|
1604
1715
|
*
|
|
1605
|
-
* To notify a waiting workflow
|
|
1716
|
+
* To notify a waiting workflow:
|
|
1606
1717
|
*
|
|
1607
1718
|
* ```ts
|
|
1608
1719
|
* import { Client } from "@upstash/workflow";
|
|
1609
1720
|
*
|
|
1610
|
-
* const client = new Client({ token: });
|
|
1721
|
+
* const client = new Client({ token: "<QSTASH_TOKEN>" });
|
|
1611
1722
|
*
|
|
1612
1723
|
* await client.notify({
|
|
1613
|
-
* eventId: "
|
|
1614
|
-
*
|
|
1724
|
+
* eventId: "payment.confirmed",
|
|
1725
|
+
* data: {
|
|
1726
|
+
* amount: 99.99,
|
|
1727
|
+
* currency: "USD"
|
|
1728
|
+
* }
|
|
1615
1729
|
* })
|
|
1616
1730
|
* ```
|
|
1617
1731
|
*
|
|
1732
|
+
* Alternatively, you can use the `context.notify` method.
|
|
1733
|
+
*
|
|
1618
1734
|
* @param stepName
|
|
1619
|
-
* @param eventId
|
|
1620
|
-
* @param
|
|
1621
|
-
* @returns
|
|
1622
|
-
* timeout
|
|
1623
|
-
* is the
|
|
1735
|
+
* @param eventId - Unique identifier for the event to wait for
|
|
1736
|
+
* @param options - Configuration options.
|
|
1737
|
+
* @returns `{ timeout: boolean, eventData: unknown }`.
|
|
1738
|
+
* The `timeout` property specifies if the workflow has timed out. The `eventData`
|
|
1739
|
+
* is the data passed when notifying this workflow of an event.
|
|
1624
1740
|
*/
|
|
1625
|
-
async waitForEvent(stepName, eventId,
|
|
1626
|
-
const
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
eventId,
|
|
1630
|
-
typeof timeout === "string" ? timeout : `${timeout}s`
|
|
1631
|
-
)
|
|
1632
|
-
);
|
|
1741
|
+
async waitForEvent(stepName, eventId, options = {}) {
|
|
1742
|
+
const { timeout = "7d" } = options;
|
|
1743
|
+
const timeoutStr = typeof timeout === "string" ? timeout : `${timeout}s`;
|
|
1744
|
+
const result = await this.addStep(new LazyWaitForEventStep(stepName, eventId, timeoutStr));
|
|
1633
1745
|
try {
|
|
1634
1746
|
return {
|
|
1635
1747
|
...result,
|
|
@@ -1639,6 +1751,27 @@ var WorkflowContext = class {
|
|
|
1639
1751
|
return result;
|
|
1640
1752
|
}
|
|
1641
1753
|
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Notify workflow runs waiting for an event
|
|
1756
|
+
*
|
|
1757
|
+
* ```ts
|
|
1758
|
+
* const { eventId, eventData, notifyResponse } = await context.notify(
|
|
1759
|
+
* "notify step", "event-id", "event-data"
|
|
1760
|
+
* );
|
|
1761
|
+
* ```
|
|
1762
|
+
*
|
|
1763
|
+
* Upon `context.notify`, the workflow runs waiting for the given eventId (context.waitForEvent)
|
|
1764
|
+
* will receive the given event data and resume execution.
|
|
1765
|
+
*
|
|
1766
|
+
* The response includes the same eventId and eventData. Additionally, there is
|
|
1767
|
+
* a notifyResponse field which contains a list of `Waiter` objects, each corresponding
|
|
1768
|
+
* to a notified workflow run.
|
|
1769
|
+
*
|
|
1770
|
+
* @param stepName
|
|
1771
|
+
* @param eventId event id to notify
|
|
1772
|
+
* @param eventData event data to notify with
|
|
1773
|
+
* @returns notify response which has event id, event data and list of waiters which were notified
|
|
1774
|
+
*/
|
|
1642
1775
|
async notify(stepName, eventId, eventData) {
|
|
1643
1776
|
const result = await this.addStep(
|
|
1644
1777
|
new LazyNotifyStep(stepName, eventId, eventData, this.qstashClient.http)
|
|
@@ -1652,6 +1785,15 @@ var WorkflowContext = class {
|
|
|
1652
1785
|
return result;
|
|
1653
1786
|
}
|
|
1654
1787
|
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Cancel the current workflow run
|
|
1790
|
+
*
|
|
1791
|
+
* Will throw WorkflowAbort to stop workflow execution.
|
|
1792
|
+
* Shouldn't be inside try/catch.
|
|
1793
|
+
*/
|
|
1794
|
+
async cancel() {
|
|
1795
|
+
throw new WorkflowAbort("cancel", void 0, true);
|
|
1796
|
+
}
|
|
1655
1797
|
/**
|
|
1656
1798
|
* Adds steps to the executor. Needed so that it can be overwritten in
|
|
1657
1799
|
* DisabledWorkflowContext.
|
|
@@ -1692,7 +1834,8 @@ var WorkflowLogger = class _WorkflowLogger {
|
|
|
1692
1834
|
}
|
|
1693
1835
|
writeToConsole(logEntry) {
|
|
1694
1836
|
const JSON_SPACING = 2;
|
|
1695
|
-
console.
|
|
1837
|
+
const logMethod = logEntry.logLevel === "ERROR" ? console.error : logEntry.logLevel === "WARN" ? console.warn : console.log;
|
|
1838
|
+
logMethod(JSON.stringify(logEntry, void 0, JSON_SPACING));
|
|
1696
1839
|
}
|
|
1697
1840
|
shouldLog(level) {
|
|
1698
1841
|
return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.options.logLevel);
|
|
@@ -1734,6 +1877,63 @@ function decodeBase64(base64) {
|
|
|
1734
1877
|
}
|
|
1735
1878
|
}
|
|
1736
1879
|
|
|
1880
|
+
// src/serve/authorization.ts
|
|
1881
|
+
var import_qstash3 = require("@upstash/qstash");
|
|
1882
|
+
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
1883
|
+
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
1884
|
+
/**
|
|
1885
|
+
* overwrite the WorkflowContext.addStep method to always raise WorkflowAbort
|
|
1886
|
+
* error in order to stop the execution whenever we encounter a step.
|
|
1887
|
+
*
|
|
1888
|
+
* @param _step
|
|
1889
|
+
*/
|
|
1890
|
+
async addStep(_step) {
|
|
1891
|
+
throw new WorkflowAbort(_DisabledWorkflowContext.disabledMessage);
|
|
1892
|
+
}
|
|
1893
|
+
/**
|
|
1894
|
+
* overwrite cancel method to do nothing
|
|
1895
|
+
*/
|
|
1896
|
+
async cancel() {
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
/**
|
|
1900
|
+
* copies the passed context to create a DisabledWorkflowContext. Then, runs the
|
|
1901
|
+
* route function with the new context.
|
|
1902
|
+
*
|
|
1903
|
+
* - returns "run-ended" if there are no steps found or
|
|
1904
|
+
* if the auth failed and user called `return`
|
|
1905
|
+
* - returns "step-found" if DisabledWorkflowContext.addStep is called.
|
|
1906
|
+
* - if there is another error, returns the error.
|
|
1907
|
+
*
|
|
1908
|
+
* @param routeFunction
|
|
1909
|
+
*/
|
|
1910
|
+
static async tryAuthentication(routeFunction, context) {
|
|
1911
|
+
const disabledContext = new _DisabledWorkflowContext({
|
|
1912
|
+
qstashClient: new import_qstash3.Client({
|
|
1913
|
+
baseUrl: "disabled-client",
|
|
1914
|
+
token: "disabled-client"
|
|
1915
|
+
}),
|
|
1916
|
+
workflowRunId: context.workflowRunId,
|
|
1917
|
+
headers: context.headers,
|
|
1918
|
+
steps: [],
|
|
1919
|
+
url: context.url,
|
|
1920
|
+
failureUrl: context.failureUrl,
|
|
1921
|
+
initialPayload: context.requestPayload,
|
|
1922
|
+
env: context.env,
|
|
1923
|
+
retries: context.retries
|
|
1924
|
+
});
|
|
1925
|
+
try {
|
|
1926
|
+
await routeFunction(disabledContext);
|
|
1927
|
+
} catch (error) {
|
|
1928
|
+
if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage) {
|
|
1929
|
+
return ok("step-found");
|
|
1930
|
+
}
|
|
1931
|
+
return err(error);
|
|
1932
|
+
}
|
|
1933
|
+
return ok("run-ended");
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1737
1937
|
// src/workflow-parser.ts
|
|
1738
1938
|
var getPayload = async (request) => {
|
|
1739
1939
|
try {
|
|
@@ -1742,8 +1942,8 @@ var getPayload = async (request) => {
|
|
|
1742
1942
|
return;
|
|
1743
1943
|
}
|
|
1744
1944
|
};
|
|
1745
|
-
var
|
|
1746
|
-
const [encodedInitialPayload, ...encodedSteps] =
|
|
1945
|
+
var processRawSteps = (rawSteps) => {
|
|
1946
|
+
const [encodedInitialPayload, ...encodedSteps] = rawSteps;
|
|
1747
1947
|
const rawInitialPayload = decodeBase64(encodedInitialPayload.body);
|
|
1748
1948
|
const initialStep = {
|
|
1749
1949
|
stepId: 0,
|
|
@@ -1753,27 +1953,21 @@ var parsePayload = async (rawPayload, debug) => {
|
|
|
1753
1953
|
concurrent: NO_CONCURRENCY
|
|
1754
1954
|
};
|
|
1755
1955
|
const stepsToDecode = encodedSteps.filter((step) => step.callType === "step");
|
|
1756
|
-
const otherSteps =
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
};
|
|
1772
|
-
step.out = newOut;
|
|
1773
|
-
}
|
|
1774
|
-
return step;
|
|
1775
|
-
})
|
|
1776
|
-
);
|
|
1956
|
+
const otherSteps = stepsToDecode.map((rawStep) => {
|
|
1957
|
+
const step = JSON.parse(decodeBase64(rawStep.body));
|
|
1958
|
+
try {
|
|
1959
|
+
step.out = JSON.parse(step.out);
|
|
1960
|
+
} catch {
|
|
1961
|
+
}
|
|
1962
|
+
if (step.waitEventId) {
|
|
1963
|
+
const newOut = {
|
|
1964
|
+
eventData: step.out ? decodeBase64(step.out) : void 0,
|
|
1965
|
+
timeout: step.waitTimeout ?? false
|
|
1966
|
+
};
|
|
1967
|
+
step.out = newOut;
|
|
1968
|
+
}
|
|
1969
|
+
return step;
|
|
1970
|
+
});
|
|
1777
1971
|
const steps = [initialStep, ...otherSteps];
|
|
1778
1972
|
return {
|
|
1779
1973
|
rawInitialPayload,
|
|
@@ -1821,20 +2015,20 @@ var validateRequest = (request) => {
|
|
|
1821
2015
|
const versionHeader = request.headers.get(WORKFLOW_PROTOCOL_VERSION_HEADER);
|
|
1822
2016
|
const isFirstInvocation = !versionHeader;
|
|
1823
2017
|
if (!isFirstInvocation && versionHeader !== WORKFLOW_PROTOCOL_VERSION) {
|
|
1824
|
-
throw new
|
|
2018
|
+
throw new WorkflowError(
|
|
1825
2019
|
`Incompatible workflow sdk protocol version. Expected ${WORKFLOW_PROTOCOL_VERSION}, got ${versionHeader} from the request.`
|
|
1826
2020
|
);
|
|
1827
2021
|
}
|
|
1828
2022
|
const workflowRunId = isFirstInvocation ? getWorkflowRunId() : request.headers.get(WORKFLOW_ID_HEADER) ?? "";
|
|
1829
2023
|
if (workflowRunId.length === 0) {
|
|
1830
|
-
throw new
|
|
2024
|
+
throw new WorkflowError("Couldn't get workflow id from header");
|
|
1831
2025
|
}
|
|
1832
2026
|
return {
|
|
1833
2027
|
isFirstInvocation,
|
|
1834
2028
|
workflowRunId
|
|
1835
2029
|
};
|
|
1836
2030
|
};
|
|
1837
|
-
var parseRequest = async (requestPayload, isFirstInvocation, debug) => {
|
|
2031
|
+
var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requester, messageId, debug) => {
|
|
1838
2032
|
if (isFirstInvocation) {
|
|
1839
2033
|
return {
|
|
1840
2034
|
rawInitialPayload: requestPayload ?? "",
|
|
@@ -1842,10 +2036,18 @@ var parseRequest = async (requestPayload, isFirstInvocation, debug) => {
|
|
|
1842
2036
|
isLastDuplicate: false
|
|
1843
2037
|
};
|
|
1844
2038
|
} else {
|
|
2039
|
+
let rawSteps;
|
|
1845
2040
|
if (!requestPayload) {
|
|
1846
|
-
|
|
2041
|
+
await debug?.log(
|
|
2042
|
+
"INFO",
|
|
2043
|
+
"ENDPOINT_START",
|
|
2044
|
+
"request payload is empty, steps will be fetched from QStash."
|
|
2045
|
+
);
|
|
2046
|
+
rawSteps = await getSteps(requester, workflowRunId, messageId, debug);
|
|
2047
|
+
} else {
|
|
2048
|
+
rawSteps = JSON.parse(requestPayload);
|
|
1847
2049
|
}
|
|
1848
|
-
const { rawInitialPayload, steps } =
|
|
2050
|
+
const { rawInitialPayload, steps } = processRawSteps(rawSteps);
|
|
1849
2051
|
const isLastDuplicate = await checkIfLastOneIsDuplicate(steps, debug);
|
|
1850
2052
|
const deduplicatedSteps = deduplicateSteps(steps);
|
|
1851
2053
|
return {
|
|
@@ -1855,13 +2057,13 @@ var parseRequest = async (requestPayload, isFirstInvocation, debug) => {
|
|
|
1855
2057
|
};
|
|
1856
2058
|
}
|
|
1857
2059
|
};
|
|
1858
|
-
var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, failureFunction, debug) => {
|
|
2060
|
+
var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, debug) => {
|
|
1859
2061
|
if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
|
|
1860
2062
|
return ok("not-failure-callback");
|
|
1861
2063
|
}
|
|
1862
2064
|
if (!failureFunction) {
|
|
1863
2065
|
return err(
|
|
1864
|
-
new
|
|
2066
|
+
new WorkflowError(
|
|
1865
2067
|
"Workflow endpoint is called to handle a failure, but a failureFunction is not provided in serve options. Either provide a failureUrl or a failureFunction."
|
|
1866
2068
|
)
|
|
1867
2069
|
);
|
|
@@ -1872,92 +2074,48 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
1872
2074
|
);
|
|
1873
2075
|
const decodedBody = body ? decodeBase64(body) : "{}";
|
|
1874
2076
|
const errorPayload = JSON.parse(decodedBody);
|
|
1875
|
-
const {
|
|
1876
|
-
rawInitialPayload,
|
|
1877
|
-
steps,
|
|
1878
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1879
|
-
isLastDuplicate: _isLastDuplicate
|
|
1880
|
-
} = await parseRequest(decodeBase64(sourceBody), false, debug);
|
|
1881
2077
|
const workflowContext = new WorkflowContext({
|
|
1882
2078
|
qstashClient,
|
|
1883
2079
|
workflowRunId,
|
|
1884
|
-
initialPayload: initialPayloadParser(
|
|
1885
|
-
rawInitialPayload,
|
|
2080
|
+
initialPayload: initialPayloadParser(decodeBase64(sourceBody)),
|
|
1886
2081
|
headers: recreateUserHeaders(new Headers(sourceHeader)),
|
|
1887
|
-
steps,
|
|
2082
|
+
steps: [],
|
|
1888
2083
|
url,
|
|
1889
2084
|
failureUrl: url,
|
|
1890
2085
|
debug
|
|
1891
2086
|
});
|
|
1892
|
-
|
|
2087
|
+
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
2088
|
+
routeFunction,
|
|
2089
|
+
workflowContext
|
|
2090
|
+
);
|
|
2091
|
+
if (authCheck.isErr()) {
|
|
2092
|
+
await debug?.log("ERROR", "ERROR", { error: authCheck.error.message });
|
|
2093
|
+
throw authCheck.error;
|
|
2094
|
+
} else if (authCheck.value === "run-ended") {
|
|
2095
|
+
return err(new WorkflowError("Not authorized to run the failure function."));
|
|
2096
|
+
}
|
|
2097
|
+
await failureFunction({
|
|
2098
|
+
context: workflowContext,
|
|
2099
|
+
failStatus: status,
|
|
2100
|
+
failResponse: errorPayload.message,
|
|
2101
|
+
failHeaders: header
|
|
2102
|
+
});
|
|
1893
2103
|
} catch (error) {
|
|
1894
2104
|
return err(error);
|
|
1895
2105
|
}
|
|
1896
2106
|
return ok("is-failure-callback");
|
|
1897
2107
|
};
|
|
1898
2108
|
|
|
1899
|
-
// src/serve/authorization.ts
|
|
1900
|
-
var import_qstash2 = require("@upstash/qstash");
|
|
1901
|
-
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
1902
|
-
static disabledMessage = "disabled-qstash-worklfow-run";
|
|
1903
|
-
/**
|
|
1904
|
-
* overwrite the WorkflowContext.addStep method to always raise QStashWorkflowAbort
|
|
1905
|
-
* error in order to stop the execution whenever we encounter a step.
|
|
1906
|
-
*
|
|
1907
|
-
* @param _step
|
|
1908
|
-
*/
|
|
1909
|
-
async addStep(_step) {
|
|
1910
|
-
throw new QStashWorkflowAbort(_DisabledWorkflowContext.disabledMessage);
|
|
1911
|
-
}
|
|
1912
|
-
/**
|
|
1913
|
-
* copies the passed context to create a DisabledWorkflowContext. Then, runs the
|
|
1914
|
-
* route function with the new context.
|
|
1915
|
-
*
|
|
1916
|
-
* - returns "run-ended" if there are no steps found or
|
|
1917
|
-
* if the auth failed and user called `return`
|
|
1918
|
-
* - returns "step-found" if DisabledWorkflowContext.addStep is called.
|
|
1919
|
-
* - if there is another error, returns the error.
|
|
1920
|
-
*
|
|
1921
|
-
* @param routeFunction
|
|
1922
|
-
*/
|
|
1923
|
-
static async tryAuthentication(routeFunction, context) {
|
|
1924
|
-
const disabledContext = new _DisabledWorkflowContext({
|
|
1925
|
-
qstashClient: new import_qstash2.Client({
|
|
1926
|
-
baseUrl: "disabled-client",
|
|
1927
|
-
token: "disabled-client"
|
|
1928
|
-
}),
|
|
1929
|
-
workflowRunId: context.workflowRunId,
|
|
1930
|
-
headers: context.headers,
|
|
1931
|
-
steps: [],
|
|
1932
|
-
url: context.url,
|
|
1933
|
-
failureUrl: context.failureUrl,
|
|
1934
|
-
initialPayload: context.requestPayload,
|
|
1935
|
-
rawInitialPayload: context.rawInitialPayload,
|
|
1936
|
-
env: context.env,
|
|
1937
|
-
retries: context.retries
|
|
1938
|
-
});
|
|
1939
|
-
try {
|
|
1940
|
-
await routeFunction(disabledContext);
|
|
1941
|
-
} catch (error) {
|
|
1942
|
-
if (error instanceof QStashWorkflowAbort && error.stepName === this.disabledMessage) {
|
|
1943
|
-
return ok("step-found");
|
|
1944
|
-
}
|
|
1945
|
-
return err(error);
|
|
1946
|
-
}
|
|
1947
|
-
return ok("run-ended");
|
|
1948
|
-
}
|
|
1949
|
-
};
|
|
1950
|
-
|
|
1951
2109
|
// src/serve/options.ts
|
|
1952
|
-
var import_qstash3 = require("@upstash/qstash");
|
|
1953
2110
|
var import_qstash4 = require("@upstash/qstash");
|
|
2111
|
+
var import_qstash5 = require("@upstash/qstash");
|
|
1954
2112
|
var processOptions = (options) => {
|
|
1955
2113
|
const environment = options?.env ?? (typeof process === "undefined" ? {} : process.env);
|
|
1956
2114
|
const receiverEnvironmentVariablesSet = Boolean(
|
|
1957
2115
|
environment.QSTASH_CURRENT_SIGNING_KEY && environment.QSTASH_NEXT_SIGNING_KEY
|
|
1958
2116
|
);
|
|
1959
2117
|
return {
|
|
1960
|
-
qstashClient: new
|
|
2118
|
+
qstashClient: new import_qstash5.Client({
|
|
1961
2119
|
baseUrl: environment.QSTASH_URL,
|
|
1962
2120
|
token: environment.QSTASH_TOKEN
|
|
1963
2121
|
}),
|
|
@@ -1978,7 +2136,7 @@ var processOptions = (options) => {
|
|
|
1978
2136
|
throw error;
|
|
1979
2137
|
}
|
|
1980
2138
|
},
|
|
1981
|
-
receiver: receiverEnvironmentVariablesSet ? new
|
|
2139
|
+
receiver: receiverEnvironmentVariablesSet ? new import_qstash4.Receiver({
|
|
1982
2140
|
currentSigningKey: environment.QSTASH_CURRENT_SIGNING_KEY,
|
|
1983
2141
|
nextSigningKey: environment.QSTASH_NEXT_SIGNING_KEY
|
|
1984
2142
|
}) : void 0,
|
|
@@ -2040,6 +2198,9 @@ var serve = (routeFunction, options) => {
|
|
|
2040
2198
|
const { rawInitialPayload, steps, isLastDuplicate } = await parseRequest(
|
|
2041
2199
|
requestPayload,
|
|
2042
2200
|
isFirstInvocation,
|
|
2201
|
+
workflowRunId,
|
|
2202
|
+
qstashClient.http,
|
|
2203
|
+
request.headers.get("upstash-message-id"),
|
|
2043
2204
|
debug
|
|
2044
2205
|
);
|
|
2045
2206
|
if (isLastDuplicate) {
|
|
@@ -2050,6 +2211,7 @@ var serve = (routeFunction, options) => {
|
|
|
2050
2211
|
requestPayload,
|
|
2051
2212
|
qstashClient,
|
|
2052
2213
|
initialPayloadParser,
|
|
2214
|
+
routeFunction,
|
|
2053
2215
|
failureFunction
|
|
2054
2216
|
);
|
|
2055
2217
|
if (failureCheck.isErr()) {
|
|
@@ -2062,7 +2224,6 @@ var serve = (routeFunction, options) => {
|
|
|
2062
2224
|
qstashClient,
|
|
2063
2225
|
workflowRunId,
|
|
2064
2226
|
initialPayload: initialPayloadParser(rawInitialPayload),
|
|
2065
|
-
rawInitialPayload,
|
|
2066
2227
|
headers: recreateUserHeaders(request.headers),
|
|
2067
2228
|
steps,
|
|
2068
2229
|
url: workflowUrl,
|
|
@@ -2100,7 +2261,11 @@ var serve = (routeFunction, options) => {
|
|
|
2100
2261
|
onStep: async () => routeFunction(workflowContext),
|
|
2101
2262
|
onCleanup: async () => {
|
|
2102
2263
|
await triggerWorkflowDelete(workflowContext, debug);
|
|
2103
|
-
}
|
|
2264
|
+
},
|
|
2265
|
+
onCancel: async () => {
|
|
2266
|
+
await makeCancelRequest(workflowContext.qstashClient.http, workflowRunId);
|
|
2267
|
+
},
|
|
2268
|
+
debug
|
|
2104
2269
|
});
|
|
2105
2270
|
if (result.isErr()) {
|
|
2106
2271
|
await debug?.log("ERROR", "ERROR", { error: result.error.message });
|
|
@@ -2126,7 +2291,7 @@ var serve = (routeFunction, options) => {
|
|
|
2126
2291
|
};
|
|
2127
2292
|
|
|
2128
2293
|
// src/client/index.ts
|
|
2129
|
-
var
|
|
2294
|
+
var import_qstash6 = require("@upstash/qstash");
|
|
2130
2295
|
|
|
2131
2296
|
// platforms/astro.ts
|
|
2132
2297
|
function serve2(routeFunction, options) {
|