@upstash/workflow 0.2.8 → 0.2.10-hono-generics
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 +8 -3
- package/astro.d.ts +8 -3
- package/astro.js +393 -82
- package/astro.mjs +36 -8
- package/{chunk-BPUSHNSD.mjs → chunk-IPXJZU3K.mjs} +1226 -943
- package/cloudflare.d.mts +9 -4
- package/cloudflare.d.ts +9 -4
- package/cloudflare.js +392 -88
- package/cloudflare.mjs +35 -14
- package/express.d.mts +7 -3
- package/express.d.ts +7 -3
- package/express.js +400 -92
- package/express.mjs +43 -18
- package/h3.d.mts +9 -7
- package/h3.d.ts +9 -7
- package/h3.js +397 -95
- package/h3.mjs +40 -21
- package/hono.d.mts +10 -4
- package/hono.d.ts +10 -4
- package/hono.js +391 -90
- package/hono.mjs +34 -16
- package/index.d.mts +47 -33
- package/index.d.ts +47 -33
- package/index.js +315 -92
- package/index.mjs +32 -30
- package/nextjs.d.mts +14 -5
- package/nextjs.d.ts +14 -5
- package/nextjs.js +408 -77
- package/nextjs.mjs +63 -17
- package/package.json +1 -1
- package/serve-many-BVDpPsF-.d.mts +13 -0
- package/serve-many-e4zufyXN.d.ts +13 -0
- package/solidjs.d.mts +3 -3
- package/solidjs.d.ts +3 -3
- package/solidjs.js +289 -71
- package/solidjs.mjs +7 -10
- package/svelte.d.mts +13 -6
- package/svelte.d.ts +13 -6
- package/svelte.js +391 -88
- package/svelte.mjs +34 -14
- package/{types-B62AnIU3.d.mts → types-CYhDXnf8.d.mts} +74 -8
- package/{types-B62AnIU3.d.ts → types-CYhDXnf8.d.ts} +74 -8
package/index.js
CHANGED
|
@@ -97,12 +97,13 @@ var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
|
|
|
97
97
|
var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
|
|
98
98
|
var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
|
|
99
99
|
var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
|
|
100
|
+
var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
|
|
100
101
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
101
102
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
102
103
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
103
104
|
var NO_CONCURRENCY = 1;
|
|
104
105
|
var DEFAULT_RETRIES = 3;
|
|
105
|
-
var VERSION = "v0.2.
|
|
106
|
+
var VERSION = "v0.2.7";
|
|
106
107
|
var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
|
|
107
108
|
var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
|
|
108
109
|
var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
|
|
@@ -149,6 +150,31 @@ var formatWorkflowError = (error) => {
|
|
|
149
150
|
};
|
|
150
151
|
};
|
|
151
152
|
|
|
153
|
+
// src/utils.ts
|
|
154
|
+
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
155
|
+
var NANOID_LENGTH = 21;
|
|
156
|
+
function getRandomInt() {
|
|
157
|
+
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
158
|
+
}
|
|
159
|
+
function nanoid() {
|
|
160
|
+
return Array.from({ length: NANOID_LENGTH }).map(() => NANOID_CHARS[getRandomInt()]).join("");
|
|
161
|
+
}
|
|
162
|
+
function getWorkflowRunId(id) {
|
|
163
|
+
return `wfr_${id ?? nanoid()}`;
|
|
164
|
+
}
|
|
165
|
+
function decodeBase64(base64) {
|
|
166
|
+
try {
|
|
167
|
+
const binString = atob(base64);
|
|
168
|
+
const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
|
|
169
|
+
return new TextDecoder().decode(intArray);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.warn(
|
|
172
|
+
`Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
|
|
173
|
+
);
|
|
174
|
+
return atob(base64);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
152
178
|
// src/context/steps.ts
|
|
153
179
|
var BaseLazyStep = class {
|
|
154
180
|
stepName;
|
|
@@ -253,8 +279,9 @@ var LazyCallStep = class extends BaseLazyStep {
|
|
|
253
279
|
headers;
|
|
254
280
|
retries;
|
|
255
281
|
timeout;
|
|
282
|
+
flowControl;
|
|
256
283
|
stepType = "Call";
|
|
257
|
-
constructor(stepName, url, method, body, headers, retries, timeout) {
|
|
284
|
+
constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
|
|
258
285
|
super(stepName);
|
|
259
286
|
this.url = url;
|
|
260
287
|
this.method = method;
|
|
@@ -262,6 +289,7 @@ var LazyCallStep = class extends BaseLazyStep {
|
|
|
262
289
|
this.headers = headers;
|
|
263
290
|
this.retries = retries;
|
|
264
291
|
this.timeout = timeout;
|
|
292
|
+
this.flowControl = flowControl;
|
|
265
293
|
}
|
|
266
294
|
getPlanStep(concurrent, targetStep) {
|
|
267
295
|
return {
|
|
@@ -329,6 +357,49 @@ var LazyNotifyStep = class extends LazyFunctionStep {
|
|
|
329
357
|
});
|
|
330
358
|
}
|
|
331
359
|
};
|
|
360
|
+
var LazyInvokeStep = class extends BaseLazyStep {
|
|
361
|
+
stepType = "Invoke";
|
|
362
|
+
params;
|
|
363
|
+
constructor(stepName, {
|
|
364
|
+
workflow,
|
|
365
|
+
body,
|
|
366
|
+
headers = {},
|
|
367
|
+
workflowRunId,
|
|
368
|
+
retries,
|
|
369
|
+
flowControl
|
|
370
|
+
}) {
|
|
371
|
+
super(stepName);
|
|
372
|
+
this.params = {
|
|
373
|
+
workflow,
|
|
374
|
+
body,
|
|
375
|
+
headers,
|
|
376
|
+
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
377
|
+
retries,
|
|
378
|
+
flowControl
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
getPlanStep(concurrent, targetStep) {
|
|
382
|
+
return {
|
|
383
|
+
stepId: 0,
|
|
384
|
+
stepName: this.stepName,
|
|
385
|
+
stepType: this.stepType,
|
|
386
|
+
concurrent,
|
|
387
|
+
targetStep
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* won't be used as it's the server who will add the result step
|
|
392
|
+
* in Invoke step.
|
|
393
|
+
*/
|
|
394
|
+
getResultStep(concurrent, stepId) {
|
|
395
|
+
return Promise.resolve({
|
|
396
|
+
stepId,
|
|
397
|
+
stepName: this.stepName,
|
|
398
|
+
stepType: this.stepType,
|
|
399
|
+
concurrent
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
};
|
|
332
403
|
|
|
333
404
|
// node_modules/neverthrow/dist/index.es.js
|
|
334
405
|
var defaultErrorConfig = {
|
|
@@ -753,7 +824,8 @@ var StepTypes = [
|
|
|
753
824
|
"SleepUntil",
|
|
754
825
|
"Call",
|
|
755
826
|
"Wait",
|
|
756
|
-
"Notify"
|
|
827
|
+
"Notify",
|
|
828
|
+
"Invoke"
|
|
757
829
|
];
|
|
758
830
|
|
|
759
831
|
// src/workflow-requests.ts
|
|
@@ -762,7 +834,8 @@ var triggerFirstInvocation = async ({
|
|
|
762
834
|
workflowContext,
|
|
763
835
|
useJSONContent,
|
|
764
836
|
telemetry,
|
|
765
|
-
debug
|
|
837
|
+
debug,
|
|
838
|
+
invokeCount
|
|
766
839
|
}) => {
|
|
767
840
|
const { headers } = getHeaders({
|
|
768
841
|
initHeaderValue: "true",
|
|
@@ -771,7 +844,9 @@ var triggerFirstInvocation = async ({
|
|
|
771
844
|
userHeaders: workflowContext.headers,
|
|
772
845
|
failureUrl: workflowContext.failureUrl,
|
|
773
846
|
retries: workflowContext.retries,
|
|
774
|
-
telemetry
|
|
847
|
+
telemetry,
|
|
848
|
+
invokeCount,
|
|
849
|
+
flowControl: workflowContext.flowControl
|
|
775
850
|
});
|
|
776
851
|
if (workflowContext.headers.get("content-type")) {
|
|
777
852
|
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
@@ -817,8 +892,8 @@ var triggerRouteFunction = async ({
|
|
|
817
892
|
debug
|
|
818
893
|
}) => {
|
|
819
894
|
try {
|
|
820
|
-
await onStep();
|
|
821
|
-
await onCleanup();
|
|
895
|
+
const result = await onStep();
|
|
896
|
+
await onCleanup(result);
|
|
822
897
|
return ok("workflow-finished");
|
|
823
898
|
} catch (error) {
|
|
824
899
|
const error_ = error;
|
|
@@ -839,14 +914,15 @@ var triggerRouteFunction = async ({
|
|
|
839
914
|
}
|
|
840
915
|
}
|
|
841
916
|
};
|
|
842
|
-
var triggerWorkflowDelete = async (workflowContext, debug, cancel = false) => {
|
|
917
|
+
var triggerWorkflowDelete = async (workflowContext, result, debug, cancel = false) => {
|
|
843
918
|
await debug?.log("SUBMIT", "SUBMIT_CLEANUP", {
|
|
844
919
|
deletedWorkflowRunId: workflowContext.workflowRunId
|
|
845
920
|
});
|
|
846
921
|
await workflowContext.qstashClient.http.request({
|
|
847
922
|
path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
|
|
848
923
|
method: "DELETE",
|
|
849
|
-
parseResponseAsJson: false
|
|
924
|
+
parseResponseAsJson: false,
|
|
925
|
+
body: JSON.stringify(result)
|
|
850
926
|
});
|
|
851
927
|
await debug?.log(
|
|
852
928
|
"SUBMIT",
|
|
@@ -876,6 +952,7 @@ var handleThirdPartyCallResult = async ({
|
|
|
876
952
|
failureUrl,
|
|
877
953
|
retries,
|
|
878
954
|
telemetry,
|
|
955
|
+
flowControl,
|
|
879
956
|
debug
|
|
880
957
|
}) => {
|
|
881
958
|
try {
|
|
@@ -923,6 +1000,7 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
923
1000
|
const stepType = request.headers.get("Upstash-Workflow-StepType");
|
|
924
1001
|
const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
|
|
925
1002
|
const contentType = request.headers.get("Upstash-Workflow-ContentType");
|
|
1003
|
+
const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
|
|
926
1004
|
if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
|
|
927
1005
|
throw new Error(
|
|
928
1006
|
`Missing info in callback message source header: ${JSON.stringify({
|
|
@@ -943,7 +1021,9 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
943
1021
|
userHeaders,
|
|
944
1022
|
failureUrl,
|
|
945
1023
|
retries,
|
|
946
|
-
telemetry
|
|
1024
|
+
telemetry,
|
|
1025
|
+
invokeCount: Number(invokeCount),
|
|
1026
|
+
flowControl
|
|
947
1027
|
});
|
|
948
1028
|
const callResponse = {
|
|
949
1029
|
status: callbackMessage.status,
|
|
@@ -999,15 +1079,24 @@ var getHeaders = ({
|
|
|
999
1079
|
step,
|
|
1000
1080
|
callRetries,
|
|
1001
1081
|
callTimeout,
|
|
1002
|
-
telemetry
|
|
1082
|
+
telemetry,
|
|
1083
|
+
invokeCount,
|
|
1084
|
+
flowControl,
|
|
1085
|
+
callFlowControl
|
|
1003
1086
|
}) => {
|
|
1087
|
+
const contentType = (userHeaders ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
|
|
1004
1088
|
const baseHeaders = {
|
|
1005
1089
|
[WORKFLOW_INIT_HEADER]: initHeaderValue,
|
|
1006
1090
|
[WORKFLOW_ID_HEADER]: workflowRunId,
|
|
1007
1091
|
[WORKFLOW_URL_HEADER]: workflowUrl,
|
|
1008
1092
|
[WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
|
|
1093
|
+
[WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
|
|
1094
|
+
"content-type": contentType,
|
|
1009
1095
|
...telemetry ? getTelemetryHeaders(telemetry) : {}
|
|
1010
1096
|
};
|
|
1097
|
+
if (invokeCount !== void 0 && !step?.callUrl) {
|
|
1098
|
+
baseHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount.toString();
|
|
1099
|
+
}
|
|
1011
1100
|
if (!step?.callUrl) {
|
|
1012
1101
|
baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
1013
1102
|
}
|
|
@@ -1024,6 +1113,11 @@ var getHeaders = ({
|
|
|
1024
1113
|
if (retries !== void 0) {
|
|
1025
1114
|
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
1026
1115
|
}
|
|
1116
|
+
if (flowControl) {
|
|
1117
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
1118
|
+
baseHeaders["Upstash-Failure-Callback-Flow-Control-Key"] = flowControlKey;
|
|
1119
|
+
baseHeaders["Upstash-Failure-Callback-Flow-Control-Value"] = flowControlValue;
|
|
1120
|
+
}
|
|
1027
1121
|
if (!step?.callUrl) {
|
|
1028
1122
|
baseHeaders["Upstash-Failure-Callback"] = failureUrl;
|
|
1029
1123
|
}
|
|
@@ -1035,9 +1129,26 @@ var getHeaders = ({
|
|
|
1035
1129
|
baseHeaders["Upstash-Callback-Retries"] = retries.toString();
|
|
1036
1130
|
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
1037
1131
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1132
|
+
if (callFlowControl) {
|
|
1133
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(callFlowControl);
|
|
1134
|
+
baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
1135
|
+
baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
1136
|
+
}
|
|
1137
|
+
if (flowControl) {
|
|
1138
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
1139
|
+
baseHeaders["Upstash-Callback-Flow-Control-Key"] = flowControlKey;
|
|
1140
|
+
baseHeaders["Upstash-Callback-Flow-Control-Value"] = flowControlValue;
|
|
1141
|
+
}
|
|
1142
|
+
} else {
|
|
1143
|
+
if (flowControl) {
|
|
1144
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
1145
|
+
baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
1146
|
+
baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
1147
|
+
}
|
|
1148
|
+
if (retries !== void 0) {
|
|
1149
|
+
baseHeaders["Upstash-Retries"] = retries.toString();
|
|
1150
|
+
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
1151
|
+
}
|
|
1041
1152
|
}
|
|
1042
1153
|
if (userHeaders) {
|
|
1043
1154
|
for (const header of userHeaders.keys()) {
|
|
@@ -1049,7 +1160,6 @@ var getHeaders = ({
|
|
|
1049
1160
|
baseHeaders[`Upstash-Failure-Callback-Forward-${header}`] = userHeaders.get(header);
|
|
1050
1161
|
}
|
|
1051
1162
|
}
|
|
1052
|
-
const contentType = (userHeaders ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
|
|
1053
1163
|
if (step?.callHeaders) {
|
|
1054
1164
|
const forwardedHeaders = Object.fromEntries(
|
|
1055
1165
|
Object.entries(step.callHeaders).map(([header, value]) => [
|
|
@@ -1073,6 +1183,7 @@ var getHeaders = ({
|
|
|
1073
1183
|
"Upstash-Callback-Forward-Upstash-Workflow-StepType": step.stepType,
|
|
1074
1184
|
"Upstash-Callback-Forward-Upstash-Workflow-Concurrent": step.concurrent.toString(),
|
|
1075
1185
|
"Upstash-Callback-Forward-Upstash-Workflow-ContentType": contentType,
|
|
1186
|
+
[`Upstash-Callback-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`]: (invokeCount ?? 0).toString(),
|
|
1076
1187
|
"Upstash-Workflow-CallType": "toCallback"
|
|
1077
1188
|
}
|
|
1078
1189
|
};
|
|
@@ -1099,8 +1210,7 @@ var getHeaders = ({
|
|
|
1099
1210
|
"Upstash-Workflow-Runid": [workflowRunId],
|
|
1100
1211
|
[WORKFLOW_INIT_HEADER]: ["false"],
|
|
1101
1212
|
[WORKFLOW_URL_HEADER]: [workflowUrl],
|
|
1102
|
-
"Upstash-Workflow-CallType": ["step"]
|
|
1103
|
-
"Content-Type": [contentType]
|
|
1213
|
+
"Upstash-Workflow-CallType": ["step"]
|
|
1104
1214
|
}
|
|
1105
1215
|
};
|
|
1106
1216
|
}
|
|
@@ -1131,9 +1241,98 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
|
|
|
1131
1241
|
);
|
|
1132
1242
|
}
|
|
1133
1243
|
};
|
|
1244
|
+
var prepareFlowControl = (flowControl) => {
|
|
1245
|
+
const parallelism = flowControl.parallelism?.toString();
|
|
1246
|
+
const rate = flowControl.ratePerSecond?.toString();
|
|
1247
|
+
const controlValue = [
|
|
1248
|
+
parallelism ? `parallelism=${parallelism}` : void 0,
|
|
1249
|
+
rate ? `rate=${rate}` : void 0
|
|
1250
|
+
].filter(Boolean);
|
|
1251
|
+
if (controlValue.length === 0) {
|
|
1252
|
+
throw new import_qstash3.QstashError("Provide at least one of parallelism or ratePerSecond for flowControl");
|
|
1253
|
+
}
|
|
1254
|
+
return {
|
|
1255
|
+
flowControlKey: flowControl.key,
|
|
1256
|
+
flowControlValue: controlValue.join(", ")
|
|
1257
|
+
};
|
|
1258
|
+
};
|
|
1134
1259
|
|
|
1135
1260
|
// src/context/auto-executor.ts
|
|
1136
1261
|
var import_qstash4 = require("@upstash/qstash");
|
|
1262
|
+
|
|
1263
|
+
// src/serve/serve-many.ts
|
|
1264
|
+
var invokeWorkflow = async ({
|
|
1265
|
+
settings,
|
|
1266
|
+
invokeStep,
|
|
1267
|
+
context,
|
|
1268
|
+
invokeCount,
|
|
1269
|
+
telemetry
|
|
1270
|
+
}) => {
|
|
1271
|
+
const {
|
|
1272
|
+
body,
|
|
1273
|
+
workflow,
|
|
1274
|
+
headers = {},
|
|
1275
|
+
workflowRunId = getWorkflowRunId(),
|
|
1276
|
+
retries,
|
|
1277
|
+
flowControl
|
|
1278
|
+
} = settings;
|
|
1279
|
+
const { workflowId } = workflow;
|
|
1280
|
+
const {
|
|
1281
|
+
retries: workflowRetries,
|
|
1282
|
+
failureFunction,
|
|
1283
|
+
failureUrl,
|
|
1284
|
+
useJSONContent,
|
|
1285
|
+
flowControl: workflowFlowControl
|
|
1286
|
+
} = workflow.options;
|
|
1287
|
+
if (!workflowId) {
|
|
1288
|
+
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1289
|
+
}
|
|
1290
|
+
const { headers: invokerHeaders } = getHeaders({
|
|
1291
|
+
initHeaderValue: "false",
|
|
1292
|
+
workflowRunId: context.workflowRunId,
|
|
1293
|
+
workflowUrl: context.url,
|
|
1294
|
+
userHeaders: context.headers,
|
|
1295
|
+
failureUrl: context.failureUrl,
|
|
1296
|
+
retries: context.retries,
|
|
1297
|
+
telemetry,
|
|
1298
|
+
invokeCount,
|
|
1299
|
+
flowControl: context.flowControl
|
|
1300
|
+
});
|
|
1301
|
+
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1302
|
+
const newUrl = context.url.replace(/[^/]+$/, workflowId);
|
|
1303
|
+
const { headers: triggerHeaders } = getHeaders({
|
|
1304
|
+
initHeaderValue: "true",
|
|
1305
|
+
workflowRunId,
|
|
1306
|
+
workflowUrl: newUrl,
|
|
1307
|
+
userHeaders: new Headers(headers),
|
|
1308
|
+
retries: retries ?? workflowRetries,
|
|
1309
|
+
telemetry,
|
|
1310
|
+
failureUrl: failureFunction ? newUrl : failureUrl,
|
|
1311
|
+
invokeCount: invokeCount + 1,
|
|
1312
|
+
flowControl: flowControl ?? workflowFlowControl
|
|
1313
|
+
});
|
|
1314
|
+
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1315
|
+
if (useJSONContent) {
|
|
1316
|
+
triggerHeaders["content-type"] = "application/json";
|
|
1317
|
+
}
|
|
1318
|
+
const request = {
|
|
1319
|
+
body: JSON.stringify(body),
|
|
1320
|
+
headers: Object.fromEntries(
|
|
1321
|
+
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1322
|
+
),
|
|
1323
|
+
workflowRunId,
|
|
1324
|
+
workflowUrl: context.url,
|
|
1325
|
+
step: invokeStep
|
|
1326
|
+
};
|
|
1327
|
+
await context.qstashClient.publish({
|
|
1328
|
+
headers: triggerHeaders,
|
|
1329
|
+
method: "POST",
|
|
1330
|
+
body: JSON.stringify(request),
|
|
1331
|
+
url: newUrl
|
|
1332
|
+
});
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1335
|
+
// src/context/auto-executor.ts
|
|
1137
1336
|
var AutoExecutor = class _AutoExecutor {
|
|
1138
1337
|
context;
|
|
1139
1338
|
promises = /* @__PURE__ */ new WeakMap();
|
|
@@ -1142,14 +1341,16 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1142
1341
|
nonPlanStepCount;
|
|
1143
1342
|
steps;
|
|
1144
1343
|
indexInCurrentList = 0;
|
|
1344
|
+
invokeCount;
|
|
1145
1345
|
telemetry;
|
|
1146
1346
|
stepCount = 0;
|
|
1147
1347
|
planStepCount = 0;
|
|
1148
1348
|
executingStep = false;
|
|
1149
|
-
constructor(context, steps, telemetry, debug) {
|
|
1349
|
+
constructor(context, steps, telemetry, invokeCount, debug) {
|
|
1150
1350
|
this.context = context;
|
|
1151
1351
|
this.steps = steps;
|
|
1152
1352
|
this.telemetry = telemetry;
|
|
1353
|
+
this.invokeCount = invokeCount ?? 0;
|
|
1153
1354
|
this.debug = debug;
|
|
1154
1355
|
this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
|
|
1155
1356
|
}
|
|
@@ -1372,7 +1573,9 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1372
1573
|
step: waitStep,
|
|
1373
1574
|
failureUrl: this.context.failureUrl,
|
|
1374
1575
|
retries: this.context.retries,
|
|
1375
|
-
telemetry: this.telemetry
|
|
1576
|
+
telemetry: this.telemetry,
|
|
1577
|
+
invokeCount: this.invokeCount,
|
|
1578
|
+
flowControl: this.context.flowControl
|
|
1376
1579
|
});
|
|
1377
1580
|
const waitBody = {
|
|
1378
1581
|
url: this.context.url,
|
|
@@ -1395,7 +1598,19 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1395
1598
|
method: "POST",
|
|
1396
1599
|
parseResponseAsJson: false
|
|
1397
1600
|
});
|
|
1398
|
-
throw new WorkflowAbort(
|
|
1601
|
+
throw new WorkflowAbort(waitStep.stepName, waitStep);
|
|
1602
|
+
}
|
|
1603
|
+
if (steps.length === 1 && lazySteps[0] instanceof LazyInvokeStep) {
|
|
1604
|
+
const invokeStep = steps[0];
|
|
1605
|
+
const lazyInvokeStep = lazySteps[0];
|
|
1606
|
+
await invokeWorkflow({
|
|
1607
|
+
settings: lazyInvokeStep.params,
|
|
1608
|
+
invokeStep,
|
|
1609
|
+
context: this.context,
|
|
1610
|
+
invokeCount: this.invokeCount,
|
|
1611
|
+
telemetry: this.telemetry
|
|
1612
|
+
});
|
|
1613
|
+
throw new WorkflowAbort(invokeStep.stepName, invokeStep);
|
|
1399
1614
|
}
|
|
1400
1615
|
const result = await this.context.qstashClient.batchJSON(
|
|
1401
1616
|
steps.map((singleStep, index) => {
|
|
@@ -1410,11 +1625,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1410
1625
|
retries: this.context.retries,
|
|
1411
1626
|
callRetries: lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
|
|
1412
1627
|
callTimeout: lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0,
|
|
1413
|
-
telemetry: this.telemetry
|
|
1628
|
+
telemetry: this.telemetry,
|
|
1629
|
+
invokeCount: this.invokeCount,
|
|
1630
|
+
flowControl: this.context.flowControl,
|
|
1631
|
+
callFlowControl: lazyStep instanceof LazyCallStep ? lazyStep.flowControl : void 0
|
|
1414
1632
|
});
|
|
1415
1633
|
const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
|
|
1416
1634
|
singleStep.out = JSON.stringify(singleStep.out);
|
|
1417
|
-
return singleStep.callUrl ? (
|
|
1635
|
+
return singleStep.callUrl && lazyStep instanceof LazyCallStep ? (
|
|
1418
1636
|
// if the step is a third party call, we call the third party
|
|
1419
1637
|
// url (singleStep.callUrl) and pass information about the workflow
|
|
1420
1638
|
// in the headers (handled in getHeaders). QStash makes the request
|
|
@@ -1756,7 +1974,7 @@ var WorkflowTool = class {
|
|
|
1756
1974
|
*/
|
|
1757
1975
|
executeAsStep;
|
|
1758
1976
|
/**
|
|
1759
|
-
*
|
|
1977
|
+
*
|
|
1760
1978
|
* @param description description of the tool
|
|
1761
1979
|
* @param schema schema of the tool
|
|
1762
1980
|
* @param invoke function to invoke the tool
|
|
@@ -2102,6 +2320,11 @@ var WorkflowContext = class {
|
|
|
2102
2320
|
* Number of retries
|
|
2103
2321
|
*/
|
|
2104
2322
|
retries;
|
|
2323
|
+
/**
|
|
2324
|
+
* Settings for controlling the number of active requests
|
|
2325
|
+
* and number of requests per second with the same key.
|
|
2326
|
+
*/
|
|
2327
|
+
flowControl;
|
|
2105
2328
|
constructor({
|
|
2106
2329
|
qstashClient,
|
|
2107
2330
|
workflowRunId,
|
|
@@ -2113,7 +2336,9 @@ var WorkflowContext = class {
|
|
|
2113
2336
|
initialPayload,
|
|
2114
2337
|
env,
|
|
2115
2338
|
retries,
|
|
2116
|
-
telemetry
|
|
2339
|
+
telemetry,
|
|
2340
|
+
invokeCount,
|
|
2341
|
+
flowControl
|
|
2117
2342
|
}) {
|
|
2118
2343
|
this.qstashClient = qstashClient;
|
|
2119
2344
|
this.workflowRunId = workflowRunId;
|
|
@@ -2124,7 +2349,8 @@ var WorkflowContext = class {
|
|
|
2124
2349
|
this.requestPayload = initialPayload;
|
|
2125
2350
|
this.env = env ?? {};
|
|
2126
2351
|
this.retries = retries ?? DEFAULT_RETRIES;
|
|
2127
|
-
this.
|
|
2352
|
+
this.flowControl = flowControl;
|
|
2353
|
+
this.executor = new AutoExecutor(this, this.steps, telemetry, invokeCount, debug);
|
|
2128
2354
|
}
|
|
2129
2355
|
/**
|
|
2130
2356
|
* Executes a workflow step
|
|
@@ -2226,7 +2452,7 @@ var WorkflowContext = class {
|
|
|
2226
2452
|
* }
|
|
2227
2453
|
*/
|
|
2228
2454
|
async call(stepName, settings) {
|
|
2229
|
-
const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
|
|
2455
|
+
const { url, method = "GET", body, headers = {}, retries = 0, timeout, flowControl } = settings;
|
|
2230
2456
|
const result = await this.addStep(
|
|
2231
2457
|
new LazyCallStep(
|
|
2232
2458
|
stepName,
|
|
@@ -2235,7 +2461,8 @@ var WorkflowContext = class {
|
|
|
2235
2461
|
body,
|
|
2236
2462
|
headers,
|
|
2237
2463
|
retries,
|
|
2238
|
-
timeout
|
|
2464
|
+
timeout,
|
|
2465
|
+
flowControl
|
|
2239
2466
|
)
|
|
2240
2467
|
);
|
|
2241
2468
|
if (typeof result === "string") {
|
|
@@ -2344,6 +2571,13 @@ var WorkflowContext = class {
|
|
|
2344
2571
|
return result;
|
|
2345
2572
|
}
|
|
2346
2573
|
}
|
|
2574
|
+
async invoke(stepName, settings) {
|
|
2575
|
+
const result = await this.addStep(new LazyInvokeStep(stepName, settings));
|
|
2576
|
+
return {
|
|
2577
|
+
...result,
|
|
2578
|
+
body: result.body ? JSON.parse(result.body) : void 0
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2347
2581
|
/**
|
|
2348
2582
|
* Cancel the current workflow run
|
|
2349
2583
|
*
|
|
@@ -2421,31 +2655,6 @@ var WorkflowLogger = class _WorkflowLogger {
|
|
|
2421
2655
|
}
|
|
2422
2656
|
};
|
|
2423
2657
|
|
|
2424
|
-
// src/utils.ts
|
|
2425
|
-
var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
|
|
2426
|
-
var NANOID_LENGTH = 21;
|
|
2427
|
-
function getRandomInt() {
|
|
2428
|
-
return Math.floor(Math.random() * NANOID_CHARS.length);
|
|
2429
|
-
}
|
|
2430
|
-
function nanoid() {
|
|
2431
|
-
return Array.from({ length: NANOID_LENGTH }).map(() => NANOID_CHARS[getRandomInt()]).join("");
|
|
2432
|
-
}
|
|
2433
|
-
function getWorkflowRunId(id) {
|
|
2434
|
-
return `wfr_${id ?? nanoid()}`;
|
|
2435
|
-
}
|
|
2436
|
-
function decodeBase64(base64) {
|
|
2437
|
-
try {
|
|
2438
|
-
const binString = atob(base64);
|
|
2439
|
-
const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
|
|
2440
|
-
return new TextDecoder().decode(intArray);
|
|
2441
|
-
} catch (error) {
|
|
2442
|
-
console.warn(
|
|
2443
|
-
`Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
|
|
2444
|
-
);
|
|
2445
|
-
return atob(base64);
|
|
2446
|
-
}
|
|
2447
|
-
}
|
|
2448
|
-
|
|
2449
2658
|
// src/serve/authorization.ts
|
|
2450
2659
|
var import_qstash8 = require("@upstash/qstash");
|
|
2451
2660
|
var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowContext {
|
|
@@ -2490,7 +2699,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
2490
2699
|
failureUrl: context.failureUrl,
|
|
2491
2700
|
initialPayload: context.requestPayload,
|
|
2492
2701
|
env: context.env,
|
|
2493
|
-
retries: context.retries
|
|
2702
|
+
retries: context.retries,
|
|
2703
|
+
flowControl: context.flowControl
|
|
2494
2704
|
});
|
|
2495
2705
|
try {
|
|
2496
2706
|
await routeFunction(disabledContext);
|
|
@@ -2643,7 +2853,7 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
2643
2853
|
};
|
|
2644
2854
|
}
|
|
2645
2855
|
};
|
|
2646
|
-
var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, debug) => {
|
|
2856
|
+
var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, flowControl, debug) => {
|
|
2647
2857
|
if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
|
|
2648
2858
|
return ok("not-failure-callback");
|
|
2649
2859
|
}
|
|
@@ -2655,22 +2865,21 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
2655
2865
|
);
|
|
2656
2866
|
}
|
|
2657
2867
|
try {
|
|
2658
|
-
const { status, header, body, url,
|
|
2659
|
-
requestPayload
|
|
2660
|
-
);
|
|
2868
|
+
const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
|
|
2661
2869
|
const decodedBody = body ? decodeBase64(body) : "{}";
|
|
2662
2870
|
const errorPayload = JSON.parse(decodedBody);
|
|
2663
2871
|
const workflowContext = new WorkflowContext({
|
|
2664
2872
|
qstashClient,
|
|
2665
2873
|
workflowRunId,
|
|
2666
2874
|
initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
|
|
2667
|
-
headers: recreateUserHeaders(
|
|
2875
|
+
headers: recreateUserHeaders(request.headers),
|
|
2668
2876
|
steps: [],
|
|
2669
2877
|
url,
|
|
2670
2878
|
failureUrl: url,
|
|
2671
2879
|
debug,
|
|
2672
2880
|
env,
|
|
2673
2881
|
retries,
|
|
2882
|
+
flowControl,
|
|
2674
2883
|
telemetry: void 0
|
|
2675
2884
|
// not going to make requests in authentication check
|
|
2676
2885
|
});
|
|
@@ -2797,7 +3006,8 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2797
3006
|
env,
|
|
2798
3007
|
retries,
|
|
2799
3008
|
useJSONContent,
|
|
2800
|
-
disableTelemetry
|
|
3009
|
+
disableTelemetry,
|
|
3010
|
+
flowControl
|
|
2801
3011
|
} = processOptions(options);
|
|
2802
3012
|
telemetry = disableTelemetry ? void 0 : telemetry;
|
|
2803
3013
|
const debug = WorkflowLogger.getLogger(verbose);
|
|
@@ -2838,6 +3048,7 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2838
3048
|
failureFunction,
|
|
2839
3049
|
env,
|
|
2840
3050
|
retries,
|
|
3051
|
+
flowControl,
|
|
2841
3052
|
debug
|
|
2842
3053
|
);
|
|
2843
3054
|
if (failureCheck.isErr()) {
|
|
@@ -2846,6 +3057,7 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2846
3057
|
await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
|
|
2847
3058
|
return onStepFinish(workflowRunId, "failure-callback");
|
|
2848
3059
|
}
|
|
3060
|
+
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
2849
3061
|
const workflowContext = new WorkflowContext({
|
|
2850
3062
|
qstashClient,
|
|
2851
3063
|
workflowRunId,
|
|
@@ -2857,7 +3069,9 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2857
3069
|
debug,
|
|
2858
3070
|
env,
|
|
2859
3071
|
retries,
|
|
2860
|
-
telemetry
|
|
3072
|
+
telemetry,
|
|
3073
|
+
invokeCount,
|
|
3074
|
+
flowControl
|
|
2861
3075
|
});
|
|
2862
3076
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
2863
3077
|
routeFunction,
|
|
@@ -2880,6 +3094,7 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2880
3094
|
workflowUrl,
|
|
2881
3095
|
failureUrl: workflowFailureUrl,
|
|
2882
3096
|
retries,
|
|
3097
|
+
flowControl,
|
|
2883
3098
|
telemetry,
|
|
2884
3099
|
debug
|
|
2885
3100
|
});
|
|
@@ -2889,10 +3104,16 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2889
3104
|
});
|
|
2890
3105
|
throw callReturnCheck.error;
|
|
2891
3106
|
} else if (callReturnCheck.value === "continue-workflow") {
|
|
2892
|
-
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3107
|
+
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3108
|
+
workflowContext,
|
|
3109
|
+
useJSONContent,
|
|
3110
|
+
telemetry,
|
|
3111
|
+
debug,
|
|
3112
|
+
invokeCount
|
|
3113
|
+
}) : await triggerRouteFunction({
|
|
2893
3114
|
onStep: async () => routeFunction(workflowContext),
|
|
2894
|
-
onCleanup: async () => {
|
|
2895
|
-
await triggerWorkflowDelete(workflowContext, debug);
|
|
3115
|
+
onCleanup: async (result2) => {
|
|
3116
|
+
await triggerWorkflowDelete(workflowContext, result2, debug);
|
|
2896
3117
|
},
|
|
2897
3118
|
onCancel: async () => {
|
|
2898
3119
|
await makeCancelRequest(workflowContext.qstashClient.http, workflowRunId);
|
|
@@ -3095,7 +3316,8 @@ var Client4 = class {
|
|
|
3095
3316
|
body,
|
|
3096
3317
|
headers,
|
|
3097
3318
|
workflowRunId,
|
|
3098
|
-
retries
|
|
3319
|
+
retries,
|
|
3320
|
+
flowControl
|
|
3099
3321
|
}) {
|
|
3100
3322
|
const finalWorkflowRunId = getWorkflowRunId(workflowRunId);
|
|
3101
3323
|
const context = new WorkflowContext({
|
|
@@ -3107,8 +3329,9 @@ var Client4 = class {
|
|
|
3107
3329
|
url,
|
|
3108
3330
|
workflowRunId: finalWorkflowRunId,
|
|
3109
3331
|
retries,
|
|
3110
|
-
telemetry: void 0
|
|
3332
|
+
telemetry: void 0,
|
|
3111
3333
|
// can't know workflow telemetry here
|
|
3334
|
+
flowControl
|
|
3112
3335
|
});
|
|
3113
3336
|
const result = await triggerFirstInvocation({
|
|
3114
3337
|
workflowContext: context,
|
|
@@ -3122,35 +3345,35 @@ var Client4 = class {
|
|
|
3122
3345
|
}
|
|
3123
3346
|
}
|
|
3124
3347
|
/**
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3348
|
+
* Fetches logs for workflow runs.
|
|
3349
|
+
*
|
|
3350
|
+
* @param workflowRunId - The ID of the workflow run to fetch logs for.
|
|
3351
|
+
* @param cursor - The cursor for pagination.
|
|
3352
|
+
* @param count - Number of runs to fetch. Default value is 10.
|
|
3353
|
+
* @param state - The state of the workflow run.
|
|
3354
|
+
* @param workflowUrl - The URL of the workflow. Should be an exact match.
|
|
3355
|
+
* @param workflowCreatedAt - The creation time of the workflow. If you have two workflow runs with the same URL, you can use this to filter them.
|
|
3356
|
+
* @returns A promise that resolves to either a `WorkflowRunLog` or a `WorkflowRunResponse`.
|
|
3357
|
+
*
|
|
3358
|
+
* @example
|
|
3359
|
+
* Fetch logs for a specific workflow run:
|
|
3360
|
+
* ```typescript
|
|
3361
|
+
* const { runs } = await client.logs({ workflowRunId: '12345' });
|
|
3362
|
+
* const steps = runs[0].steps; // access steps
|
|
3363
|
+
* ```
|
|
3364
|
+
*
|
|
3365
|
+
* @example
|
|
3366
|
+
* Fetch logs with pagination:
|
|
3367
|
+
* ```typescript
|
|
3368
|
+
* const { runs, cursor } = await client.logs();
|
|
3369
|
+
* const steps = runs[0].steps // access steps
|
|
3370
|
+
*
|
|
3371
|
+
* const { runs: nextRuns, cursor: nextCursor } = await client.logs({ cursor, count: 2 });
|
|
3372
|
+
* ```
|
|
3373
|
+
*/
|
|
3151
3374
|
async logs(params) {
|
|
3152
3375
|
const { workflowRunId, cursor, count, state, workflowUrl, workflowCreatedAt } = params ?? {};
|
|
3153
|
-
const urlParams = new URLSearchParams({
|
|
3376
|
+
const urlParams = new URLSearchParams({ groupBy: "workflowRunId" });
|
|
3154
3377
|
if (workflowRunId) {
|
|
3155
3378
|
urlParams.append("workflowRunId", workflowRunId);
|
|
3156
3379
|
}
|