@upstash/workflow 0.2.8-rc-invoke → 0.2.9
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 +4 -4
- package/astro.d.ts +4 -4
- package/astro.js +282 -135
- package/astro.mjs +17 -15
- package/{chunk-IWAW7GIG.mjs → chunk-IPXJZU3K.mjs} +851 -592
- package/cloudflare.d.mts +4 -4
- package/cloudflare.d.ts +4 -4
- package/cloudflare.js +278 -135
- package/cloudflare.mjs +13 -15
- package/express.d.mts +4 -4
- package/express.d.ts +4 -4
- package/express.js +281 -144
- package/express.mjs +16 -22
- package/h3.d.mts +4 -4
- package/h3.d.ts +4 -4
- package/h3.js +275 -135
- package/h3.mjs +10 -15
- package/hono.d.mts +4 -4
- package/hono.d.ts +4 -4
- package/hono.js +277 -134
- package/hono.mjs +12 -14
- package/index.d.mts +268 -5
- package/index.d.ts +268 -5
- package/index.js +297 -43
- package/index.mjs +60 -3
- package/nextjs.d.mts +6 -6
- package/nextjs.d.ts +6 -6
- package/nextjs.js +286 -143
- package/nextjs.mjs +21 -23
- 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 +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +207 -41
- package/solidjs.mjs +1 -1
- package/svelte.d.mts +8 -9
- package/svelte.d.ts +8 -9
- package/svelte.js +278 -135
- package/svelte.mjs +13 -15
- package/{types-C7Y7WUQd.d.mts → types-CYhDXnf8.d.mts} +110 -18
- package/{types-C7Y7WUQd.d.ts → types-CYhDXnf8.d.ts} +110 -18
- package/chunk-LCZMBGEM.mjs +0 -95
- package/serve-many-BlBvXfBS.d.mts +0 -10
- package/serve-many-Dw-UUnH6.d.ts +0 -10
package/nextjs.js
CHANGED
|
@@ -88,6 +88,7 @@ var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
|
|
|
88
88
|
var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
|
|
89
89
|
var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
|
|
90
90
|
var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
|
|
91
|
+
var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
|
|
91
92
|
var WORKFLOW_PROTOCOL_VERSION = "1";
|
|
92
93
|
var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
|
|
93
94
|
var DEFAULT_CONTENT_TYPE = "application/json";
|
|
@@ -269,8 +270,9 @@ var LazyCallStep = class extends BaseLazyStep {
|
|
|
269
270
|
headers;
|
|
270
271
|
retries;
|
|
271
272
|
timeout;
|
|
273
|
+
flowControl;
|
|
272
274
|
stepType = "Call";
|
|
273
|
-
constructor(stepName, url, method, body, headers, retries, timeout) {
|
|
275
|
+
constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
|
|
274
276
|
super(stepName);
|
|
275
277
|
this.url = url;
|
|
276
278
|
this.method = method;
|
|
@@ -278,6 +280,7 @@ var LazyCallStep = class extends BaseLazyStep {
|
|
|
278
280
|
this.headers = headers;
|
|
279
281
|
this.retries = retries;
|
|
280
282
|
this.timeout = timeout;
|
|
283
|
+
this.flowControl = flowControl;
|
|
281
284
|
}
|
|
282
285
|
getPlanStep(concurrent, targetStep) {
|
|
283
286
|
return {
|
|
@@ -348,14 +351,22 @@ var LazyNotifyStep = class extends LazyFunctionStep {
|
|
|
348
351
|
var LazyInvokeStep = class extends BaseLazyStep {
|
|
349
352
|
stepType = "Invoke";
|
|
350
353
|
params;
|
|
351
|
-
constructor(stepName, {
|
|
354
|
+
constructor(stepName, {
|
|
355
|
+
workflow,
|
|
356
|
+
body,
|
|
357
|
+
headers = {},
|
|
358
|
+
workflowRunId,
|
|
359
|
+
retries,
|
|
360
|
+
flowControl
|
|
361
|
+
}) {
|
|
352
362
|
super(stepName);
|
|
353
363
|
this.params = {
|
|
354
364
|
workflow,
|
|
355
365
|
body,
|
|
356
366
|
headers,
|
|
357
367
|
workflowRunId: getWorkflowRunId(workflowRunId),
|
|
358
|
-
retries
|
|
368
|
+
retries,
|
|
369
|
+
flowControl
|
|
359
370
|
};
|
|
360
371
|
}
|
|
361
372
|
getPlanStep(concurrent, targetStep) {
|
|
@@ -814,7 +825,8 @@ var triggerFirstInvocation = async ({
|
|
|
814
825
|
workflowContext,
|
|
815
826
|
useJSONContent,
|
|
816
827
|
telemetry,
|
|
817
|
-
debug
|
|
828
|
+
debug,
|
|
829
|
+
invokeCount
|
|
818
830
|
}) => {
|
|
819
831
|
const { headers } = getHeaders({
|
|
820
832
|
initHeaderValue: "true",
|
|
@@ -823,7 +835,9 @@ var triggerFirstInvocation = async ({
|
|
|
823
835
|
userHeaders: workflowContext.headers,
|
|
824
836
|
failureUrl: workflowContext.failureUrl,
|
|
825
837
|
retries: workflowContext.retries,
|
|
826
|
-
telemetry
|
|
838
|
+
telemetry,
|
|
839
|
+
invokeCount,
|
|
840
|
+
flowControl: workflowContext.flowControl
|
|
827
841
|
});
|
|
828
842
|
if (workflowContext.headers.get("content-type")) {
|
|
829
843
|
headers["content-type"] = workflowContext.headers.get("content-type");
|
|
@@ -929,6 +943,7 @@ var handleThirdPartyCallResult = async ({
|
|
|
929
943
|
failureUrl,
|
|
930
944
|
retries,
|
|
931
945
|
telemetry,
|
|
946
|
+
flowControl,
|
|
932
947
|
debug
|
|
933
948
|
}) => {
|
|
934
949
|
try {
|
|
@@ -976,6 +991,7 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
976
991
|
const stepType = request.headers.get("Upstash-Workflow-StepType");
|
|
977
992
|
const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
|
|
978
993
|
const contentType = request.headers.get("Upstash-Workflow-ContentType");
|
|
994
|
+
const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
|
|
979
995
|
if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
|
|
980
996
|
throw new Error(
|
|
981
997
|
`Missing info in callback message source header: ${JSON.stringify({
|
|
@@ -996,7 +1012,9 @@ ${atob(callbackMessage.body ?? "")}`
|
|
|
996
1012
|
userHeaders,
|
|
997
1013
|
failureUrl,
|
|
998
1014
|
retries,
|
|
999
|
-
telemetry
|
|
1015
|
+
telemetry,
|
|
1016
|
+
invokeCount: Number(invokeCount),
|
|
1017
|
+
flowControl
|
|
1000
1018
|
});
|
|
1001
1019
|
const callResponse = {
|
|
1002
1020
|
status: callbackMessage.status,
|
|
@@ -1052,7 +1070,10 @@ var getHeaders = ({
|
|
|
1052
1070
|
step,
|
|
1053
1071
|
callRetries,
|
|
1054
1072
|
callTimeout,
|
|
1055
|
-
telemetry
|
|
1073
|
+
telemetry,
|
|
1074
|
+
invokeCount,
|
|
1075
|
+
flowControl,
|
|
1076
|
+
callFlowControl
|
|
1056
1077
|
}) => {
|
|
1057
1078
|
const contentType = (userHeaders ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
|
|
1058
1079
|
const baseHeaders = {
|
|
@@ -1064,6 +1085,9 @@ var getHeaders = ({
|
|
|
1064
1085
|
"content-type": contentType,
|
|
1065
1086
|
...telemetry ? getTelemetryHeaders(telemetry) : {}
|
|
1066
1087
|
};
|
|
1088
|
+
if (invokeCount !== void 0 && !step?.callUrl) {
|
|
1089
|
+
baseHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount.toString();
|
|
1090
|
+
}
|
|
1067
1091
|
if (!step?.callUrl) {
|
|
1068
1092
|
baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
|
|
1069
1093
|
}
|
|
@@ -1072,13 +1096,23 @@ var getHeaders = ({
|
|
|
1072
1096
|
}
|
|
1073
1097
|
if (failureUrl) {
|
|
1074
1098
|
baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
|
|
1099
|
+
baseHeaders[`Upstash-Failure-Callback-Forward-Upstash-Workflow-Failure-Callback`] = "true";
|
|
1100
|
+
baseHeaders["Upstash-Failure-Callback-Workflow-Runid"] = workflowRunId;
|
|
1101
|
+
baseHeaders["Upstash-Failure-Callback-Workflow-Init"] = "false";
|
|
1102
|
+
baseHeaders["Upstash-Failure-Callback-Workflow-Url"] = workflowUrl;
|
|
1103
|
+
baseHeaders["Upstash-Failure-Callback-Workflow-Calltype"] = "failureCall";
|
|
1104
|
+
if (retries !== void 0) {
|
|
1105
|
+
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
1106
|
+
}
|
|
1107
|
+
if (flowControl) {
|
|
1108
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
1109
|
+
baseHeaders["Upstash-Failure-Callback-Flow-Control-Key"] = flowControlKey;
|
|
1110
|
+
baseHeaders["Upstash-Failure-Callback-Flow-Control-Value"] = flowControlValue;
|
|
1111
|
+
}
|
|
1075
1112
|
if (!step?.callUrl) {
|
|
1076
1113
|
baseHeaders["Upstash-Failure-Callback"] = failureUrl;
|
|
1077
1114
|
}
|
|
1078
1115
|
}
|
|
1079
|
-
if (step?.stepType === "Invoke") {
|
|
1080
|
-
baseHeaders["upstash-workflow-invoke"] = "true";
|
|
1081
|
-
}
|
|
1082
1116
|
if (step?.callUrl) {
|
|
1083
1117
|
baseHeaders["Upstash-Retries"] = callRetries?.toString() ?? "0";
|
|
1084
1118
|
baseHeaders[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
|
|
@@ -1086,9 +1120,26 @@ var getHeaders = ({
|
|
|
1086
1120
|
baseHeaders["Upstash-Callback-Retries"] = retries.toString();
|
|
1087
1121
|
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
1088
1122
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1123
|
+
if (callFlowControl) {
|
|
1124
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(callFlowControl);
|
|
1125
|
+
baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
1126
|
+
baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
1127
|
+
}
|
|
1128
|
+
if (flowControl) {
|
|
1129
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
1130
|
+
baseHeaders["Upstash-Callback-Flow-Control-Key"] = flowControlKey;
|
|
1131
|
+
baseHeaders["Upstash-Callback-Flow-Control-Value"] = flowControlValue;
|
|
1132
|
+
}
|
|
1133
|
+
} else {
|
|
1134
|
+
if (flowControl) {
|
|
1135
|
+
const { flowControlKey, flowControlValue } = prepareFlowControl(flowControl);
|
|
1136
|
+
baseHeaders["Upstash-Flow-Control-Key"] = flowControlKey;
|
|
1137
|
+
baseHeaders["Upstash-Flow-Control-Value"] = flowControlValue;
|
|
1138
|
+
}
|
|
1139
|
+
if (retries !== void 0) {
|
|
1140
|
+
baseHeaders["Upstash-Retries"] = retries.toString();
|
|
1141
|
+
baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
|
|
1142
|
+
}
|
|
1092
1143
|
}
|
|
1093
1144
|
if (userHeaders) {
|
|
1094
1145
|
for (const header of userHeaders.keys()) {
|
|
@@ -1123,6 +1174,7 @@ var getHeaders = ({
|
|
|
1123
1174
|
"Upstash-Callback-Forward-Upstash-Workflow-StepType": step.stepType,
|
|
1124
1175
|
"Upstash-Callback-Forward-Upstash-Workflow-Concurrent": step.concurrent.toString(),
|
|
1125
1176
|
"Upstash-Callback-Forward-Upstash-Workflow-ContentType": contentType,
|
|
1177
|
+
[`Upstash-Callback-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`]: (invokeCount ?? 0).toString(),
|
|
1126
1178
|
"Upstash-Workflow-CallType": "toCallback"
|
|
1127
1179
|
}
|
|
1128
1180
|
};
|
|
@@ -1180,9 +1232,159 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
|
|
|
1180
1232
|
);
|
|
1181
1233
|
}
|
|
1182
1234
|
};
|
|
1235
|
+
var prepareFlowControl = (flowControl) => {
|
|
1236
|
+
const parallelism = flowControl.parallelism?.toString();
|
|
1237
|
+
const rate = flowControl.ratePerSecond?.toString();
|
|
1238
|
+
const controlValue = [
|
|
1239
|
+
parallelism ? `parallelism=${parallelism}` : void 0,
|
|
1240
|
+
rate ? `rate=${rate}` : void 0
|
|
1241
|
+
].filter(Boolean);
|
|
1242
|
+
if (controlValue.length === 0) {
|
|
1243
|
+
throw new import_qstash3.QstashError("Provide at least one of parallelism or ratePerSecond for flowControl");
|
|
1244
|
+
}
|
|
1245
|
+
return {
|
|
1246
|
+
flowControlKey: flowControl.key,
|
|
1247
|
+
flowControlValue: controlValue.join(", ")
|
|
1248
|
+
};
|
|
1249
|
+
};
|
|
1183
1250
|
|
|
1184
1251
|
// src/context/auto-executor.ts
|
|
1185
1252
|
var import_qstash4 = require("@upstash/qstash");
|
|
1253
|
+
|
|
1254
|
+
// src/serve/serve-many.ts
|
|
1255
|
+
var getWorkflowId = (url) => {
|
|
1256
|
+
const components = url.split("/");
|
|
1257
|
+
const lastComponent = components[components.length - 1];
|
|
1258
|
+
return lastComponent.split("?")[0];
|
|
1259
|
+
};
|
|
1260
|
+
var serveManyBase = ({
|
|
1261
|
+
workflows,
|
|
1262
|
+
getUrl,
|
|
1263
|
+
serveMethod,
|
|
1264
|
+
options
|
|
1265
|
+
}) => {
|
|
1266
|
+
const workflowIds = [];
|
|
1267
|
+
const workflowMap = Object.fromEntries(
|
|
1268
|
+
Object.entries(workflows).map((workflow) => {
|
|
1269
|
+
const workflowId = workflow[0];
|
|
1270
|
+
if (workflowIds.includes(workflowId)) {
|
|
1271
|
+
throw new WorkflowError(
|
|
1272
|
+
`Duplicate workflow name found: '${workflowId}'. Please set different workflow names in serveMany.`
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
if (workflowId.includes("/")) {
|
|
1276
|
+
throw new WorkflowError(
|
|
1277
|
+
`Invalid workflow name found: '${workflowId}'. Workflow name cannot contain '/'.`
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
workflowIds.push(workflowId);
|
|
1281
|
+
workflow[1].workflowId = workflowId;
|
|
1282
|
+
workflow[1].options = {
|
|
1283
|
+
...options,
|
|
1284
|
+
...workflow[1].options
|
|
1285
|
+
};
|
|
1286
|
+
const params = [workflow[1].routeFunction, workflow[1].options];
|
|
1287
|
+
const handler = serveMethod(...params);
|
|
1288
|
+
return [workflowId, handler];
|
|
1289
|
+
})
|
|
1290
|
+
);
|
|
1291
|
+
return {
|
|
1292
|
+
handler: async (...params) => {
|
|
1293
|
+
const url = getUrl(...params);
|
|
1294
|
+
const pickedWorkflowId = getWorkflowId(url);
|
|
1295
|
+
if (!pickedWorkflowId) {
|
|
1296
|
+
return new Response(
|
|
1297
|
+
`Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
|
|
1298
|
+
{
|
|
1299
|
+
status: 404
|
|
1300
|
+
}
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
const workflow = workflowMap[pickedWorkflowId];
|
|
1304
|
+
if (!workflow) {
|
|
1305
|
+
return new Response(
|
|
1306
|
+
`No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
|
|
1307
|
+
{
|
|
1308
|
+
status: 404
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
return await workflow(...params);
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
};
|
|
1316
|
+
var invokeWorkflow = async ({
|
|
1317
|
+
settings,
|
|
1318
|
+
invokeStep,
|
|
1319
|
+
context,
|
|
1320
|
+
invokeCount,
|
|
1321
|
+
telemetry
|
|
1322
|
+
}) => {
|
|
1323
|
+
const {
|
|
1324
|
+
body,
|
|
1325
|
+
workflow,
|
|
1326
|
+
headers = {},
|
|
1327
|
+
workflowRunId = getWorkflowRunId(),
|
|
1328
|
+
retries,
|
|
1329
|
+
flowControl
|
|
1330
|
+
} = settings;
|
|
1331
|
+
const { workflowId } = workflow;
|
|
1332
|
+
const {
|
|
1333
|
+
retries: workflowRetries,
|
|
1334
|
+
failureFunction,
|
|
1335
|
+
failureUrl,
|
|
1336
|
+
useJSONContent,
|
|
1337
|
+
flowControl: workflowFlowControl
|
|
1338
|
+
} = workflow.options;
|
|
1339
|
+
if (!workflowId) {
|
|
1340
|
+
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
1341
|
+
}
|
|
1342
|
+
const { headers: invokerHeaders } = getHeaders({
|
|
1343
|
+
initHeaderValue: "false",
|
|
1344
|
+
workflowRunId: context.workflowRunId,
|
|
1345
|
+
workflowUrl: context.url,
|
|
1346
|
+
userHeaders: context.headers,
|
|
1347
|
+
failureUrl: context.failureUrl,
|
|
1348
|
+
retries: context.retries,
|
|
1349
|
+
telemetry,
|
|
1350
|
+
invokeCount,
|
|
1351
|
+
flowControl: context.flowControl
|
|
1352
|
+
});
|
|
1353
|
+
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
1354
|
+
const newUrl = context.url.replace(/[^/]+$/, workflowId);
|
|
1355
|
+
const { headers: triggerHeaders } = getHeaders({
|
|
1356
|
+
initHeaderValue: "true",
|
|
1357
|
+
workflowRunId,
|
|
1358
|
+
workflowUrl: newUrl,
|
|
1359
|
+
userHeaders: new Headers(headers),
|
|
1360
|
+
retries: retries ?? workflowRetries,
|
|
1361
|
+
telemetry,
|
|
1362
|
+
failureUrl: failureFunction ? newUrl : failureUrl,
|
|
1363
|
+
invokeCount: invokeCount + 1,
|
|
1364
|
+
flowControl: flowControl ?? workflowFlowControl
|
|
1365
|
+
});
|
|
1366
|
+
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
1367
|
+
if (useJSONContent) {
|
|
1368
|
+
triggerHeaders["content-type"] = "application/json";
|
|
1369
|
+
}
|
|
1370
|
+
const request = {
|
|
1371
|
+
body: JSON.stringify(body),
|
|
1372
|
+
headers: Object.fromEntries(
|
|
1373
|
+
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
1374
|
+
),
|
|
1375
|
+
workflowRunId,
|
|
1376
|
+
workflowUrl: context.url,
|
|
1377
|
+
step: invokeStep
|
|
1378
|
+
};
|
|
1379
|
+
await context.qstashClient.publish({
|
|
1380
|
+
headers: triggerHeaders,
|
|
1381
|
+
method: "POST",
|
|
1382
|
+
body: JSON.stringify(request),
|
|
1383
|
+
url: newUrl
|
|
1384
|
+
});
|
|
1385
|
+
};
|
|
1386
|
+
|
|
1387
|
+
// src/context/auto-executor.ts
|
|
1186
1388
|
var AutoExecutor = class _AutoExecutor {
|
|
1187
1389
|
context;
|
|
1188
1390
|
promises = /* @__PURE__ */ new WeakMap();
|
|
@@ -1191,14 +1393,16 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1191
1393
|
nonPlanStepCount;
|
|
1192
1394
|
steps;
|
|
1193
1395
|
indexInCurrentList = 0;
|
|
1396
|
+
invokeCount;
|
|
1194
1397
|
telemetry;
|
|
1195
1398
|
stepCount = 0;
|
|
1196
1399
|
planStepCount = 0;
|
|
1197
1400
|
executingStep = false;
|
|
1198
|
-
constructor(context, steps, telemetry, debug) {
|
|
1401
|
+
constructor(context, steps, telemetry, invokeCount, debug) {
|
|
1199
1402
|
this.context = context;
|
|
1200
1403
|
this.steps = steps;
|
|
1201
1404
|
this.telemetry = telemetry;
|
|
1405
|
+
this.invokeCount = invokeCount ?? 0;
|
|
1202
1406
|
this.debug = debug;
|
|
1203
1407
|
this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
|
|
1204
1408
|
}
|
|
@@ -1421,7 +1625,9 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1421
1625
|
step: waitStep,
|
|
1422
1626
|
failureUrl: this.context.failureUrl,
|
|
1423
1627
|
retries: this.context.retries,
|
|
1424
|
-
telemetry: this.telemetry
|
|
1628
|
+
telemetry: this.telemetry,
|
|
1629
|
+
invokeCount: this.invokeCount,
|
|
1630
|
+
flowControl: this.context.flowControl
|
|
1425
1631
|
});
|
|
1426
1632
|
const waitBody = {
|
|
1427
1633
|
url: this.context.url,
|
|
@@ -1449,17 +1655,13 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1449
1655
|
if (steps.length === 1 && lazySteps[0] instanceof LazyInvokeStep) {
|
|
1450
1656
|
const invokeStep = steps[0];
|
|
1451
1657
|
const lazyInvokeStep = lazySteps[0];
|
|
1452
|
-
await
|
|
1453
|
-
|
|
1454
|
-
body: lazyInvokeStep.params.body,
|
|
1455
|
-
headers: lazyInvokeStep.params.headers,
|
|
1456
|
-
workflowRunId: lazyInvokeStep.params.workflowRunId,
|
|
1457
|
-
workflow: lazyInvokeStep.params.workflow,
|
|
1458
|
-
retries: lazyInvokeStep.params.retries
|
|
1459
|
-
},
|
|
1658
|
+
await invokeWorkflow({
|
|
1659
|
+
settings: lazyInvokeStep.params,
|
|
1460
1660
|
invokeStep,
|
|
1461
|
-
this.context
|
|
1462
|
-
|
|
1661
|
+
context: this.context,
|
|
1662
|
+
invokeCount: this.invokeCount,
|
|
1663
|
+
telemetry: this.telemetry
|
|
1664
|
+
});
|
|
1463
1665
|
throw new WorkflowAbort(invokeStep.stepName, invokeStep);
|
|
1464
1666
|
}
|
|
1465
1667
|
const result = await this.context.qstashClient.batchJSON(
|
|
@@ -1475,11 +1677,14 @@ var AutoExecutor = class _AutoExecutor {
|
|
|
1475
1677
|
retries: this.context.retries,
|
|
1476
1678
|
callRetries: lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
|
|
1477
1679
|
callTimeout: lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0,
|
|
1478
|
-
telemetry: this.telemetry
|
|
1680
|
+
telemetry: this.telemetry,
|
|
1681
|
+
invokeCount: this.invokeCount,
|
|
1682
|
+
flowControl: this.context.flowControl,
|
|
1683
|
+
callFlowControl: lazyStep instanceof LazyCallStep ? lazyStep.flowControl : void 0
|
|
1479
1684
|
});
|
|
1480
1685
|
const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
|
|
1481
1686
|
singleStep.out = JSON.stringify(singleStep.out);
|
|
1482
|
-
return singleStep.callUrl ? (
|
|
1687
|
+
return singleStep.callUrl && lazyStep instanceof LazyCallStep ? (
|
|
1483
1688
|
// if the step is a third party call, we call the third party
|
|
1484
1689
|
// url (singleStep.callUrl) and pass information about the workflow
|
|
1485
1690
|
// in the headers (handled in getHeaders). QStash makes the request
|
|
@@ -1779,9 +1984,10 @@ var wrapTools = ({
|
|
|
1779
1984
|
return Object.fromEntries(
|
|
1780
1985
|
Object.entries(tools).map((toolInfo) => {
|
|
1781
1986
|
const [toolName, tool3] = toolInfo;
|
|
1987
|
+
const executeAsStep = "executeAsStep" in tool3 ? tool3.executeAsStep : true;
|
|
1782
1988
|
const aiSDKTool = convertToAISDKTool(tool3);
|
|
1783
1989
|
const execute = aiSDKTool.execute;
|
|
1784
|
-
if (execute) {
|
|
1990
|
+
if (execute && executeAsStep) {
|
|
1785
1991
|
const wrappedExecute = (...params) => {
|
|
1786
1992
|
return context.run(`Run tool ${toolName}`, () => execute(...params));
|
|
1787
1993
|
};
|
|
@@ -2135,6 +2341,11 @@ var WorkflowContext = class {
|
|
|
2135
2341
|
* Number of retries
|
|
2136
2342
|
*/
|
|
2137
2343
|
retries;
|
|
2344
|
+
/**
|
|
2345
|
+
* Settings for controlling the number of active requests
|
|
2346
|
+
* and number of requests per second with the same key.
|
|
2347
|
+
*/
|
|
2348
|
+
flowControl;
|
|
2138
2349
|
constructor({
|
|
2139
2350
|
qstashClient,
|
|
2140
2351
|
workflowRunId,
|
|
@@ -2146,7 +2357,9 @@ var WorkflowContext = class {
|
|
|
2146
2357
|
initialPayload,
|
|
2147
2358
|
env,
|
|
2148
2359
|
retries,
|
|
2149
|
-
telemetry
|
|
2360
|
+
telemetry,
|
|
2361
|
+
invokeCount,
|
|
2362
|
+
flowControl
|
|
2150
2363
|
}) {
|
|
2151
2364
|
this.qstashClient = qstashClient;
|
|
2152
2365
|
this.workflowRunId = workflowRunId;
|
|
@@ -2157,7 +2370,8 @@ var WorkflowContext = class {
|
|
|
2157
2370
|
this.requestPayload = initialPayload;
|
|
2158
2371
|
this.env = env ?? {};
|
|
2159
2372
|
this.retries = retries ?? DEFAULT_RETRIES;
|
|
2160
|
-
this.
|
|
2373
|
+
this.flowControl = flowControl;
|
|
2374
|
+
this.executor = new AutoExecutor(this, this.steps, telemetry, invokeCount, debug);
|
|
2161
2375
|
}
|
|
2162
2376
|
/**
|
|
2163
2377
|
* Executes a workflow step
|
|
@@ -2259,7 +2473,7 @@ var WorkflowContext = class {
|
|
|
2259
2473
|
* }
|
|
2260
2474
|
*/
|
|
2261
2475
|
async call(stepName, settings) {
|
|
2262
|
-
const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
|
|
2476
|
+
const { url, method = "GET", body, headers = {}, retries = 0, timeout, flowControl } = settings;
|
|
2263
2477
|
const result = await this.addStep(
|
|
2264
2478
|
new LazyCallStep(
|
|
2265
2479
|
stepName,
|
|
@@ -2268,7 +2482,8 @@ var WorkflowContext = class {
|
|
|
2268
2482
|
body,
|
|
2269
2483
|
headers,
|
|
2270
2484
|
retries,
|
|
2271
|
-
timeout
|
|
2485
|
+
timeout,
|
|
2486
|
+
flowControl
|
|
2272
2487
|
)
|
|
2273
2488
|
);
|
|
2274
2489
|
if (typeof result === "string") {
|
|
@@ -2505,7 +2720,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
|
|
|
2505
2720
|
failureUrl: context.failureUrl,
|
|
2506
2721
|
initialPayload: context.requestPayload,
|
|
2507
2722
|
env: context.env,
|
|
2508
|
-
retries: context.retries
|
|
2723
|
+
retries: context.retries,
|
|
2724
|
+
flowControl: context.flowControl
|
|
2509
2725
|
});
|
|
2510
2726
|
try {
|
|
2511
2727
|
await routeFunction(disabledContext);
|
|
@@ -2658,7 +2874,7 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
|
|
|
2658
2874
|
};
|
|
2659
2875
|
}
|
|
2660
2876
|
};
|
|
2661
|
-
var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, debug) => {
|
|
2877
|
+
var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, flowControl, debug) => {
|
|
2662
2878
|
if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
|
|
2663
2879
|
return ok("not-failure-callback");
|
|
2664
2880
|
}
|
|
@@ -2670,22 +2886,21 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
|
|
|
2670
2886
|
);
|
|
2671
2887
|
}
|
|
2672
2888
|
try {
|
|
2673
|
-
const { status, header, body, url,
|
|
2674
|
-
requestPayload
|
|
2675
|
-
);
|
|
2889
|
+
const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
|
|
2676
2890
|
const decodedBody = body ? decodeBase64(body) : "{}";
|
|
2677
2891
|
const errorPayload = JSON.parse(decodedBody);
|
|
2678
2892
|
const workflowContext = new WorkflowContext({
|
|
2679
2893
|
qstashClient,
|
|
2680
2894
|
workflowRunId,
|
|
2681
2895
|
initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
|
|
2682
|
-
headers: recreateUserHeaders(
|
|
2896
|
+
headers: recreateUserHeaders(request.headers),
|
|
2683
2897
|
steps: [],
|
|
2684
2898
|
url,
|
|
2685
2899
|
failureUrl: url,
|
|
2686
2900
|
debug,
|
|
2687
2901
|
env,
|
|
2688
2902
|
retries,
|
|
2903
|
+
flowControl,
|
|
2689
2904
|
telemetry: void 0
|
|
2690
2905
|
// not going to make requests in authentication check
|
|
2691
2906
|
});
|
|
@@ -2812,7 +3027,8 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2812
3027
|
env,
|
|
2813
3028
|
retries,
|
|
2814
3029
|
useJSONContent,
|
|
2815
|
-
disableTelemetry
|
|
3030
|
+
disableTelemetry,
|
|
3031
|
+
flowControl
|
|
2816
3032
|
} = processOptions(options);
|
|
2817
3033
|
telemetry = disableTelemetry ? void 0 : telemetry;
|
|
2818
3034
|
const debug = WorkflowLogger.getLogger(verbose);
|
|
@@ -2853,6 +3069,7 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2853
3069
|
failureFunction,
|
|
2854
3070
|
env,
|
|
2855
3071
|
retries,
|
|
3072
|
+
flowControl,
|
|
2856
3073
|
debug
|
|
2857
3074
|
);
|
|
2858
3075
|
if (failureCheck.isErr()) {
|
|
@@ -2861,6 +3078,7 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2861
3078
|
await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
|
|
2862
3079
|
return onStepFinish(workflowRunId, "failure-callback");
|
|
2863
3080
|
}
|
|
3081
|
+
const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
|
|
2864
3082
|
const workflowContext = new WorkflowContext({
|
|
2865
3083
|
qstashClient,
|
|
2866
3084
|
workflowRunId,
|
|
@@ -2872,7 +3090,9 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2872
3090
|
debug,
|
|
2873
3091
|
env,
|
|
2874
3092
|
retries,
|
|
2875
|
-
telemetry
|
|
3093
|
+
telemetry,
|
|
3094
|
+
invokeCount,
|
|
3095
|
+
flowControl
|
|
2876
3096
|
});
|
|
2877
3097
|
const authCheck = await DisabledWorkflowContext.tryAuthentication(
|
|
2878
3098
|
routeFunction,
|
|
@@ -2895,6 +3115,7 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2895
3115
|
workflowUrl,
|
|
2896
3116
|
failureUrl: workflowFailureUrl,
|
|
2897
3117
|
retries,
|
|
3118
|
+
flowControl,
|
|
2898
3119
|
telemetry,
|
|
2899
3120
|
debug
|
|
2900
3121
|
});
|
|
@@ -2904,7 +3125,13 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2904
3125
|
});
|
|
2905
3126
|
throw callReturnCheck.error;
|
|
2906
3127
|
} else if (callReturnCheck.value === "continue-workflow") {
|
|
2907
|
-
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3128
|
+
const result = isFirstInvocation ? await triggerFirstInvocation({
|
|
3129
|
+
workflowContext,
|
|
3130
|
+
useJSONContent,
|
|
3131
|
+
telemetry,
|
|
3132
|
+
debug,
|
|
3133
|
+
invokeCount
|
|
3134
|
+
}) : await triggerRouteFunction({
|
|
2908
3135
|
onStep: async () => routeFunction(workflowContext),
|
|
2909
3136
|
onCleanup: async (result2) => {
|
|
2910
3137
|
await triggerWorkflowDelete(workflowContext, result2, debug);
|
|
@@ -2939,91 +3166,6 @@ var serveBase = (routeFunction, telemetry, options) => {
|
|
|
2939
3166
|
return { handler: safeHandler };
|
|
2940
3167
|
};
|
|
2941
3168
|
|
|
2942
|
-
// src/serve/serve-many.ts
|
|
2943
|
-
var serveManyBase = ({
|
|
2944
|
-
workflows,
|
|
2945
|
-
getWorkflowId
|
|
2946
|
-
}) => {
|
|
2947
|
-
const workflowIds = [];
|
|
2948
|
-
const workflowMap = Object.fromEntries(
|
|
2949
|
-
Object.entries(workflows).map((workflow) => {
|
|
2950
|
-
const workflowId = workflow[0];
|
|
2951
|
-
if (workflowIds.includes(workflowId)) {
|
|
2952
|
-
throw new WorkflowError(
|
|
2953
|
-
`Duplicate workflow name found: '${workflowId}'. Please set different workflow names in serveMany.`
|
|
2954
|
-
);
|
|
2955
|
-
}
|
|
2956
|
-
if (workflowId.includes("/")) {
|
|
2957
|
-
throw new WorkflowError(
|
|
2958
|
-
`Invalid workflow name found: '${workflowId}'. Workflow name cannot contain '/'.`
|
|
2959
|
-
);
|
|
2960
|
-
}
|
|
2961
|
-
workflowIds.push(workflowId);
|
|
2962
|
-
workflow[1].workflowId = workflowId;
|
|
2963
|
-
return [workflowId, workflow[1].handler];
|
|
2964
|
-
})
|
|
2965
|
-
);
|
|
2966
|
-
return {
|
|
2967
|
-
handler: async (...params) => {
|
|
2968
|
-
const pickedWorkflowId = getWorkflowId(...params);
|
|
2969
|
-
if (!pickedWorkflowId) {
|
|
2970
|
-
throw new WorkflowError(`Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`);
|
|
2971
|
-
}
|
|
2972
|
-
const workflow = workflowMap[pickedWorkflowId];
|
|
2973
|
-
if (!workflow) {
|
|
2974
|
-
throw new WorkflowError(`No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`);
|
|
2975
|
-
}
|
|
2976
|
-
return await workflow(...params);
|
|
2977
|
-
}
|
|
2978
|
-
};
|
|
2979
|
-
};
|
|
2980
|
-
var createInvokeCallback = (telemetry) => {
|
|
2981
|
-
const invokeCallback = async (settings, invokeStep, context) => {
|
|
2982
|
-
const { body, workflow, headers = {}, workflowRunId = getWorkflowRunId(), retries } = settings;
|
|
2983
|
-
const { workflowId } = workflow;
|
|
2984
|
-
if (!workflowId) {
|
|
2985
|
-
throw new WorkflowError("You can only invoke workflow which has a workflowId");
|
|
2986
|
-
}
|
|
2987
|
-
const { headers: invokerHeaders } = getHeaders({
|
|
2988
|
-
initHeaderValue: "false",
|
|
2989
|
-
workflowRunId: context.workflowRunId,
|
|
2990
|
-
workflowUrl: context.url,
|
|
2991
|
-
userHeaders: context.headers,
|
|
2992
|
-
failureUrl: context.failureUrl,
|
|
2993
|
-
retries: context.retries,
|
|
2994
|
-
telemetry
|
|
2995
|
-
});
|
|
2996
|
-
invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
|
|
2997
|
-
const newUrl = context.url.replace(/[^/]+$/, workflowId);
|
|
2998
|
-
const { headers: triggerHeaders } = getHeaders({
|
|
2999
|
-
initHeaderValue: "true",
|
|
3000
|
-
workflowRunId,
|
|
3001
|
-
workflowUrl: newUrl,
|
|
3002
|
-
userHeaders: new Headers(headers),
|
|
3003
|
-
retries,
|
|
3004
|
-
telemetry
|
|
3005
|
-
});
|
|
3006
|
-
triggerHeaders["Upstash-Workflow-Invoke"] = "true";
|
|
3007
|
-
const request = {
|
|
3008
|
-
body: JSON.stringify(body),
|
|
3009
|
-
headers: Object.fromEntries(
|
|
3010
|
-
Object.entries(invokerHeaders).map((pairs) => [pairs[0], [pairs[1]]])
|
|
3011
|
-
),
|
|
3012
|
-
workflowRunId,
|
|
3013
|
-
workflowUrl: context.url,
|
|
3014
|
-
step: invokeStep
|
|
3015
|
-
};
|
|
3016
|
-
await context.qstashClient.publish({
|
|
3017
|
-
headers: triggerHeaders,
|
|
3018
|
-
method: "POST",
|
|
3019
|
-
body: JSON.stringify(request),
|
|
3020
|
-
url: newUrl
|
|
3021
|
-
});
|
|
3022
|
-
return void 0;
|
|
3023
|
-
};
|
|
3024
|
-
return invokeCallback;
|
|
3025
|
-
};
|
|
3026
|
-
|
|
3027
3169
|
// platforms/nextjs.ts
|
|
3028
3170
|
var appTelemetry = {
|
|
3029
3171
|
sdk: SDK_TELEMETRY,
|
|
@@ -3048,21 +3190,22 @@ var serve = (routeFunction, options) => {
|
|
|
3048
3190
|
};
|
|
3049
3191
|
};
|
|
3050
3192
|
var createWorkflow = (...params) => {
|
|
3051
|
-
const
|
|
3193
|
+
const [routeFunction, options = {}] = params;
|
|
3052
3194
|
return {
|
|
3053
|
-
|
|
3054
|
-
|
|
3195
|
+
routeFunction,
|
|
3196
|
+
options,
|
|
3055
3197
|
workflowId: void 0
|
|
3056
3198
|
};
|
|
3057
3199
|
};
|
|
3058
|
-
var serveMany = (workflows) => {
|
|
3200
|
+
var serveMany = (workflows, options) => {
|
|
3059
3201
|
return {
|
|
3060
3202
|
POST: serveManyBase({
|
|
3061
3203
|
workflows,
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3204
|
+
getUrl(params) {
|
|
3205
|
+
return params.url;
|
|
3206
|
+
},
|
|
3207
|
+
serveMethod: (...params) => serve(...params).POST,
|
|
3208
|
+
options
|
|
3066
3209
|
}).handler
|
|
3067
3210
|
};
|
|
3068
3211
|
};
|
|
@@ -3091,24 +3234,24 @@ var servePagesRouter = (routeFunction, options) => {
|
|
|
3091
3234
|
};
|
|
3092
3235
|
};
|
|
3093
3236
|
var createWorkflowPagesRouter = (...params) => {
|
|
3094
|
-
const
|
|
3237
|
+
const [routeFunction, options = {}] = params;
|
|
3095
3238
|
return {
|
|
3096
|
-
|
|
3097
|
-
|
|
3239
|
+
routeFunction,
|
|
3240
|
+
options,
|
|
3098
3241
|
workflowId: void 0
|
|
3099
3242
|
};
|
|
3100
3243
|
};
|
|
3101
|
-
var serveManyPagesRouter = (workflows) => {
|
|
3244
|
+
var serveManyPagesRouter = (workflows, options) => {
|
|
3102
3245
|
return serveManyBase({
|
|
3103
3246
|
workflows,
|
|
3104
|
-
|
|
3247
|
+
getUrl(request_) {
|
|
3105
3248
|
const protocol = request_.headers["x-forwarded-proto"];
|
|
3106
3249
|
const host = request_.headers.host;
|
|
3107
3250
|
const baseUrl = `${protocol}://${host}`;
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3251
|
+
return `${baseUrl}${request_.url}`;
|
|
3252
|
+
},
|
|
3253
|
+
serveMethod: (...params) => servePagesRouter(...params).handler,
|
|
3254
|
+
options
|
|
3112
3255
|
});
|
|
3113
3256
|
};
|
|
3114
3257
|
// Annotate the CommonJS export names for ESM import in node:
|