@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/index.js CHANGED
@@ -26,6 +26,7 @@ __export(src_exports, {
26
26
  WorkflowContext: () => WorkflowContext,
27
27
  WorkflowError: () => WorkflowError,
28
28
  WorkflowLogger: () => WorkflowLogger,
29
+ WorkflowTool: () => WorkflowTool,
29
30
  serve: () => serve
30
31
  });
31
32
  module.exports = __toCommonJS(src_exports);
@@ -96,6 +97,7 @@ var WORKFLOW_INIT_HEADER = "Upstash-Workflow-Init";
96
97
  var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
97
98
  var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
98
99
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
100
+ var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
99
101
  var WORKFLOW_PROTOCOL_VERSION = "1";
100
102
  var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
101
103
  var DEFAULT_CONTENT_TYPE = "application/json";
@@ -277,8 +279,9 @@ var LazyCallStep = class extends BaseLazyStep {
277
279
  headers;
278
280
  retries;
279
281
  timeout;
282
+ flowControl;
280
283
  stepType = "Call";
281
- constructor(stepName, url, method, body, headers, retries, timeout) {
284
+ constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
282
285
  super(stepName);
283
286
  this.url = url;
284
287
  this.method = method;
@@ -286,6 +289,7 @@ var LazyCallStep = class extends BaseLazyStep {
286
289
  this.headers = headers;
287
290
  this.retries = retries;
288
291
  this.timeout = timeout;
292
+ this.flowControl = flowControl;
289
293
  }
290
294
  getPlanStep(concurrent, targetStep) {
291
295
  return {
@@ -356,14 +360,22 @@ var LazyNotifyStep = class extends LazyFunctionStep {
356
360
  var LazyInvokeStep = class extends BaseLazyStep {
357
361
  stepType = "Invoke";
358
362
  params;
359
- constructor(stepName, { workflow, body, headers = {}, workflowRunId, retries }) {
363
+ constructor(stepName, {
364
+ workflow,
365
+ body,
366
+ headers = {},
367
+ workflowRunId,
368
+ retries,
369
+ flowControl
370
+ }) {
360
371
  super(stepName);
361
372
  this.params = {
362
373
  workflow,
363
374
  body,
364
375
  headers,
365
376
  workflowRunId: getWorkflowRunId(workflowRunId),
366
- retries
377
+ retries,
378
+ flowControl
367
379
  };
368
380
  }
369
381
  getPlanStep(concurrent, targetStep) {
@@ -822,7 +834,8 @@ var triggerFirstInvocation = async ({
822
834
  workflowContext,
823
835
  useJSONContent,
824
836
  telemetry,
825
- debug
837
+ debug,
838
+ invokeCount
826
839
  }) => {
827
840
  const { headers } = getHeaders({
828
841
  initHeaderValue: "true",
@@ -831,7 +844,9 @@ var triggerFirstInvocation = async ({
831
844
  userHeaders: workflowContext.headers,
832
845
  failureUrl: workflowContext.failureUrl,
833
846
  retries: workflowContext.retries,
834
- telemetry
847
+ telemetry,
848
+ invokeCount,
849
+ flowControl: workflowContext.flowControl
835
850
  });
836
851
  if (workflowContext.headers.get("content-type")) {
837
852
  headers["content-type"] = workflowContext.headers.get("content-type");
@@ -937,6 +952,7 @@ var handleThirdPartyCallResult = async ({
937
952
  failureUrl,
938
953
  retries,
939
954
  telemetry,
955
+ flowControl,
940
956
  debug
941
957
  }) => {
942
958
  try {
@@ -984,6 +1000,7 @@ ${atob(callbackMessage.body ?? "")}`
984
1000
  const stepType = request.headers.get("Upstash-Workflow-StepType");
985
1001
  const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
986
1002
  const contentType = request.headers.get("Upstash-Workflow-ContentType");
1003
+ const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
987
1004
  if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
988
1005
  throw new Error(
989
1006
  `Missing info in callback message source header: ${JSON.stringify({
@@ -1004,7 +1021,9 @@ ${atob(callbackMessage.body ?? "")}`
1004
1021
  userHeaders,
1005
1022
  failureUrl,
1006
1023
  retries,
1007
- telemetry
1024
+ telemetry,
1025
+ invokeCount: Number(invokeCount),
1026
+ flowControl
1008
1027
  });
1009
1028
  const callResponse = {
1010
1029
  status: callbackMessage.status,
@@ -1060,7 +1079,10 @@ var getHeaders = ({
1060
1079
  step,
1061
1080
  callRetries,
1062
1081
  callTimeout,
1063
- telemetry
1082
+ telemetry,
1083
+ invokeCount,
1084
+ flowControl,
1085
+ callFlowControl
1064
1086
  }) => {
1065
1087
  const contentType = (userHeaders ? userHeaders.get("Content-Type") : void 0) ?? DEFAULT_CONTENT_TYPE;
1066
1088
  const baseHeaders = {
@@ -1072,6 +1094,9 @@ var getHeaders = ({
1072
1094
  "content-type": contentType,
1073
1095
  ...telemetry ? getTelemetryHeaders(telemetry) : {}
1074
1096
  };
1097
+ if (invokeCount !== void 0 && !step?.callUrl) {
1098
+ baseHeaders[`Upstash-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`] = invokeCount.toString();
1099
+ }
1075
1100
  if (!step?.callUrl) {
1076
1101
  baseHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
1077
1102
  }
@@ -1080,13 +1105,23 @@ var getHeaders = ({
1080
1105
  }
1081
1106
  if (failureUrl) {
1082
1107
  baseHeaders[`Upstash-Failure-Callback-Forward-${WORKFLOW_FAILURE_HEADER}`] = "true";
1108
+ baseHeaders[`Upstash-Failure-Callback-Forward-Upstash-Workflow-Failure-Callback`] = "true";
1109
+ baseHeaders["Upstash-Failure-Callback-Workflow-Runid"] = workflowRunId;
1110
+ baseHeaders["Upstash-Failure-Callback-Workflow-Init"] = "false";
1111
+ baseHeaders["Upstash-Failure-Callback-Workflow-Url"] = workflowUrl;
1112
+ baseHeaders["Upstash-Failure-Callback-Workflow-Calltype"] = "failureCall";
1113
+ if (retries !== void 0) {
1114
+ baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
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
+ }
1083
1121
  if (!step?.callUrl) {
1084
1122
  baseHeaders["Upstash-Failure-Callback"] = failureUrl;
1085
1123
  }
1086
1124
  }
1087
- if (step?.stepType === "Invoke") {
1088
- baseHeaders["upstash-workflow-invoke"] = "true";
1089
- }
1090
1125
  if (step?.callUrl) {
1091
1126
  baseHeaders["Upstash-Retries"] = callRetries?.toString() ?? "0";
1092
1127
  baseHeaders[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
@@ -1094,9 +1129,26 @@ var getHeaders = ({
1094
1129
  baseHeaders["Upstash-Callback-Retries"] = retries.toString();
1095
1130
  baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
1096
1131
  }
1097
- } else if (retries !== void 0) {
1098
- baseHeaders["Upstash-Retries"] = retries.toString();
1099
- baseHeaders["Upstash-Failure-Callback-Retries"] = retries.toString();
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
+ }
1100
1152
  }
1101
1153
  if (userHeaders) {
1102
1154
  for (const header of userHeaders.keys()) {
@@ -1131,6 +1183,7 @@ var getHeaders = ({
1131
1183
  "Upstash-Callback-Forward-Upstash-Workflow-StepType": step.stepType,
1132
1184
  "Upstash-Callback-Forward-Upstash-Workflow-Concurrent": step.concurrent.toString(),
1133
1185
  "Upstash-Callback-Forward-Upstash-Workflow-ContentType": contentType,
1186
+ [`Upstash-Callback-Forward-${WORKFLOW_INVOKE_COUNT_HEADER}`]: (invokeCount ?? 0).toString(),
1134
1187
  "Upstash-Workflow-CallType": "toCallback"
1135
1188
  }
1136
1189
  };
@@ -1188,9 +1241,98 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1188
1241
  );
1189
1242
  }
1190
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
+ };
1191
1259
 
1192
1260
  // src/context/auto-executor.ts
1193
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
1194
1336
  var AutoExecutor = class _AutoExecutor {
1195
1337
  context;
1196
1338
  promises = /* @__PURE__ */ new WeakMap();
@@ -1199,14 +1341,16 @@ var AutoExecutor = class _AutoExecutor {
1199
1341
  nonPlanStepCount;
1200
1342
  steps;
1201
1343
  indexInCurrentList = 0;
1344
+ invokeCount;
1202
1345
  telemetry;
1203
1346
  stepCount = 0;
1204
1347
  planStepCount = 0;
1205
1348
  executingStep = false;
1206
- constructor(context, steps, telemetry, debug) {
1349
+ constructor(context, steps, telemetry, invokeCount, debug) {
1207
1350
  this.context = context;
1208
1351
  this.steps = steps;
1209
1352
  this.telemetry = telemetry;
1353
+ this.invokeCount = invokeCount ?? 0;
1210
1354
  this.debug = debug;
1211
1355
  this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
1212
1356
  }
@@ -1429,7 +1573,9 @@ var AutoExecutor = class _AutoExecutor {
1429
1573
  step: waitStep,
1430
1574
  failureUrl: this.context.failureUrl,
1431
1575
  retries: this.context.retries,
1432
- telemetry: this.telemetry
1576
+ telemetry: this.telemetry,
1577
+ invokeCount: this.invokeCount,
1578
+ flowControl: this.context.flowControl
1433
1579
  });
1434
1580
  const waitBody = {
1435
1581
  url: this.context.url,
@@ -1457,17 +1603,13 @@ var AutoExecutor = class _AutoExecutor {
1457
1603
  if (steps.length === 1 && lazySteps[0] instanceof LazyInvokeStep) {
1458
1604
  const invokeStep = steps[0];
1459
1605
  const lazyInvokeStep = lazySteps[0];
1460
- await lazyInvokeStep.params.workflow.callback(
1461
- {
1462
- body: lazyInvokeStep.params.body,
1463
- headers: lazyInvokeStep.params.headers,
1464
- workflowRunId: lazyInvokeStep.params.workflowRunId,
1465
- workflow: lazyInvokeStep.params.workflow,
1466
- retries: lazyInvokeStep.params.retries
1467
- },
1606
+ await invokeWorkflow({
1607
+ settings: lazyInvokeStep.params,
1468
1608
  invokeStep,
1469
- this.context
1470
- );
1609
+ context: this.context,
1610
+ invokeCount: this.invokeCount,
1611
+ telemetry: this.telemetry
1612
+ });
1471
1613
  throw new WorkflowAbort(invokeStep.stepName, invokeStep);
1472
1614
  }
1473
1615
  const result = await this.context.qstashClient.batchJSON(
@@ -1483,11 +1625,14 @@ var AutoExecutor = class _AutoExecutor {
1483
1625
  retries: this.context.retries,
1484
1626
  callRetries: lazyStep instanceof LazyCallStep ? lazyStep.retries : void 0,
1485
1627
  callTimeout: lazyStep instanceof LazyCallStep ? lazyStep.timeout : void 0,
1486
- 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
1487
1632
  });
1488
1633
  const willWait = singleStep.concurrent === NO_CONCURRENCY || singleStep.stepId === 0;
1489
1634
  singleStep.out = JSON.stringify(singleStep.out);
1490
- return singleStep.callUrl ? (
1635
+ return singleStep.callUrl && lazyStep instanceof LazyCallStep ? (
1491
1636
  // if the step is a third party call, we call the third party
1492
1637
  // url (singleStep.callUrl) and pass information about the workflow
1493
1638
  // in the headers (handled in getHeaders). QStash makes the request
@@ -1787,9 +1932,10 @@ var wrapTools = ({
1787
1932
  return Object.fromEntries(
1788
1933
  Object.entries(tools).map((toolInfo) => {
1789
1934
  const [toolName, tool3] = toolInfo;
1935
+ const executeAsStep = "executeAsStep" in tool3 ? tool3.executeAsStep : true;
1790
1936
  const aiSDKTool = convertToAISDKTool(tool3);
1791
1937
  const execute = aiSDKTool.execute;
1792
- if (execute) {
1938
+ if (execute && executeAsStep) {
1793
1939
  const wrappedExecute = (...params) => {
1794
1940
  return context.run(`Run tool ${toolName}`, () => execute(...params));
1795
1941
  };
@@ -1810,6 +1956,37 @@ var convertLangchainTool = (langchainTool) => {
1810
1956
  execute: async (...param) => langchainTool.invoke(...param)
1811
1957
  });
1812
1958
  };
1959
+ var WorkflowTool = class {
1960
+ /**
1961
+ * description of the tool
1962
+ */
1963
+ description;
1964
+ /**
1965
+ * schema of the tool
1966
+ */
1967
+ schema;
1968
+ /**
1969
+ * function to invoke the tool
1970
+ */
1971
+ invoke;
1972
+ /**
1973
+ * whether the invoke method of the tool is to be wrapped with `context.run`
1974
+ */
1975
+ executeAsStep;
1976
+ /**
1977
+ *
1978
+ * @param description description of the tool
1979
+ * @param schema schema of the tool
1980
+ * @param invoke function to invoke the tool
1981
+ * @param executeAsStep whether the invoke method of the tool is to be wrapped with `context.run`
1982
+ */
1983
+ constructor(params) {
1984
+ this.description = params.description;
1985
+ this.schema = params.schema;
1986
+ this.invoke = params.invoke;
1987
+ this.executeAsStep = params.executeAsStep ?? true;
1988
+ }
1989
+ };
1813
1990
 
1814
1991
  // src/agents/agent.ts
1815
1992
  var import_zod = require("zod");
@@ -2143,6 +2320,11 @@ var WorkflowContext = class {
2143
2320
  * Number of retries
2144
2321
  */
2145
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;
2146
2328
  constructor({
2147
2329
  qstashClient,
2148
2330
  workflowRunId,
@@ -2154,7 +2336,9 @@ var WorkflowContext = class {
2154
2336
  initialPayload,
2155
2337
  env,
2156
2338
  retries,
2157
- telemetry
2339
+ telemetry,
2340
+ invokeCount,
2341
+ flowControl
2158
2342
  }) {
2159
2343
  this.qstashClient = qstashClient;
2160
2344
  this.workflowRunId = workflowRunId;
@@ -2165,7 +2349,8 @@ var WorkflowContext = class {
2165
2349
  this.requestPayload = initialPayload;
2166
2350
  this.env = env ?? {};
2167
2351
  this.retries = retries ?? DEFAULT_RETRIES;
2168
- this.executor = new AutoExecutor(this, this.steps, telemetry, debug);
2352
+ this.flowControl = flowControl;
2353
+ this.executor = new AutoExecutor(this, this.steps, telemetry, invokeCount, debug);
2169
2354
  }
2170
2355
  /**
2171
2356
  * Executes a workflow step
@@ -2267,7 +2452,7 @@ var WorkflowContext = class {
2267
2452
  * }
2268
2453
  */
2269
2454
  async call(stepName, settings) {
2270
- const { url, method = "GET", body, headers = {}, retries = 0, timeout } = settings;
2455
+ const { url, method = "GET", body, headers = {}, retries = 0, timeout, flowControl } = settings;
2271
2456
  const result = await this.addStep(
2272
2457
  new LazyCallStep(
2273
2458
  stepName,
@@ -2276,7 +2461,8 @@ var WorkflowContext = class {
2276
2461
  body,
2277
2462
  headers,
2278
2463
  retries,
2279
- timeout
2464
+ timeout,
2465
+ flowControl
2280
2466
  )
2281
2467
  );
2282
2468
  if (typeof result === "string") {
@@ -2513,7 +2699,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2513
2699
  failureUrl: context.failureUrl,
2514
2700
  initialPayload: context.requestPayload,
2515
2701
  env: context.env,
2516
- retries: context.retries
2702
+ retries: context.retries,
2703
+ flowControl: context.flowControl
2517
2704
  });
2518
2705
  try {
2519
2706
  await routeFunction(disabledContext);
@@ -2666,7 +2853,7 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
2666
2853
  };
2667
2854
  }
2668
2855
  };
2669
- 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) => {
2670
2857
  if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
2671
2858
  return ok("not-failure-callback");
2672
2859
  }
@@ -2678,22 +2865,21 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
2678
2865
  );
2679
2866
  }
2680
2867
  try {
2681
- const { status, header, body, url, sourceHeader, sourceBody, workflowRunId } = JSON.parse(
2682
- requestPayload
2683
- );
2868
+ const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
2684
2869
  const decodedBody = body ? decodeBase64(body) : "{}";
2685
2870
  const errorPayload = JSON.parse(decodedBody);
2686
2871
  const workflowContext = new WorkflowContext({
2687
2872
  qstashClient,
2688
2873
  workflowRunId,
2689
2874
  initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
2690
- headers: recreateUserHeaders(new Headers(sourceHeader)),
2875
+ headers: recreateUserHeaders(request.headers),
2691
2876
  steps: [],
2692
2877
  url,
2693
2878
  failureUrl: url,
2694
2879
  debug,
2695
2880
  env,
2696
2881
  retries,
2882
+ flowControl,
2697
2883
  telemetry: void 0
2698
2884
  // not going to make requests in authentication check
2699
2885
  });
@@ -2820,7 +3006,8 @@ var serveBase = (routeFunction, telemetry, options) => {
2820
3006
  env,
2821
3007
  retries,
2822
3008
  useJSONContent,
2823
- disableTelemetry
3009
+ disableTelemetry,
3010
+ flowControl
2824
3011
  } = processOptions(options);
2825
3012
  telemetry = disableTelemetry ? void 0 : telemetry;
2826
3013
  const debug = WorkflowLogger.getLogger(verbose);
@@ -2861,6 +3048,7 @@ var serveBase = (routeFunction, telemetry, options) => {
2861
3048
  failureFunction,
2862
3049
  env,
2863
3050
  retries,
3051
+ flowControl,
2864
3052
  debug
2865
3053
  );
2866
3054
  if (failureCheck.isErr()) {
@@ -2869,6 +3057,7 @@ var serveBase = (routeFunction, telemetry, options) => {
2869
3057
  await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
2870
3058
  return onStepFinish(workflowRunId, "failure-callback");
2871
3059
  }
3060
+ const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
2872
3061
  const workflowContext = new WorkflowContext({
2873
3062
  qstashClient,
2874
3063
  workflowRunId,
@@ -2880,7 +3069,9 @@ var serveBase = (routeFunction, telemetry, options) => {
2880
3069
  debug,
2881
3070
  env,
2882
3071
  retries,
2883
- telemetry
3072
+ telemetry,
3073
+ invokeCount,
3074
+ flowControl
2884
3075
  });
2885
3076
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
2886
3077
  routeFunction,
@@ -2903,6 +3094,7 @@ var serveBase = (routeFunction, telemetry, options) => {
2903
3094
  workflowUrl,
2904
3095
  failureUrl: workflowFailureUrl,
2905
3096
  retries,
3097
+ flowControl,
2906
3098
  telemetry,
2907
3099
  debug
2908
3100
  });
@@ -2912,7 +3104,13 @@ var serveBase = (routeFunction, telemetry, options) => {
2912
3104
  });
2913
3105
  throw callReturnCheck.error;
2914
3106
  } else if (callReturnCheck.value === "continue-workflow") {
2915
- const result = isFirstInvocation ? await triggerFirstInvocation({ workflowContext, useJSONContent, telemetry, debug }) : await triggerRouteFunction({
3107
+ const result = isFirstInvocation ? await triggerFirstInvocation({
3108
+ workflowContext,
3109
+ useJSONContent,
3110
+ telemetry,
3111
+ debug,
3112
+ invokeCount
3113
+ }) : await triggerRouteFunction({
2916
3114
  onStep: async () => routeFunction(workflowContext),
2917
3115
  onCleanup: async (result2) => {
2918
3116
  await triggerWorkflowDelete(workflowContext, result2, debug);
@@ -3118,7 +3316,8 @@ var Client4 = class {
3118
3316
  body,
3119
3317
  headers,
3120
3318
  workflowRunId,
3121
- retries
3319
+ retries,
3320
+ flowControl
3122
3321
  }) {
3123
3322
  const finalWorkflowRunId = getWorkflowRunId(workflowRunId);
3124
3323
  const context = new WorkflowContext({
@@ -3130,8 +3329,9 @@ var Client4 = class {
3130
3329
  url,
3131
3330
  workflowRunId: finalWorkflowRunId,
3132
3331
  retries,
3133
- telemetry: void 0
3332
+ telemetry: void 0,
3134
3333
  // can't know workflow telemetry here
3334
+ flowControl
3135
3335
  });
3136
3336
  const result = await triggerFirstInvocation({
3137
3337
  workflowContext: context,
@@ -3144,6 +3344,59 @@ var Client4 = class {
3144
3344
  throw result.error;
3145
3345
  }
3146
3346
  }
3347
+ /**
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
+ */
3374
+ async logs(params) {
3375
+ const { workflowRunId, cursor, count, state, workflowUrl, workflowCreatedAt } = params ?? {};
3376
+ const urlParams = new URLSearchParams({ groupBy: "workflowRunId" });
3377
+ if (workflowRunId) {
3378
+ urlParams.append("workflowRunId", workflowRunId);
3379
+ }
3380
+ if (cursor) {
3381
+ urlParams.append("cursor", cursor);
3382
+ }
3383
+ if (count) {
3384
+ urlParams.append("count", count.toString());
3385
+ }
3386
+ if (state) {
3387
+ urlParams.append("state", state);
3388
+ }
3389
+ if (workflowUrl) {
3390
+ urlParams.append("workflowUrl", workflowUrl);
3391
+ }
3392
+ if (workflowCreatedAt) {
3393
+ urlParams.append("workflowCreatedAt", workflowCreatedAt.toString());
3394
+ }
3395
+ const result = await this.client.http.request({
3396
+ path: ["v2", "workflows", `events?${urlParams.toString()}`]
3397
+ });
3398
+ return result;
3399
+ }
3147
3400
  };
3148
3401
  // Annotate the CommonJS export names for ESM import in node:
3149
3402
  0 && (module.exports = {
@@ -3153,5 +3406,6 @@ var Client4 = class {
3153
3406
  WorkflowContext,
3154
3407
  WorkflowError,
3155
3408
  WorkflowLogger,
3409
+ WorkflowTool,
3156
3410
  serve
3157
3411
  });