@upstash/workflow 1.4.0-rc → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/astro.d.mts +2 -3
  2. package/astro.d.ts +2 -3
  3. package/astro.js +164 -575
  4. package/astro.mjs +1 -1
  5. package/{chunk-UH6O5IJY.mjs → chunk-DRHEHWMS.mjs} +326 -737
  6. package/cloudflare.d.mts +2 -3
  7. package/cloudflare.d.ts +2 -3
  8. package/cloudflare.js +164 -575
  9. package/cloudflare.mjs +1 -1
  10. package/express.d.mts +2 -3
  11. package/express.d.ts +2 -3
  12. package/express.js +164 -575
  13. package/express.mjs +1 -1
  14. package/h3.d.mts +2 -3
  15. package/h3.d.ts +2 -3
  16. package/h3.js +164 -575
  17. package/h3.mjs +1 -1
  18. package/hono.d.mts +2 -3
  19. package/hono.d.ts +2 -3
  20. package/hono.js +164 -575
  21. package/hono.mjs +1 -1
  22. package/index.d.mts +2 -3
  23. package/index.d.ts +2 -3
  24. package/index.js +164 -575
  25. package/index.mjs +1 -1
  26. package/nextjs.d.mts +2 -3
  27. package/nextjs.d.ts +2 -3
  28. package/nextjs.js +164 -575
  29. package/nextjs.mjs +1 -1
  30. package/package.json +1 -1
  31. package/react-router.d.mts +2 -3
  32. package/react-router.d.ts +2 -3
  33. package/react-router.js +164 -575
  34. package/react-router.mjs +1 -1
  35. package/{serve-many-CbIV7145.d.mts → serve-many-CG3BFvO3.d.mts} +1 -1
  36. package/{serve-many-BCtZg31b.d.ts → serve-many-iJF1IUXk.d.ts} +1 -1
  37. package/solidjs.d.mts +1 -2
  38. package/solidjs.d.ts +1 -2
  39. package/solidjs.js +164 -575
  40. package/solidjs.mjs +1 -1
  41. package/svelte.d.mts +2 -3
  42. package/svelte.d.ts +2 -3
  43. package/svelte.js +164 -575
  44. package/svelte.mjs +1 -1
  45. package/tanstack.d.mts +2 -3
  46. package/tanstack.d.ts +2 -3
  47. package/tanstack.js +164 -575
  48. package/tanstack.mjs +1 -1
  49. package/{types-ffLPVG5_.d.ts → types-CekOpKvz.d.mts} +8 -248
  50. package/{types-ffLPVG5_.d.mts → types-CekOpKvz.d.ts} +8 -248
package/solidjs.js CHANGED
@@ -215,14 +215,6 @@ var WORKFLOW_CREATED_AT_HEADER = "Upstash-Workflow-CreatedAt";
215
215
  var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
216
216
  var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
217
217
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
218
- var WORKFLOW_FEATURE_SET = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
219
- var WORKFLOW_STEP_CONFIG_CALL_TYPE = "stepConfig";
220
- var WORKFLOW_STEP_CONFIG_HEADER = "Upstash-Workflow-Step-Config";
221
- var FLOW_CONTROL_KEY_HEADER = "Upstash-Flow-Control-Key";
222
- var FLOW_CONTROL_VALUE_HEADER = "Upstash-Flow-Control-Value";
223
- var RETRIES_HEADER = "Upstash-Retries";
224
- var RETRY_DELAY_HEADER = "Upstash-Retry-Delay";
225
- var WORKFLOW_STEP_CONFIG_FEATURE = "WF_StepConfig";
226
218
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
227
219
  var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
228
220
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
@@ -240,6 +232,102 @@ var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
240
232
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
241
233
  var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
242
234
 
235
+ // src/context/auto-executor.ts
236
+ var import_qstash5 = require("@upstash/qstash");
237
+
238
+ // src/qstash/headers.ts
239
+ var import_qstash4 = require("@upstash/qstash");
240
+
241
+ // src/utils.ts
242
+ var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
243
+ var NANOID_LENGTH = 21;
244
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
245
+ function validateLabel(label) {
246
+ if (label === void 0) return;
247
+ const labels = Array.isArray(label) ? label : [label];
248
+ if (labels.length === 0) {
249
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
250
+ }
251
+ for (const value of labels) {
252
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
253
+ throw new WorkflowNonRetryableError(
254
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
255
+ );
256
+ }
257
+ }
258
+ }
259
+ function serializeLabel(label) {
260
+ return Array.isArray(label) ? label.join(",") : label;
261
+ }
262
+ function validateFlowControl(flowControl) {
263
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
264
+ throw new WorkflowNonRetryableError(
265
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
266
+ );
267
+ }
268
+ }
269
+ function getRandomInt() {
270
+ return Math.floor(Math.random() * NANOID_CHARS.length);
271
+ }
272
+ function nanoid(length = NANOID_LENGTH) {
273
+ return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
274
+ }
275
+ function getWorkflowRunId(id) {
276
+ return `wfr_${id ?? nanoid()}`;
277
+ }
278
+ function decodeBase64(base64) {
279
+ const binString = atob(base64);
280
+ try {
281
+ const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
282
+ return new TextDecoder().decode(intArray);
283
+ } catch (error) {
284
+ console.warn(
285
+ `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
286
+ );
287
+ return binString;
288
+ }
289
+ }
290
+ function getUserIdFromToken(qstashClient) {
291
+ try {
292
+ const token = qstashClient.token;
293
+ const decodedToken = decodeBase64(token);
294
+ const tokenPayload = JSON.parse(decodedToken);
295
+ const userId = tokenPayload.UserID;
296
+ if (!userId) {
297
+ throw new WorkflowError("QStash token payload does not contain userId");
298
+ }
299
+ return userId;
300
+ } catch (error) {
301
+ throw new WorkflowError(
302
+ `Failed to decode QStash token while running create webhook step: ${error.message}`
303
+ );
304
+ }
305
+ }
306
+ function getQStashUrl(qstashClient) {
307
+ try {
308
+ const requester = qstashClient.http;
309
+ const baseUrl = requester.baseUrl;
310
+ if (!baseUrl) {
311
+ throw new WorkflowError("QStash client does not have a baseUrl");
312
+ }
313
+ return baseUrl;
314
+ } catch (error) {
315
+ throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
316
+ }
317
+ }
318
+ function getEventId() {
319
+ return `evt_${nanoid(15)}`;
320
+ }
321
+ function stringifyBody(body) {
322
+ if (body === void 0) {
323
+ return void 0;
324
+ }
325
+ if (typeof body === "string") {
326
+ return body;
327
+ }
328
+ return JSON.stringify(body);
329
+ }
330
+
243
331
  // node_modules/neverthrow/dist/index.es.js
244
332
  var defaultErrorConfig = {
245
333
  withStackTrace: false
@@ -655,102 +743,6 @@ var Err = class {
655
743
  };
656
744
  var fromThrowable = Result.fromThrowable;
657
745
 
658
- // src/context/auto-executor.ts
659
- var import_qstash5 = require("@upstash/qstash");
660
-
661
- // src/qstash/headers.ts
662
- var import_qstash4 = require("@upstash/qstash");
663
-
664
- // src/utils.ts
665
- var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
666
- var NANOID_LENGTH = 21;
667
- var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
668
- function validateLabel(label) {
669
- if (label === void 0) return;
670
- const labels = Array.isArray(label) ? label : [label];
671
- if (labels.length === 0) {
672
- throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
673
- }
674
- for (const value of labels) {
675
- if (!RESOURCE_NAME_PATTERN.test(value)) {
676
- throw new WorkflowNonRetryableError(
677
- `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
678
- );
679
- }
680
- }
681
- }
682
- function serializeLabel(label) {
683
- return Array.isArray(label) ? label.join(",") : label;
684
- }
685
- function validateFlowControl(flowControl) {
686
- if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
687
- throw new WorkflowNonRetryableError(
688
- `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
689
- );
690
- }
691
- }
692
- function getRandomInt() {
693
- return Math.floor(Math.random() * NANOID_CHARS.length);
694
- }
695
- function nanoid(length = NANOID_LENGTH) {
696
- return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
697
- }
698
- function getWorkflowRunId(id) {
699
- return `wfr_${id ?? nanoid()}`;
700
- }
701
- function decodeBase64(base64) {
702
- const binString = atob(base64);
703
- try {
704
- const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
705
- return new TextDecoder().decode(intArray);
706
- } catch (error) {
707
- console.warn(
708
- `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
709
- );
710
- return binString;
711
- }
712
- }
713
- function getUserIdFromToken(qstashClient) {
714
- try {
715
- const token = qstashClient.token;
716
- const decodedToken = decodeBase64(token);
717
- const tokenPayload = JSON.parse(decodedToken);
718
- const userId = tokenPayload.UserID;
719
- if (!userId) {
720
- throw new WorkflowError("QStash token payload does not contain userId");
721
- }
722
- return userId;
723
- } catch (error) {
724
- throw new WorkflowError(
725
- `Failed to decode QStash token while running create webhook step: ${error.message}`
726
- );
727
- }
728
- }
729
- function getQStashUrl(qstashClient) {
730
- try {
731
- const requester = qstashClient.http;
732
- const baseUrl = requester.baseUrl;
733
- if (!baseUrl) {
734
- throw new WorkflowError("QStash client does not have a baseUrl");
735
- }
736
- return baseUrl;
737
- } catch (error) {
738
- throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
739
- }
740
- }
741
- function getEventId() {
742
- return `evt_${nanoid(15)}`;
743
- }
744
- function stringifyBody(body) {
745
- if (body === void 0) {
746
- return void 0;
747
- }
748
- if (typeof body === "string") {
749
- return body;
750
- }
751
- return JSON.stringify(body);
752
- }
753
-
754
746
  // src/types.ts
755
747
  var StepTypes = [
756
748
  "Initial",
@@ -790,6 +782,10 @@ var triggerFirstInvocation = async (params) => {
790
782
  workflowConfig: {
791
783
  workflowRunId: workflowContext.workflowRunId,
792
784
  workflowUrl: workflowContext.url,
785
+ // the run doesn't exist yet, so the trigger time is sent when the creation time
786
+ // is not known. serve and client.trigger set it on the context already, so a
787
+ // retry of this request carries the same value and is deduplicated.
788
+ workflowRunCreatedAt: workflowContext.workflowRunCreatedAt || Date.now(),
793
789
  failureUrl,
794
790
  retries,
795
791
  retryDelay,
@@ -856,10 +852,6 @@ var triggerFirstInvocation = async (params) => {
856
852
  return err(error_);
857
853
  }
858
854
  };
859
- var flushPendingStep = async (workflowContext) => {
860
- const { executor } = workflowContext;
861
- return await executor.submitPendingStep();
862
- };
863
855
  var triggerRouteFunction = async ({
864
856
  onCleanup,
865
857
  onStep,
@@ -897,7 +889,10 @@ var triggerWorkflowDelete = async (workflowContext, result, cancel = false, disp
897
889
  path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
898
890
  method: "DELETE",
899
891
  parseResponseAsJson: false,
900
- body: JSON.stringify(result)
892
+ body: JSON.stringify(result),
893
+ // with the creation time, QStash deletes the run only if it is the same run.
894
+ // a late delete of a previous run can't delete a new run with the same id.
895
+ headers: workflowContext.workflowRunCreatedAt ? { [WORKFLOW_CREATED_AT_HEADER]: workflowContext.workflowRunCreatedAt.toString() } : void 0
901
896
  });
902
897
  await dispatchDebug?.("onInfo", {
903
898
  info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
@@ -974,6 +969,7 @@ ${atob(callbackMessage.body ?? "")}`
974
969
  const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
975
970
  const contentType = request.headers.get("Upstash-Workflow-ContentType");
976
971
  const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
972
+ const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
977
973
  if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
978
974
  throw new Error(
979
975
  `Missing info in callback message source header: ${JSON.stringify({
@@ -991,6 +987,7 @@ ${atob(callbackMessage.body ?? "")}`
991
987
  workflowConfig: {
992
988
  workflowRunId,
993
989
  workflowUrl,
990
+ workflowRunCreatedAt: Number(workflowRunCreatedAt ?? "0"),
994
991
  telemetry
995
992
  },
996
993
  invokeCount: Number(invokeCount)
@@ -1067,29 +1064,8 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1067
1064
  var BaseLazyStep = class _BaseLazyStep {
1068
1065
  stepName;
1069
1066
  context;
1070
- /**
1071
- * step-level settings (flow control, retries etc.) which override the
1072
- * settings the workflow run was triggered with, for this step only.
1073
- */
1074
- stepSettings;
1075
- /**
1076
- * whether this step's result can be submitted after the route function
1077
- * has moved on, instead of right away.
1078
- *
1079
- * Enabled for steps whose `getResultStep` produces the final `out` —
1080
- * which is not the same as "needs no server round trip":
1081
- * `LazyCreateWebhookStep` builds its result in `getBody` and returns
1082
- * `out: undefined` from `getResultStep`, so deferring it would hand
1083
- * `undefined` to the route function.
1084
- *
1085
- * Deferring lets the route function continue and reveal the next step,
1086
- * so that step's settings can ride on this step's submission instead
1087
- * of needing a step config request of their own.
1088
- */
1089
- supportsDeferredSubmission = false;
1090
- constructor(context, stepName, stepSettings) {
1067
+ constructor(context, stepName) {
1091
1068
  this.context = context;
1092
- this.stepSettings = stepSettings;
1093
1069
  if (!stepName) {
1094
1070
  throw new WorkflowError(
1095
1071
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -1153,18 +1129,13 @@ var BaseLazyStep = class _BaseLazyStep {
1153
1129
  step.out = JSON.stringify(step.out);
1154
1130
  return JSON.stringify(step);
1155
1131
  }
1156
- getHeaders({
1157
- context,
1158
- telemetry,
1159
- invokeCount,
1160
- step,
1161
- stepSettings
1162
- }) {
1132
+ getHeaders({ context, telemetry, invokeCount, step }) {
1163
1133
  return getHeaders({
1164
1134
  initHeaderValue: "false",
1165
1135
  workflowConfig: {
1166
1136
  workflowRunId: context.workflowRunId,
1167
1137
  workflowUrl: context.url,
1138
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1168
1139
  useJSONContent: false,
1169
1140
  telemetry
1170
1141
  },
@@ -1172,8 +1143,7 @@ var BaseLazyStep = class _BaseLazyStep {
1172
1143
  stepInfo: {
1173
1144
  step,
1174
1145
  lazyStep: this
1175
- },
1176
- stepSettings
1146
+ }
1177
1147
  });
1178
1148
  }
1179
1149
  async submitStep({ context, body, headers }) {
@@ -1191,9 +1161,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1191
1161
  stepFunction;
1192
1162
  stepType = "Run";
1193
1163
  allowUndefinedOut = true;
1194
- supportsDeferredSubmission = true;
1195
- constructor(context, stepName, stepFunction, stepSettings) {
1196
- super(context, stepName, stepSettings);
1164
+ constructor(context, stepName, stepFunction) {
1165
+ super(context, stepName);
1197
1166
  this.stepFunction = stepFunction;
1198
1167
  }
1199
1168
  getPlanStep(concurrent, targetStep) {
@@ -1223,7 +1192,6 @@ var LazySleepStep = class extends BaseLazyStep {
1223
1192
  sleep;
1224
1193
  stepType = "SleepFor";
1225
1194
  allowUndefinedOut = true;
1226
- supportsDeferredSubmission = true;
1227
1195
  constructor(context, stepName, sleep) {
1228
1196
  super(context, stepName);
1229
1197
  this.sleep = sleep;
@@ -1263,7 +1231,6 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1263
1231
  sleepUntil;
1264
1232
  stepType = "SleepUntil";
1265
1233
  allowUndefinedOut = true;
1266
- supportsDeferredSubmission = true;
1267
1234
  constructor(context, stepName, sleepUntil) {
1268
1235
  super(context, stepName);
1269
1236
  this.sleepUntil = sleepUntil;
@@ -1496,6 +1463,8 @@ var LazyWaitEventStep = class extends BaseLazyStep {
1496
1463
  ) : {},
1497
1464
  // note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
1498
1465
  "Upstash-Workflow-Runid": [context.workflowRunId],
1466
+ // same for WORKFLOW_CREATED_AT_HEADER, because Createdat -> CreatedAt:
1467
+ ...context.workflowRunCreatedAt ? { "Upstash-Workflow-Createdat": [context.workflowRunCreatedAt.toString()] } : {},
1499
1468
  [WORKFLOW_INIT_HEADER]: ["false"],
1500
1469
  [WORKFLOW_URL_HEADER]: [context.url],
1501
1470
  "Upstash-Workflow-CallType": ["step"]
@@ -1598,6 +1567,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1598
1567
  workflowConfig: {
1599
1568
  workflowRunId: context.workflowRunId,
1600
1569
  workflowUrl: context.url,
1570
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1601
1571
  telemetry,
1602
1572
  useJSONContent: false
1603
1573
  },
@@ -1607,6 +1577,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1607
1577
  invokerHeaders[key] = value;
1608
1578
  });
1609
1579
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1580
+ if (context.workflowRunCreatedAt) {
1581
+ invokerHeaders["Upstash-Workflow-Createdat"] = context.workflowRunCreatedAt.toString();
1582
+ }
1610
1583
  const request = {
1611
1584
  body: stringifyBody(this.params.body),
1612
1585
  headers: Object.fromEntries(
@@ -1635,6 +1608,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1635
1608
  workflowConfig: {
1636
1609
  workflowRunId: getWorkflowRunId(workflowRunId),
1637
1610
  workflowUrl: newUrl,
1611
+ // the invoked run doesn't exist yet, so the creation time of the invoker run is sent.
1612
+ // it separates the invocations made by different runs of the invoker.
1613
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1638
1614
  retries,
1639
1615
  retryDelay,
1640
1616
  telemetry,
@@ -1756,7 +1732,6 @@ var WorkflowHeaders = class {
1756
1732
  invokeCount;
1757
1733
  initHeaderValue;
1758
1734
  stepInfo;
1759
- stepSettings;
1760
1735
  headers;
1761
1736
  /**
1762
1737
  * @param params workflow header parameters
@@ -1766,20 +1741,17 @@ var WorkflowHeaders = class {
1766
1741
  workflowConfig,
1767
1742
  invokeCount,
1768
1743
  initHeaderValue,
1769
- stepInfo,
1770
- stepSettings
1744
+ stepInfo
1771
1745
  }) {
1772
1746
  this.userHeaders = userHeaders;
1773
1747
  this.workflowConfig = workflowConfig;
1774
1748
  this.invokeCount = invokeCount;
1775
1749
  this.initHeaderValue = initHeaderValue;
1776
1750
  this.stepInfo = stepInfo;
1777
- this.stepSettings = stepSettings;
1778
1751
  this.headers = {
1779
1752
  rawHeaders: {},
1780
1753
  workflowHeaders: {},
1781
- failureHeaders: {},
1782
- stepSettingsHeaders: {}
1754
+ failureHeaders: {}
1783
1755
  };
1784
1756
  }
1785
1757
  getHeaders() {
@@ -1790,7 +1762,6 @@ var WorkflowHeaders = class {
1790
1762
  this.addUserHeaders();
1791
1763
  this.addInvokeCount();
1792
1764
  this.addFailureUrl();
1793
- this.addStepSettings();
1794
1765
  const contentType = this.addContentType();
1795
1766
  return this.prefixHeaders(contentType);
1796
1767
  }
@@ -1800,10 +1771,13 @@ var WorkflowHeaders = class {
1800
1771
  [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
1801
1772
  [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
1802
1773
  [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
1803
- [WORKFLOW_FEATURE_HEADER]: WORKFLOW_FEATURE_SET,
1774
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
1804
1775
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1805
1776
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
1806
1777
  };
1778
+ if (this.workflowConfig.workflowRunCreatedAt) {
1779
+ this.headers.rawHeaders[WORKFLOW_CREATED_AT_HEADER] = this.workflowConfig.workflowRunCreatedAt.toString();
1780
+ }
1807
1781
  if (this.stepInfo?.lazyStep.stepType !== "Call") {
1808
1782
  this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
1809
1783
  }
@@ -1878,7 +1852,7 @@ var WorkflowHeaders = class {
1878
1852
  this.headers.failureHeaders["Workflow-Init"] = "false";
1879
1853
  this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
1880
1854
  this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
1881
- this.headers.failureHeaders["Feature-Set"] = WORKFLOW_FEATURE_SET;
1855
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
1882
1856
  if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
1883
1857
  this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
1884
1858
  }
@@ -1886,42 +1860,6 @@ var WorkflowHeaders = class {
1886
1860
  this.headers.failureHeaders["Retry-Delay"] = this.workflowConfig.retryDelay.toString();
1887
1861
  }
1888
1862
  }
1889
- /**
1890
- * Applies the step-level settings of a step to the message.
1891
- *
1892
- * These headers configure the message itself, so that QStash uses them
1893
- * instead of the settings the run was triggered with. The delivery of
1894
- * the message is what executes the step, which is how a step's
1895
- * settings reach it.
1896
- *
1897
- * When any setting is present the feature set is extended with
1898
- * `WF_StepConfig`, which is what tells QStash to keep them. QStash
1899
- * reports that back on the delivery as `Upstash-Workflow-Step-Config`.
1900
- */
1901
- addStepSettings() {
1902
- if (!this.stepSettings) {
1903
- return;
1904
- }
1905
- const headers = {};
1906
- if (this.stepSettings.flowControl) {
1907
- const { flowControlKey, flowControlValue } = prepareFlowControl(
1908
- this.stepSettings.flowControl
1909
- );
1910
- headers[FLOW_CONTROL_KEY_HEADER] = flowControlKey;
1911
- headers[FLOW_CONTROL_VALUE_HEADER] = flowControlValue;
1912
- }
1913
- if (this.stepSettings.retries !== void 0) {
1914
- headers[RETRIES_HEADER] = this.stepSettings.retries.toString();
1915
- }
1916
- if (this.stepSettings.retryDelay) {
1917
- headers[RETRY_DELAY_HEADER] = this.stepSettings.retryDelay;
1918
- }
1919
- if (Object.keys(headers).length === 0) {
1920
- return;
1921
- }
1922
- headers[WORKFLOW_FEATURE_HEADER] = `${WORKFLOW_FEATURE_SET},${WORKFLOW_STEP_CONFIG_FEATURE}`;
1923
- this.headers.stepSettingsHeaders = headers;
1924
- }
1925
1863
  addContentType() {
1926
1864
  if (this.workflowConfig.useJSONContent) {
1927
1865
  this.headers.rawHeaders["content-type"] = "application/json";
@@ -1935,17 +1873,14 @@ var WorkflowHeaders = class {
1935
1873
  return contentType;
1936
1874
  }
1937
1875
  prefixHeaders(contentType) {
1938
- const { rawHeaders, workflowHeaders, failureHeaders, stepSettingsHeaders } = this.headers;
1876
+ const { rawHeaders, workflowHeaders, failureHeaders } = this.headers;
1939
1877
  const isCall = this.stepInfo?.lazyStep.stepType === "Call";
1940
1878
  return {
1941
1879
  headers: {
1942
1880
  ...rawHeaders,
1943
1881
  ...addPrefixToHeaders(workflowHeaders, isCall ? "Upstash-Callback-" : "Upstash-"),
1944
1882
  ...addPrefixToHeaders(failureHeaders, "Upstash-Failure-Callback-"),
1945
- ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {},
1946
- // last, so they override the run's settings above. Never
1947
- // prefixed: they configure this message, not its callback.
1948
- ...stepSettingsHeaders
1883
+ ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {}
1949
1884
  },
1950
1885
  contentType
1951
1886
  };
@@ -1996,16 +1931,16 @@ var submitParallelSteps = async ({
1996
1931
  info: `Submitting ${planSteps.length} parallel steps.`
1997
1932
  });
1998
1933
  const result = await context.qstashClient.batch(
1999
- planSteps.map((planStep, index) => {
1934
+ planSteps.map((planStep) => {
2000
1935
  const { headers } = getHeaders({
2001
1936
  initHeaderValue: "false",
2002
1937
  workflowConfig: {
2003
1938
  workflowRunId: context.workflowRunId,
2004
1939
  workflowUrl: context.url,
1940
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
2005
1941
  telemetry
2006
1942
  },
2007
- invokeCount,
2008
- stepSettings: steps[index].stepSettings
1943
+ invokeCount
2009
1944
  });
2010
1945
  return {
2011
1946
  headers,
@@ -2024,38 +1959,31 @@ var submitParallelSteps = async ({
2024
1959
  }
2025
1960
  throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
2026
1961
  };
2027
- var executeStep = async ({
1962
+ var submitSingleStep = async ({
1963
+ context,
2028
1964
  lazyStep,
2029
1965
  stepId,
1966
+ invokeCount,
2030
1967
  concurrency,
1968
+ telemetry,
1969
+ dispatchDebug,
2031
1970
  dispatchLifecycle
2032
1971
  }) => {
2033
1972
  await dispatchLifecycle("beforeExecution", {
2034
1973
  stepName: lazyStep.stepName
2035
1974
  });
1975
+ let resultStep;
2036
1976
  try {
2037
- return await lazyStep.getResultStep(concurrency, stepId);
1977
+ resultStep = await lazyStep.getResultStep(concurrency, stepId);
2038
1978
  } catch (error) {
2039
1979
  attachStepNameToError(error, lazyStep.stepName);
2040
1980
  throw error;
2041
1981
  }
2042
- };
2043
- var submitStepResult = async ({
2044
- context,
2045
- lazyStep,
2046
- resultStep,
2047
- invokeCount,
2048
- concurrency,
2049
- telemetry,
2050
- dispatchDebug,
2051
- nextStepSettings
2052
- }) => {
2053
1982
  const { headers } = lazyStep.getHeaders({
2054
1983
  context,
2055
1984
  step: resultStep,
2056
1985
  invokeCount,
2057
- telemetry,
2058
- stepSettings: nextStepSettings
1986
+ telemetry
2059
1987
  });
2060
1988
  const body = lazyStep.getBody({
2061
1989
  context,
@@ -2080,138 +2008,6 @@ var submitStepResult = async ({
2080
2008
  }
2081
2009
  return resultStep;
2082
2010
  };
2083
- var publishStepConfigRequest = async ({
2084
- context,
2085
- lazyStep,
2086
- targetStep,
2087
- invokeCount,
2088
- telemetry,
2089
- dispatchDebug
2090
- }) => {
2091
- const { headers } = getHeaders({
2092
- initHeaderValue: "false",
2093
- workflowConfig: {
2094
- workflowRunId: context.workflowRunId,
2095
- workflowUrl: context.url,
2096
- telemetry
2097
- },
2098
- invokeCount,
2099
- stepSettings: lazyStep.stepSettings
2100
- });
2101
- await dispatchDebug("onInfo", {
2102
- info: `Step "${lazyStep.stepName}" (${targetStep}) has step-level settings which the current delivery does not carry. Requesting a delivery which does.`
2103
- });
2104
- const result = await context.qstashClient.publishJSON({
2105
- headers: {
2106
- ...headers,
2107
- "Upstash-Workflow-CallType": WORKFLOW_STEP_CONFIG_CALL_TYPE
2108
- },
2109
- method: "POST",
2110
- body: { targetStep, invokeCount },
2111
- url: context.url,
2112
- contentBasedDeduplication: true
2113
- });
2114
- if (result?.deduplicated) {
2115
- await dispatchDebug("onWarning", {
2116
- warning: `A step config request for step "${lazyStep.stepName}" (${targetStep}) was already published and this one was deduplicated. Expected when the delivery which published it is being retried; otherwise the run stops here.`
2117
- });
2118
- } else if (result?.messageId) {
2119
- await dispatchDebug("onInfo", {
2120
- info: `Requested a delivery under the settings of step "${lazyStep.stepName}" with messageId: ${result.messageId}.`
2121
- });
2122
- }
2123
- };
2124
-
2125
- // src/qstash/step-config.ts
2126
- var DEFAULT_PARALLELISM = 0;
2127
- var DEFAULT_RATE = 0;
2128
- var DEFAULT_PERIOD_SECONDS = 1;
2129
- var SECONDS_PER_UNIT = {
2130
- s: 1,
2131
- m: 60,
2132
- h: 60 * 60,
2133
- d: 24 * 60 * 60
2134
- };
2135
- var durationToSeconds = (duration) => {
2136
- if (typeof duration === "number") {
2137
- return Number.isFinite(duration) ? duration : void 0;
2138
- }
2139
- const match = /^(\d+)([smhd])$/.exec(duration.trim());
2140
- if (match) {
2141
- return Number(match[1]) * SECONDS_PER_UNIT[match[2]];
2142
- }
2143
- const seconds = Number(duration.trim());
2144
- return Number.isFinite(seconds) ? seconds : void 0;
2145
- };
2146
- var normalizeFlowControl = (flowControl) => {
2147
- const period = flowControl.period === void 0 ? void 0 : durationToSeconds(flowControl.period);
2148
- return {
2149
- key: flowControl.key,
2150
- parallelism: flowControl.parallelism ?? DEFAULT_PARALLELISM,
2151
- rate: flowControl.rate ?? flowControl.ratePerSecond ?? DEFAULT_RATE,
2152
- period: period ?? DEFAULT_PERIOD_SECONDS
2153
- };
2154
- };
2155
- var parseFlowControlHeaders = (key, value) => {
2156
- if (!key) {
2157
- return void 0;
2158
- }
2159
- const flowControl = {
2160
- key,
2161
- parallelism: DEFAULT_PARALLELISM,
2162
- rate: DEFAULT_RATE,
2163
- period: DEFAULT_PERIOD_SECONDS
2164
- };
2165
- for (const entry of (value ?? "").split(",")) {
2166
- const [name, rawValue] = entry.split("=").map((part) => part.trim());
2167
- if (!name || rawValue === void 0) {
2168
- continue;
2169
- }
2170
- switch (name) {
2171
- case "parallelism": {
2172
- flowControl.parallelism = Number(rawValue);
2173
- break;
2174
- }
2175
- case "rate": {
2176
- flowControl.rate = Number(rawValue);
2177
- break;
2178
- }
2179
- case "period": {
2180
- flowControl.period = durationToSeconds(rawValue) ?? DEFAULT_PERIOD_SECONDS;
2181
- break;
2182
- }
2183
- }
2184
- }
2185
- return flowControl;
2186
- };
2187
- var getEffectiveConfig = (headers) => {
2188
- const retriesHeader = headers.get(RETRIES_HEADER);
2189
- return {
2190
- flowControl: parseFlowControlHeaders(
2191
- headers.get(FLOW_CONTROL_KEY_HEADER),
2192
- headers.get(FLOW_CONTROL_VALUE_HEADER)
2193
- ),
2194
- retries: retriesHeader === null ? void 0 : Number(retriesHeader),
2195
- retryDelay: headers.get(RETRY_DELAY_HEADER) ?? void 0,
2196
- hasStepConfig: headers.get(WORKFLOW_STEP_CONFIG_HEADER) === "true"
2197
- };
2198
- };
2199
- var describeStepSettingsMismatch = (stepSettings, effectiveConfig) => {
2200
- if (stepSettings.flowControl) {
2201
- const wanted = normalizeFlowControl(stepSettings.flowControl);
2202
- const applied = effectiveConfig.flowControl;
2203
- if (!applied || applied.key !== wanted.key || applied.parallelism !== wanted.parallelism || applied.rate !== wanted.rate || applied.period !== wanted.period) {
2204
- return `flow control: expected ${JSON.stringify(wanted)}, delivery has ${JSON.stringify(applied)}`;
2205
- }
2206
- }
2207
- if (stepSettings.retries !== void 0 && effectiveConfig.retries !== void 0 && stepSettings.retries !== effectiveConfig.retries) {
2208
- return `retries: expected ${stepSettings.retries}, delivery has ${effectiveConfig.retries}`;
2209
- }
2210
- if (stepSettings.retryDelay !== void 0 && stepSettings.retryDelay !== effectiveConfig.retryDelay) {
2211
- return `retry delay: expected '${stepSettings.retryDelay}', delivery has '${effectiveConfig.retryDelay ?? ""}'`;
2212
- }
2213
- return void 0;
2214
- };
2215
2011
 
2216
2012
  // src/context/auto-executor.ts
2217
2013
  var AutoExecutor = class _AutoExecutor {
@@ -2228,25 +2024,6 @@ var AutoExecutor = class _AutoExecutor {
2228
2024
  stepCount = 0;
2229
2025
  planStepCount = 0;
2230
2026
  executingStep = false;
2231
- /**
2232
- * an executed step whose result hasn't been submitted to QStash yet.
2233
- *
2234
- * Set when a step which can produce its result in-process executes. The
2235
- * submission waits so that the route function can continue and reveal
2236
- * what comes next: if that is a single step with step-level settings,
2237
- * the settings ride on this submission and no step config request is
2238
- * needed, since the delivery of the submission is what executes it.
2239
- *
2240
- * Flushed when the next step is reached (see `addStep`) or when the
2241
- * route function ends (see `flushPendingStep` in `serve`).
2242
- */
2243
- pendingStep;
2244
- /**
2245
- * configuration QStash applied to the delivery being handled. A step
2246
- * with step-level settings is settled by comparing its settings against
2247
- * this.
2248
- */
2249
- effectiveConfig;
2250
2027
  /**
2251
2028
  * @param context workflow context
2252
2029
  * @param steps list of steps
@@ -2254,17 +2031,14 @@ var AutoExecutor = class _AutoExecutor {
2254
2031
  * @param dispatchLifecycle lifecycle event dispatcher
2255
2032
  * @param telemetry optional telemetry information
2256
2033
  * @param invokeCount optional invoke count
2257
- * @param effectiveConfig configuration QStash applied to the delivery
2258
- * being handled
2259
2034
  */
2260
- constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry, invokeCount, effectiveConfig) {
2035
+ constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry, invokeCount) {
2261
2036
  this.context = context;
2262
2037
  this.steps = steps;
2263
2038
  this.dispatchDebug = dispatchDebug;
2264
2039
  this.dispatchLifecycle = dispatchLifecycle;
2265
2040
  this.telemetry = telemetry;
2266
2041
  this.invokeCount = invokeCount ?? 0;
2267
- this.effectiveConfig = effectiveConfig ?? { hasStepConfig: false };
2268
2042
  this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
2269
2043
  }
2270
2044
  /**
@@ -2299,15 +2073,6 @@ var AutoExecutor = class _AutoExecutor {
2299
2073
  lazyStepList.push(stepInfo);
2300
2074
  const index = this.indexInCurrentList++;
2301
2075
  const requestComplete = this.deferExecution().then(async () => {
2302
- const submitted = await this.submitPendingStep(
2303
- lazyStepList.length === 1 ? lazyStepList[0].stepSettings : void 0
2304
- );
2305
- if (submitted.isErr()) {
2306
- throw submitted.error;
2307
- }
2308
- if (submitted.value.result === "submitted-step") {
2309
- throw submitted.value.abort;
2310
- }
2311
2076
  if (!this.promises.has(lazyStepList)) {
2312
2077
  const promise2 = this.getExecutionPromise(lazyStepList);
2313
2078
  this.promises.set(lazyStepList, promise2);
@@ -2361,100 +2126,18 @@ var AutoExecutor = class _AutoExecutor {
2361
2126
  }
2362
2127
  return parsedOut;
2363
2128
  }
2364
- const mismatch = lazyStep.stepSettings ? describeStepSettingsMismatch(lazyStep.stepSettings, this.effectiveConfig) : void 0;
2365
- if (mismatch) {
2366
- if (!this.effectiveConfig.hasStepConfig) {
2367
- await publishStepConfigRequest({
2368
- context: this.context,
2369
- lazyStep,
2370
- targetStep: this.stepCount,
2371
- invokeCount: this.invokeCount,
2372
- telemetry: this.telemetry,
2373
- dispatchDebug: this.dispatchDebug
2374
- });
2375
- throw new WorkflowAbort(lazyStep.stepName);
2376
- } else {
2377
- await this.dispatchDebug("onWarning", {
2378
- warning: `The step-level settings of step '${lazyStep.stepName}' were published but are not recognized on the delivery which carries them (${mismatch}). Executing the step with the settings of the delivery instead. This is a bug in @upstash/workflow, please report it.`
2379
- });
2380
- }
2381
- }
2382
- const resultStep = await executeStep({
2383
- lazyStep,
2384
- stepId: this.stepCount,
2385
- concurrency: NO_CONCURRENCY,
2386
- dispatchLifecycle: this.dispatchLifecycle
2387
- });
2388
- if (lazyStep.supportsDeferredSubmission) {
2389
- this.pendingStep = { status: "held", lazyStep, resultStep };
2390
- return lazyStep.parseOut({
2391
- ...resultStep,
2392
- out: resultStep.out === void 0 ? void 0 : JSON.stringify(resultStep.out)
2393
- });
2394
- }
2395
- await submitStepResult({
2129
+ const resultStep = await submitSingleStep({
2396
2130
  context: this.context,
2397
2131
  lazyStep,
2398
- resultStep,
2132
+ stepId: this.stepCount,
2399
2133
  invokeCount: this.invokeCount,
2400
- concurrency: NO_CONCURRENCY,
2134
+ concurrency: 1,
2401
2135
  telemetry: this.telemetry,
2402
- dispatchDebug: this.dispatchDebug
2136
+ dispatchDebug: this.dispatchDebug,
2137
+ dispatchLifecycle: this.dispatchLifecycle
2403
2138
  });
2404
2139
  throw new WorkflowAbort(lazyStep.stepName, resultStep);
2405
2140
  }
2406
- /**
2407
- * Submits the result of the step being held, if there is one, and
2408
- * returns the abort the caller has to throw to end the invocation.
2409
- *
2410
- * Returns undefined when no step is being held, which is the caller's
2411
- * signal that there is nothing to end. Throws instead of returning
2412
- * when the submission itself fails, so that error reaches the caller
2413
- * rather than an abort claiming the step was submitted.
2414
- *
2415
- * Callers which arrive while a submission is already under way (the
2416
- * steps of a parallel group, added together) wait for that one and get
2417
- * the same abort, rather than submitting a second time.
2418
- *
2419
- * The next step's settings are attached whenever it has any, without
2420
- * checking them against the current delivery: the executor only knows
2421
- * the configuration of the delivery in hand, which inside a
2422
- * delivery is the *previous* step's, so such a check would be wrong
2423
- * exactly when two steps with settings follow each other.
2424
- *
2425
- * @param nextStepSettings step-level settings of the next step
2426
- * @returns `submitted-step` with the abort which ends this invocation,
2427
- * or `no-pending-step` when nothing was held and there is nothing to
2428
- * end
2429
- */
2430
- async submitPendingStep(nextStepSettings) {
2431
- if (!this.pendingStep) {
2432
- return ok({ result: "no-pending-step" });
2433
- }
2434
- try {
2435
- if (this.pendingStep.status === "submitting") {
2436
- return ok({ result: "submitted-step", abort: await this.pendingStep.submitted });
2437
- }
2438
- const { lazyStep, resultStep } = this.pendingStep;
2439
- const submitted = (async () => {
2440
- await submitStepResult({
2441
- context: this.context,
2442
- lazyStep,
2443
- resultStep,
2444
- invokeCount: this.invokeCount,
2445
- concurrency: NO_CONCURRENCY,
2446
- telemetry: this.telemetry,
2447
- dispatchDebug: this.dispatchDebug,
2448
- nextStepSettings
2449
- });
2450
- return new WorkflowAbort(lazyStep.stepName, resultStep);
2451
- })();
2452
- this.pendingStep = { status: "submitting", submitted };
2453
- return ok({ result: "submitted-step", abort: await submitted });
2454
- } catch (error) {
2455
- return err(error);
2456
- }
2457
- }
2458
2141
  /**
2459
2142
  * Runs steps in parallel.
2460
2143
  *
@@ -2503,20 +2186,15 @@ var AutoExecutor = class _AutoExecutor {
2503
2186
  validateStep(parallelSteps[stepIndex], planStep);
2504
2187
  try {
2505
2188
  const parallelStep = parallelSteps[stepIndex];
2506
- const resultStep = await executeStep({
2507
- lazyStep: parallelStep,
2508
- stepId: planStep.targetStep,
2509
- concurrency: parallelSteps.length,
2510
- dispatchLifecycle: this.dispatchLifecycle
2511
- });
2512
- await submitStepResult({
2189
+ const resultStep = await submitSingleStep({
2513
2190
  context: this.context,
2514
2191
  lazyStep: parallelStep,
2515
- resultStep,
2192
+ stepId: planStep.targetStep,
2516
2193
  invokeCount: this.invokeCount,
2517
2194
  concurrency: parallelSteps.length,
2518
2195
  telemetry: this.telemetry,
2519
- dispatchDebug: this.dispatchDebug
2196
+ dispatchDebug: this.dispatchDebug,
2197
+ dispatchLifecycle: this.dispatchLifecycle
2520
2198
  });
2521
2199
  throw new WorkflowAbort(parallelStep.stepName, resultStep);
2522
2200
  } catch (error) {
@@ -3065,46 +2743,6 @@ var WorkflowContext = class {
3065
2743
  * `1` on the first retry, `2` on the second, and so on.
3066
2744
  */
3067
2745
  retried;
3068
- /**
3069
- * Configuration QStash applied to the request being handled.
3070
- *
3071
- * This is the configuration of *this delivery*, not of the run: it is
3072
- * the configuration the run was triggered with, except inside the
3073
- * delivery which executes a step that has step-level settings, where
3074
- * it is that step's settings. The fields below expose it; the executor
3075
- * gets it directly rather than reaching through the context.
3076
- */
3077
- effectiveConfig;
3078
- /**
3079
- * Flow control QStash applied to the request being handled, if any.
3080
- *
3081
- * This is the flow control of the request in hand, which is the one the
3082
- * run was triggered with except inside a step carrying its own.
3083
- */
3084
- get flowControl() {
3085
- return this.effectiveConfig.flowControl;
3086
- }
3087
- /**
3088
- * Retry limit QStash applied to the request being handled, if it
3089
- * reported one.
3090
- *
3091
- * Not to be confused with {@link retried}, which is how many retries
3092
- * have already happened.
3093
- *
3094
- * @see {@link flowControl} for what "the request being handled" means
3095
- */
3096
- get retries() {
3097
- return this.effectiveConfig.retries;
3098
- }
3099
- /**
3100
- * Retry delay expression QStash applied to the request being handled,
3101
- * if any.
3102
- *
3103
- * @see {@link flowControl} for what "the request being handled" means
3104
- */
3105
- get retryDelay() {
3106
- return this.effectiveConfig.retryDelay;
3107
- }
3108
2746
  constructor({
3109
2747
  qstashClient,
3110
2748
  workflowRunId,
@@ -3118,8 +2756,7 @@ var WorkflowContext = class {
3118
2756
  invokeCount,
3119
2757
  label,
3120
2758
  retried,
3121
- middlewareManager,
3122
- effectiveConfig
2759
+ middlewareManager
3123
2760
  }) {
3124
2761
  this.qstashClient = qstashClient;
3125
2762
  this.workflowRunId = workflowRunId;
@@ -3131,7 +2768,6 @@ var WorkflowContext = class {
3131
2768
  this.env = env ?? {};
3132
2769
  this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
3133
2770
  this.retried = retried ?? 0;
3134
- this.effectiveConfig = effectiveConfig ?? { hasStepConfig: false };
3135
2771
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
3136
2772
  middlewareManagerInstance.assignContext(this);
3137
2773
  this.executor = new AutoExecutor(
@@ -3140,8 +2776,7 @@ var WorkflowContext = class {
3140
2776
  middlewareManagerInstance.dispatchDebug.bind(middlewareManagerInstance),
3141
2777
  middlewareManagerInstance.dispatchLifecycle.bind(middlewareManagerInstance),
3142
2778
  telemetry,
3143
- invokeCount,
3144
- this.effectiveConfig
2779
+ invokeCount
3145
2780
  );
3146
2781
  }
3147
2782
  /**
@@ -3167,35 +2802,13 @@ var WorkflowContext = class {
3167
2802
  * ])
3168
2803
  * ```
3169
2804
  *
3170
- * Step-level settings can be passed as a third argument, overriding
3171
- * the settings the workflow run was triggered with for this step only:
3172
- *
3173
- * ```typescript
3174
- * const result = await context.run(
3175
- * "step 1",
3176
- * () => {
3177
- * return "result"
3178
- * },
3179
- * {
3180
- * flowControl: { key: "custom-key", parallelism: 3 },
3181
- * retries: 5,
3182
- * }
3183
- * )
3184
- * ```
3185
- *
3186
2805
  * @param stepName name of the step
3187
2806
  * @param stepFunction step function to be executed
3188
- * @param stepSettings step-level settings for this step
3189
2807
  * @returns result of the step function
3190
2808
  */
3191
- async run(stepName, stepFunction, stepSettings) {
3192
- if (stepSettings) {
3193
- validateFlowControl(stepSettings.flowControl);
3194
- }
2809
+ async run(stepName, stepFunction) {
3195
2810
  const wrappedStepFunction = (() => this.executor.wrapStep(stepName, stepFunction));
3196
- return await this.addStep(
3197
- new LazyFunctionStep(this, stepName, wrappedStepFunction, stepSettings)
3198
- );
2811
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
3199
2812
  }
3200
2813
  /**
3201
2814
  * Stops the execution for the duration provided.
@@ -3418,7 +3031,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3418
3031
  *
3419
3032
  * @param routeFunction
3420
3033
  */
3421
- static async tryAuthentication(routeFunction, context, effectiveConfig) {
3034
+ static async tryAuthentication(routeFunction, context) {
3422
3035
  const disabledContext = new _DisabledWorkflowContext({
3423
3036
  qstashClient: new import_qstash10.Client({
3424
3037
  baseUrl: "disabled-client",
@@ -3433,10 +3046,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3433
3046
  initialPayload: context.requestPayload,
3434
3047
  env: context.env,
3435
3048
  label: context.labels,
3436
- retried: context.retried,
3437
- // the route function runs for real here until it reaches a step, so
3438
- // it observes the same configuration as it will on the real context
3439
- effectiveConfig
3049
+ retried: context.retried
3440
3050
  });
3441
3051
  try {
3442
3052
  await routeFunction(disabledContext);
@@ -3653,7 +3263,6 @@ var handleFailure = async ({
3653
3263
  }
3654
3264
  const userHeaders = recreateUserHeaders(request.headers);
3655
3265
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3656
- const effectiveConfig = getEffectiveConfig(request.headers);
3657
3266
  const workflowContext = new WorkflowContext({
3658
3267
  qstashClient,
3659
3268
  workflowRunId,
@@ -3667,13 +3276,11 @@ var handleFailure = async ({
3667
3276
  label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
3668
3277
  retried,
3669
3278
  workflowRunCreatedAt: workflowCreatedAt,
3670
- middlewareManager: void 0,
3671
- effectiveConfig
3279
+ middlewareManager: void 0
3672
3280
  });
3673
3281
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
3674
3282
  routeFunction,
3675
- workflowContext,
3676
- effectiveConfig
3283
+ workflowContext
3677
3284
  );
3678
3285
  if (authCheck.isErr()) {
3679
3286
  await dispatchDebug?.("onError", {
@@ -4162,28 +3769,26 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
4162
3769
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
4163
3770
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
4164
3771
  const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
4165
- const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
4166
- const effectiveConfig = getEffectiveConfig(request.headers);
3772
+ const workflowRunCreatedAtHeader = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
3773
+ const workflowRunCreatedAt = workflowRunCreatedAtHeader ? Number(workflowRunCreatedAtHeader) : isFirstInvocation ? Date.now() : 0;
4167
3774
  const workflowContext = new WorkflowContext({
4168
3775
  qstashClient: regionalClient,
4169
3776
  workflowRunId,
4170
3777
  initialPayload: isThirdPartyCallResult(request) ? JSON.parse(rawInitialPayload) : initialPayloadParser(rawInitialPayload),
4171
3778
  headers: recreateUserHeaders(request.headers),
4172
3779
  steps,
4173
- effectiveConfig,
4174
3780
  url: workflowUrl,
4175
3781
  env,
4176
3782
  telemetry,
4177
3783
  invokeCount,
4178
3784
  label,
4179
3785
  retried,
4180
- workflowRunCreatedAt: Number(workflowRunCreatedAt),
3786
+ workflowRunCreatedAt,
4181
3787
  middlewareManager
4182
3788
  });
4183
3789
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
4184
3790
  routeFunction,
4185
- workflowContext,
4186
- effectiveConfig
3791
+ workflowContext
4187
3792
  );
4188
3793
  if (authCheck.isErr()) {
4189
3794
  throw authCheck.error;
@@ -4220,23 +3825,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
4220
3825
  if (steps.length === 1) {
4221
3826
  await middlewareManager.dispatchLifecycle("runStarted", {});
4222
3827
  }
4223
- let outcome;
4224
- try {
4225
- outcome = { ran: true, result: await routeFunction(workflowContext) };
4226
- } catch (error) {
4227
- outcome = { ran: false, error };
4228
- }
4229
- const submitted = await flushPendingStep(workflowContext);
4230
- if (submitted.isErr()) {
4231
- throw submitted.error;
4232
- }
4233
- if (submitted.value.result === "submitted-step") {
4234
- throw submitted.value.abort;
4235
- }
4236
- if (!outcome.ran) {
4237
- throw outcome.error;
4238
- }
4239
- return outcome.result;
3828
+ return await routeFunction(workflowContext);
4240
3829
  },
4241
3830
  onCleanup: async (result2) => {
4242
3831
  await middlewareManager.dispatchLifecycle("runCompleted", {