@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/astro.js CHANGED
@@ -217,14 +217,6 @@ var WORKFLOW_CREATED_AT_HEADER = "Upstash-Workflow-CreatedAt";
217
217
  var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
218
218
  var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
219
219
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
220
- var WORKFLOW_FEATURE_SET = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
221
- var WORKFLOW_STEP_CONFIG_CALL_TYPE = "stepConfig";
222
- var WORKFLOW_STEP_CONFIG_HEADER = "Upstash-Workflow-Step-Config";
223
- var FLOW_CONTROL_KEY_HEADER = "Upstash-Flow-Control-Key";
224
- var FLOW_CONTROL_VALUE_HEADER = "Upstash-Flow-Control-Value";
225
- var RETRIES_HEADER = "Upstash-Retries";
226
- var RETRY_DELAY_HEADER = "Upstash-Retry-Delay";
227
- var WORKFLOW_STEP_CONFIG_FEATURE = "WF_StepConfig";
228
220
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
229
221
  var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
230
222
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
@@ -242,6 +234,102 @@ var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
242
234
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
243
235
  var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
244
236
 
237
+ // src/context/auto-executor.ts
238
+ var import_qstash5 = require("@upstash/qstash");
239
+
240
+ // src/qstash/headers.ts
241
+ var import_qstash4 = require("@upstash/qstash");
242
+
243
+ // src/utils.ts
244
+ var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
245
+ var NANOID_LENGTH = 21;
246
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
247
+ function validateLabel(label) {
248
+ if (label === void 0) return;
249
+ const labels = Array.isArray(label) ? label : [label];
250
+ if (labels.length === 0) {
251
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
252
+ }
253
+ for (const value of labels) {
254
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
255
+ throw new WorkflowNonRetryableError(
256
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
257
+ );
258
+ }
259
+ }
260
+ }
261
+ function serializeLabel(label) {
262
+ return Array.isArray(label) ? label.join(",") : label;
263
+ }
264
+ function validateFlowControl(flowControl) {
265
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
266
+ throw new WorkflowNonRetryableError(
267
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
268
+ );
269
+ }
270
+ }
271
+ function getRandomInt() {
272
+ return Math.floor(Math.random() * NANOID_CHARS.length);
273
+ }
274
+ function nanoid(length = NANOID_LENGTH) {
275
+ return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
276
+ }
277
+ function getWorkflowRunId(id) {
278
+ return `wfr_${id ?? nanoid()}`;
279
+ }
280
+ function decodeBase64(base64) {
281
+ const binString = atob(base64);
282
+ try {
283
+ const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
284
+ return new TextDecoder().decode(intArray);
285
+ } catch (error) {
286
+ console.warn(
287
+ `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
288
+ );
289
+ return binString;
290
+ }
291
+ }
292
+ function getUserIdFromToken(qstashClient) {
293
+ try {
294
+ const token = qstashClient.token;
295
+ const decodedToken = decodeBase64(token);
296
+ const tokenPayload = JSON.parse(decodedToken);
297
+ const userId = tokenPayload.UserID;
298
+ if (!userId) {
299
+ throw new WorkflowError("QStash token payload does not contain userId");
300
+ }
301
+ return userId;
302
+ } catch (error) {
303
+ throw new WorkflowError(
304
+ `Failed to decode QStash token while running create webhook step: ${error.message}`
305
+ );
306
+ }
307
+ }
308
+ function getQStashUrl(qstashClient) {
309
+ try {
310
+ const requester = qstashClient.http;
311
+ const baseUrl = requester.baseUrl;
312
+ if (!baseUrl) {
313
+ throw new WorkflowError("QStash client does not have a baseUrl");
314
+ }
315
+ return baseUrl;
316
+ } catch (error) {
317
+ throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
318
+ }
319
+ }
320
+ function getEventId() {
321
+ return `evt_${nanoid(15)}`;
322
+ }
323
+ function stringifyBody(body) {
324
+ if (body === void 0) {
325
+ return void 0;
326
+ }
327
+ if (typeof body === "string") {
328
+ return body;
329
+ }
330
+ return JSON.stringify(body);
331
+ }
332
+
245
333
  // node_modules/neverthrow/dist/index.es.js
246
334
  var defaultErrorConfig = {
247
335
  withStackTrace: false
@@ -657,102 +745,6 @@ var Err = class {
657
745
  };
658
746
  var fromThrowable = Result.fromThrowable;
659
747
 
660
- // src/context/auto-executor.ts
661
- var import_qstash5 = require("@upstash/qstash");
662
-
663
- // src/qstash/headers.ts
664
- var import_qstash4 = require("@upstash/qstash");
665
-
666
- // src/utils.ts
667
- var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
668
- var NANOID_LENGTH = 21;
669
- var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
670
- function validateLabel(label) {
671
- if (label === void 0) return;
672
- const labels = Array.isArray(label) ? label : [label];
673
- if (labels.length === 0) {
674
- throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
675
- }
676
- for (const value of labels) {
677
- if (!RESOURCE_NAME_PATTERN.test(value)) {
678
- throw new WorkflowNonRetryableError(
679
- `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
680
- );
681
- }
682
- }
683
- }
684
- function serializeLabel(label) {
685
- return Array.isArray(label) ? label.join(",") : label;
686
- }
687
- function validateFlowControl(flowControl) {
688
- if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
689
- throw new WorkflowNonRetryableError(
690
- `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
691
- );
692
- }
693
- }
694
- function getRandomInt() {
695
- return Math.floor(Math.random() * NANOID_CHARS.length);
696
- }
697
- function nanoid(length = NANOID_LENGTH) {
698
- return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
699
- }
700
- function getWorkflowRunId(id) {
701
- return `wfr_${id ?? nanoid()}`;
702
- }
703
- function decodeBase64(base64) {
704
- const binString = atob(base64);
705
- try {
706
- const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
707
- return new TextDecoder().decode(intArray);
708
- } catch (error) {
709
- console.warn(
710
- `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
711
- );
712
- return binString;
713
- }
714
- }
715
- function getUserIdFromToken(qstashClient) {
716
- try {
717
- const token = qstashClient.token;
718
- const decodedToken = decodeBase64(token);
719
- const tokenPayload = JSON.parse(decodedToken);
720
- const userId = tokenPayload.UserID;
721
- if (!userId) {
722
- throw new WorkflowError("QStash token payload does not contain userId");
723
- }
724
- return userId;
725
- } catch (error) {
726
- throw new WorkflowError(
727
- `Failed to decode QStash token while running create webhook step: ${error.message}`
728
- );
729
- }
730
- }
731
- function getQStashUrl(qstashClient) {
732
- try {
733
- const requester = qstashClient.http;
734
- const baseUrl = requester.baseUrl;
735
- if (!baseUrl) {
736
- throw new WorkflowError("QStash client does not have a baseUrl");
737
- }
738
- return baseUrl;
739
- } catch (error) {
740
- throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
741
- }
742
- }
743
- function getEventId() {
744
- return `evt_${nanoid(15)}`;
745
- }
746
- function stringifyBody(body) {
747
- if (body === void 0) {
748
- return void 0;
749
- }
750
- if (typeof body === "string") {
751
- return body;
752
- }
753
- return JSON.stringify(body);
754
- }
755
-
756
748
  // src/types.ts
757
749
  var StepTypes = [
758
750
  "Initial",
@@ -792,6 +784,10 @@ var triggerFirstInvocation = async (params) => {
792
784
  workflowConfig: {
793
785
  workflowRunId: workflowContext.workflowRunId,
794
786
  workflowUrl: workflowContext.url,
787
+ // the run doesn't exist yet, so the trigger time is sent when the creation time
788
+ // is not known. serve and client.trigger set it on the context already, so a
789
+ // retry of this request carries the same value and is deduplicated.
790
+ workflowRunCreatedAt: workflowContext.workflowRunCreatedAt || Date.now(),
795
791
  failureUrl,
796
792
  retries,
797
793
  retryDelay,
@@ -858,10 +854,6 @@ var triggerFirstInvocation = async (params) => {
858
854
  return err(error_);
859
855
  }
860
856
  };
861
- var flushPendingStep = async (workflowContext) => {
862
- const { executor } = workflowContext;
863
- return await executor.submitPendingStep();
864
- };
865
857
  var triggerRouteFunction = async ({
866
858
  onCleanup,
867
859
  onStep,
@@ -899,7 +891,10 @@ var triggerWorkflowDelete = async (workflowContext, result, cancel = false, disp
899
891
  path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
900
892
  method: "DELETE",
901
893
  parseResponseAsJson: false,
902
- body: JSON.stringify(result)
894
+ body: JSON.stringify(result),
895
+ // with the creation time, QStash deletes the run only if it is the same run.
896
+ // a late delete of a previous run can't delete a new run with the same id.
897
+ headers: workflowContext.workflowRunCreatedAt ? { [WORKFLOW_CREATED_AT_HEADER]: workflowContext.workflowRunCreatedAt.toString() } : void 0
903
898
  });
904
899
  await dispatchDebug?.("onInfo", {
905
900
  info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
@@ -976,6 +971,7 @@ ${atob(callbackMessage.body ?? "")}`
976
971
  const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
977
972
  const contentType = request.headers.get("Upstash-Workflow-ContentType");
978
973
  const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
974
+ const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
979
975
  if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
980
976
  throw new Error(
981
977
  `Missing info in callback message source header: ${JSON.stringify({
@@ -993,6 +989,7 @@ ${atob(callbackMessage.body ?? "")}`
993
989
  workflowConfig: {
994
990
  workflowRunId,
995
991
  workflowUrl,
992
+ workflowRunCreatedAt: Number(workflowRunCreatedAt ?? "0"),
996
993
  telemetry: telemetry2
997
994
  },
998
995
  invokeCount: Number(invokeCount)
@@ -1069,29 +1066,8 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1069
1066
  var BaseLazyStep = class _BaseLazyStep {
1070
1067
  stepName;
1071
1068
  context;
1072
- /**
1073
- * step-level settings (flow control, retries etc.) which override the
1074
- * settings the workflow run was triggered with, for this step only.
1075
- */
1076
- stepSettings;
1077
- /**
1078
- * whether this step's result can be submitted after the route function
1079
- * has moved on, instead of right away.
1080
- *
1081
- * Enabled for steps whose `getResultStep` produces the final `out` —
1082
- * which is not the same as "needs no server round trip":
1083
- * `LazyCreateWebhookStep` builds its result in `getBody` and returns
1084
- * `out: undefined` from `getResultStep`, so deferring it would hand
1085
- * `undefined` to the route function.
1086
- *
1087
- * Deferring lets the route function continue and reveal the next step,
1088
- * so that step's settings can ride on this step's submission instead
1089
- * of needing a step config request of their own.
1090
- */
1091
- supportsDeferredSubmission = false;
1092
- constructor(context, stepName, stepSettings) {
1069
+ constructor(context, stepName) {
1093
1070
  this.context = context;
1094
- this.stepSettings = stepSettings;
1095
1071
  if (!stepName) {
1096
1072
  throw new WorkflowError(
1097
1073
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -1155,18 +1131,13 @@ var BaseLazyStep = class _BaseLazyStep {
1155
1131
  step.out = JSON.stringify(step.out);
1156
1132
  return JSON.stringify(step);
1157
1133
  }
1158
- getHeaders({
1159
- context,
1160
- telemetry: telemetry2,
1161
- invokeCount,
1162
- step,
1163
- stepSettings
1164
- }) {
1134
+ getHeaders({ context, telemetry: telemetry2, invokeCount, step }) {
1165
1135
  return getHeaders({
1166
1136
  initHeaderValue: "false",
1167
1137
  workflowConfig: {
1168
1138
  workflowRunId: context.workflowRunId,
1169
1139
  workflowUrl: context.url,
1140
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1170
1141
  useJSONContent: false,
1171
1142
  telemetry: telemetry2
1172
1143
  },
@@ -1174,8 +1145,7 @@ var BaseLazyStep = class _BaseLazyStep {
1174
1145
  stepInfo: {
1175
1146
  step,
1176
1147
  lazyStep: this
1177
- },
1178
- stepSettings
1148
+ }
1179
1149
  });
1180
1150
  }
1181
1151
  async submitStep({ context, body, headers }) {
@@ -1193,9 +1163,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1193
1163
  stepFunction;
1194
1164
  stepType = "Run";
1195
1165
  allowUndefinedOut = true;
1196
- supportsDeferredSubmission = true;
1197
- constructor(context, stepName, stepFunction, stepSettings) {
1198
- super(context, stepName, stepSettings);
1166
+ constructor(context, stepName, stepFunction) {
1167
+ super(context, stepName);
1199
1168
  this.stepFunction = stepFunction;
1200
1169
  }
1201
1170
  getPlanStep(concurrent, targetStep) {
@@ -1225,7 +1194,6 @@ var LazySleepStep = class extends BaseLazyStep {
1225
1194
  sleep;
1226
1195
  stepType = "SleepFor";
1227
1196
  allowUndefinedOut = true;
1228
- supportsDeferredSubmission = true;
1229
1197
  constructor(context, stepName, sleep) {
1230
1198
  super(context, stepName);
1231
1199
  this.sleep = sleep;
@@ -1265,7 +1233,6 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1265
1233
  sleepUntil;
1266
1234
  stepType = "SleepUntil";
1267
1235
  allowUndefinedOut = true;
1268
- supportsDeferredSubmission = true;
1269
1236
  constructor(context, stepName, sleepUntil) {
1270
1237
  super(context, stepName);
1271
1238
  this.sleepUntil = sleepUntil;
@@ -1498,6 +1465,8 @@ var LazyWaitEventStep = class extends BaseLazyStep {
1498
1465
  ) : {},
1499
1466
  // note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
1500
1467
  "Upstash-Workflow-Runid": [context.workflowRunId],
1468
+ // same for WORKFLOW_CREATED_AT_HEADER, because Createdat -> CreatedAt:
1469
+ ...context.workflowRunCreatedAt ? { "Upstash-Workflow-Createdat": [context.workflowRunCreatedAt.toString()] } : {},
1501
1470
  [WORKFLOW_INIT_HEADER]: ["false"],
1502
1471
  [WORKFLOW_URL_HEADER]: [context.url],
1503
1472
  "Upstash-Workflow-CallType": ["step"]
@@ -1600,6 +1569,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1600
1569
  workflowConfig: {
1601
1570
  workflowRunId: context.workflowRunId,
1602
1571
  workflowUrl: context.url,
1572
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1603
1573
  telemetry: telemetry2,
1604
1574
  useJSONContent: false
1605
1575
  },
@@ -1609,6 +1579,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1609
1579
  invokerHeaders[key] = value;
1610
1580
  });
1611
1581
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1582
+ if (context.workflowRunCreatedAt) {
1583
+ invokerHeaders["Upstash-Workflow-Createdat"] = context.workflowRunCreatedAt.toString();
1584
+ }
1612
1585
  const request = {
1613
1586
  body: stringifyBody(this.params.body),
1614
1587
  headers: Object.fromEntries(
@@ -1637,6 +1610,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1637
1610
  workflowConfig: {
1638
1611
  workflowRunId: getWorkflowRunId(workflowRunId),
1639
1612
  workflowUrl: newUrl,
1613
+ // the invoked run doesn't exist yet, so the creation time of the invoker run is sent.
1614
+ // it separates the invocations made by different runs of the invoker.
1615
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1640
1616
  retries,
1641
1617
  retryDelay,
1642
1618
  telemetry: telemetry2,
@@ -1758,7 +1734,6 @@ var WorkflowHeaders = class {
1758
1734
  invokeCount;
1759
1735
  initHeaderValue;
1760
1736
  stepInfo;
1761
- stepSettings;
1762
1737
  headers;
1763
1738
  /**
1764
1739
  * @param params workflow header parameters
@@ -1768,20 +1743,17 @@ var WorkflowHeaders = class {
1768
1743
  workflowConfig,
1769
1744
  invokeCount,
1770
1745
  initHeaderValue,
1771
- stepInfo,
1772
- stepSettings
1746
+ stepInfo
1773
1747
  }) {
1774
1748
  this.userHeaders = userHeaders;
1775
1749
  this.workflowConfig = workflowConfig;
1776
1750
  this.invokeCount = invokeCount;
1777
1751
  this.initHeaderValue = initHeaderValue;
1778
1752
  this.stepInfo = stepInfo;
1779
- this.stepSettings = stepSettings;
1780
1753
  this.headers = {
1781
1754
  rawHeaders: {},
1782
1755
  workflowHeaders: {},
1783
- failureHeaders: {},
1784
- stepSettingsHeaders: {}
1756
+ failureHeaders: {}
1785
1757
  };
1786
1758
  }
1787
1759
  getHeaders() {
@@ -1792,7 +1764,6 @@ var WorkflowHeaders = class {
1792
1764
  this.addUserHeaders();
1793
1765
  this.addInvokeCount();
1794
1766
  this.addFailureUrl();
1795
- this.addStepSettings();
1796
1767
  const contentType = this.addContentType();
1797
1768
  return this.prefixHeaders(contentType);
1798
1769
  }
@@ -1802,10 +1773,13 @@ var WorkflowHeaders = class {
1802
1773
  [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
1803
1774
  [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
1804
1775
  [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
1805
- [WORKFLOW_FEATURE_HEADER]: WORKFLOW_FEATURE_SET,
1776
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
1806
1777
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1807
1778
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
1808
1779
  };
1780
+ if (this.workflowConfig.workflowRunCreatedAt) {
1781
+ this.headers.rawHeaders[WORKFLOW_CREATED_AT_HEADER] = this.workflowConfig.workflowRunCreatedAt.toString();
1782
+ }
1809
1783
  if (this.stepInfo?.lazyStep.stepType !== "Call") {
1810
1784
  this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
1811
1785
  }
@@ -1880,7 +1854,7 @@ var WorkflowHeaders = class {
1880
1854
  this.headers.failureHeaders["Workflow-Init"] = "false";
1881
1855
  this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
1882
1856
  this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
1883
- this.headers.failureHeaders["Feature-Set"] = WORKFLOW_FEATURE_SET;
1857
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
1884
1858
  if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
1885
1859
  this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
1886
1860
  }
@@ -1888,42 +1862,6 @@ var WorkflowHeaders = class {
1888
1862
  this.headers.failureHeaders["Retry-Delay"] = this.workflowConfig.retryDelay.toString();
1889
1863
  }
1890
1864
  }
1891
- /**
1892
- * Applies the step-level settings of a step to the message.
1893
- *
1894
- * These headers configure the message itself, so that QStash uses them
1895
- * instead of the settings the run was triggered with. The delivery of
1896
- * the message is what executes the step, which is how a step's
1897
- * settings reach it.
1898
- *
1899
- * When any setting is present the feature set is extended with
1900
- * `WF_StepConfig`, which is what tells QStash to keep them. QStash
1901
- * reports that back on the delivery as `Upstash-Workflow-Step-Config`.
1902
- */
1903
- addStepSettings() {
1904
- if (!this.stepSettings) {
1905
- return;
1906
- }
1907
- const headers = {};
1908
- if (this.stepSettings.flowControl) {
1909
- const { flowControlKey, flowControlValue } = prepareFlowControl(
1910
- this.stepSettings.flowControl
1911
- );
1912
- headers[FLOW_CONTROL_KEY_HEADER] = flowControlKey;
1913
- headers[FLOW_CONTROL_VALUE_HEADER] = flowControlValue;
1914
- }
1915
- if (this.stepSettings.retries !== void 0) {
1916
- headers[RETRIES_HEADER] = this.stepSettings.retries.toString();
1917
- }
1918
- if (this.stepSettings.retryDelay) {
1919
- headers[RETRY_DELAY_HEADER] = this.stepSettings.retryDelay;
1920
- }
1921
- if (Object.keys(headers).length === 0) {
1922
- return;
1923
- }
1924
- headers[WORKFLOW_FEATURE_HEADER] = `${WORKFLOW_FEATURE_SET},${WORKFLOW_STEP_CONFIG_FEATURE}`;
1925
- this.headers.stepSettingsHeaders = headers;
1926
- }
1927
1865
  addContentType() {
1928
1866
  if (this.workflowConfig.useJSONContent) {
1929
1867
  this.headers.rawHeaders["content-type"] = "application/json";
@@ -1937,17 +1875,14 @@ var WorkflowHeaders = class {
1937
1875
  return contentType;
1938
1876
  }
1939
1877
  prefixHeaders(contentType) {
1940
- const { rawHeaders, workflowHeaders, failureHeaders, stepSettingsHeaders } = this.headers;
1878
+ const { rawHeaders, workflowHeaders, failureHeaders } = this.headers;
1941
1879
  const isCall = this.stepInfo?.lazyStep.stepType === "Call";
1942
1880
  return {
1943
1881
  headers: {
1944
1882
  ...rawHeaders,
1945
1883
  ...addPrefixToHeaders(workflowHeaders, isCall ? "Upstash-Callback-" : "Upstash-"),
1946
1884
  ...addPrefixToHeaders(failureHeaders, "Upstash-Failure-Callback-"),
1947
- ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {},
1948
- // last, so they override the run's settings above. Never
1949
- // prefixed: they configure this message, not its callback.
1950
- ...stepSettingsHeaders
1885
+ ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {}
1951
1886
  },
1952
1887
  contentType
1953
1888
  };
@@ -1998,16 +1933,16 @@ var submitParallelSteps = async ({
1998
1933
  info: `Submitting ${planSteps.length} parallel steps.`
1999
1934
  });
2000
1935
  const result = await context.qstashClient.batch(
2001
- planSteps.map((planStep, index) => {
1936
+ planSteps.map((planStep) => {
2002
1937
  const { headers } = getHeaders({
2003
1938
  initHeaderValue: "false",
2004
1939
  workflowConfig: {
2005
1940
  workflowRunId: context.workflowRunId,
2006
1941
  workflowUrl: context.url,
1942
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
2007
1943
  telemetry: telemetry2
2008
1944
  },
2009
- invokeCount,
2010
- stepSettings: steps[index].stepSettings
1945
+ invokeCount
2011
1946
  });
2012
1947
  return {
2013
1948
  headers,
@@ -2026,38 +1961,31 @@ var submitParallelSteps = async ({
2026
1961
  }
2027
1962
  throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
2028
1963
  };
2029
- var executeStep = async ({
1964
+ var submitSingleStep = async ({
1965
+ context,
2030
1966
  lazyStep,
2031
1967
  stepId,
1968
+ invokeCount,
2032
1969
  concurrency,
1970
+ telemetry: telemetry2,
1971
+ dispatchDebug,
2033
1972
  dispatchLifecycle
2034
1973
  }) => {
2035
1974
  await dispatchLifecycle("beforeExecution", {
2036
1975
  stepName: lazyStep.stepName
2037
1976
  });
1977
+ let resultStep;
2038
1978
  try {
2039
- return await lazyStep.getResultStep(concurrency, stepId);
1979
+ resultStep = await lazyStep.getResultStep(concurrency, stepId);
2040
1980
  } catch (error) {
2041
1981
  attachStepNameToError(error, lazyStep.stepName);
2042
1982
  throw error;
2043
1983
  }
2044
- };
2045
- var submitStepResult = async ({
2046
- context,
2047
- lazyStep,
2048
- resultStep,
2049
- invokeCount,
2050
- concurrency,
2051
- telemetry: telemetry2,
2052
- dispatchDebug,
2053
- nextStepSettings
2054
- }) => {
2055
1984
  const { headers } = lazyStep.getHeaders({
2056
1985
  context,
2057
1986
  step: resultStep,
2058
1987
  invokeCount,
2059
- telemetry: telemetry2,
2060
- stepSettings: nextStepSettings
1988
+ telemetry: telemetry2
2061
1989
  });
2062
1990
  const body = lazyStep.getBody({
2063
1991
  context,
@@ -2082,138 +2010,6 @@ var submitStepResult = async ({
2082
2010
  }
2083
2011
  return resultStep;
2084
2012
  };
2085
- var publishStepConfigRequest = async ({
2086
- context,
2087
- lazyStep,
2088
- targetStep,
2089
- invokeCount,
2090
- telemetry: telemetry2,
2091
- dispatchDebug
2092
- }) => {
2093
- const { headers } = getHeaders({
2094
- initHeaderValue: "false",
2095
- workflowConfig: {
2096
- workflowRunId: context.workflowRunId,
2097
- workflowUrl: context.url,
2098
- telemetry: telemetry2
2099
- },
2100
- invokeCount,
2101
- stepSettings: lazyStep.stepSettings
2102
- });
2103
- await dispatchDebug("onInfo", {
2104
- info: `Step "${lazyStep.stepName}" (${targetStep}) has step-level settings which the current delivery does not carry. Requesting a delivery which does.`
2105
- });
2106
- const result = await context.qstashClient.publishJSON({
2107
- headers: {
2108
- ...headers,
2109
- "Upstash-Workflow-CallType": WORKFLOW_STEP_CONFIG_CALL_TYPE
2110
- },
2111
- method: "POST",
2112
- body: { targetStep, invokeCount },
2113
- url: context.url,
2114
- contentBasedDeduplication: true
2115
- });
2116
- if (result?.deduplicated) {
2117
- await dispatchDebug("onWarning", {
2118
- 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.`
2119
- });
2120
- } else if (result?.messageId) {
2121
- await dispatchDebug("onInfo", {
2122
- info: `Requested a delivery under the settings of step "${lazyStep.stepName}" with messageId: ${result.messageId}.`
2123
- });
2124
- }
2125
- };
2126
-
2127
- // src/qstash/step-config.ts
2128
- var DEFAULT_PARALLELISM = 0;
2129
- var DEFAULT_RATE = 0;
2130
- var DEFAULT_PERIOD_SECONDS = 1;
2131
- var SECONDS_PER_UNIT = {
2132
- s: 1,
2133
- m: 60,
2134
- h: 60 * 60,
2135
- d: 24 * 60 * 60
2136
- };
2137
- var durationToSeconds = (duration) => {
2138
- if (typeof duration === "number") {
2139
- return Number.isFinite(duration) ? duration : void 0;
2140
- }
2141
- const match = /^(\d+)([smhd])$/.exec(duration.trim());
2142
- if (match) {
2143
- return Number(match[1]) * SECONDS_PER_UNIT[match[2]];
2144
- }
2145
- const seconds = Number(duration.trim());
2146
- return Number.isFinite(seconds) ? seconds : void 0;
2147
- };
2148
- var normalizeFlowControl = (flowControl) => {
2149
- const period = flowControl.period === void 0 ? void 0 : durationToSeconds(flowControl.period);
2150
- return {
2151
- key: flowControl.key,
2152
- parallelism: flowControl.parallelism ?? DEFAULT_PARALLELISM,
2153
- rate: flowControl.rate ?? flowControl.ratePerSecond ?? DEFAULT_RATE,
2154
- period: period ?? DEFAULT_PERIOD_SECONDS
2155
- };
2156
- };
2157
- var parseFlowControlHeaders = (key, value) => {
2158
- if (!key) {
2159
- return void 0;
2160
- }
2161
- const flowControl = {
2162
- key,
2163
- parallelism: DEFAULT_PARALLELISM,
2164
- rate: DEFAULT_RATE,
2165
- period: DEFAULT_PERIOD_SECONDS
2166
- };
2167
- for (const entry of (value ?? "").split(",")) {
2168
- const [name, rawValue] = entry.split("=").map((part) => part.trim());
2169
- if (!name || rawValue === void 0) {
2170
- continue;
2171
- }
2172
- switch (name) {
2173
- case "parallelism": {
2174
- flowControl.parallelism = Number(rawValue);
2175
- break;
2176
- }
2177
- case "rate": {
2178
- flowControl.rate = Number(rawValue);
2179
- break;
2180
- }
2181
- case "period": {
2182
- flowControl.period = durationToSeconds(rawValue) ?? DEFAULT_PERIOD_SECONDS;
2183
- break;
2184
- }
2185
- }
2186
- }
2187
- return flowControl;
2188
- };
2189
- var getEffectiveConfig = (headers) => {
2190
- const retriesHeader = headers.get(RETRIES_HEADER);
2191
- return {
2192
- flowControl: parseFlowControlHeaders(
2193
- headers.get(FLOW_CONTROL_KEY_HEADER),
2194
- headers.get(FLOW_CONTROL_VALUE_HEADER)
2195
- ),
2196
- retries: retriesHeader === null ? void 0 : Number(retriesHeader),
2197
- retryDelay: headers.get(RETRY_DELAY_HEADER) ?? void 0,
2198
- hasStepConfig: headers.get(WORKFLOW_STEP_CONFIG_HEADER) === "true"
2199
- };
2200
- };
2201
- var describeStepSettingsMismatch = (stepSettings, effectiveConfig) => {
2202
- if (stepSettings.flowControl) {
2203
- const wanted = normalizeFlowControl(stepSettings.flowControl);
2204
- const applied = effectiveConfig.flowControl;
2205
- if (!applied || applied.key !== wanted.key || applied.parallelism !== wanted.parallelism || applied.rate !== wanted.rate || applied.period !== wanted.period) {
2206
- return `flow control: expected ${JSON.stringify(wanted)}, delivery has ${JSON.stringify(applied)}`;
2207
- }
2208
- }
2209
- if (stepSettings.retries !== void 0 && effectiveConfig.retries !== void 0 && stepSettings.retries !== effectiveConfig.retries) {
2210
- return `retries: expected ${stepSettings.retries}, delivery has ${effectiveConfig.retries}`;
2211
- }
2212
- if (stepSettings.retryDelay !== void 0 && stepSettings.retryDelay !== effectiveConfig.retryDelay) {
2213
- return `retry delay: expected '${stepSettings.retryDelay}', delivery has '${effectiveConfig.retryDelay ?? ""}'`;
2214
- }
2215
- return void 0;
2216
- };
2217
2013
 
2218
2014
  // src/context/auto-executor.ts
2219
2015
  var AutoExecutor = class _AutoExecutor {
@@ -2230,25 +2026,6 @@ var AutoExecutor = class _AutoExecutor {
2230
2026
  stepCount = 0;
2231
2027
  planStepCount = 0;
2232
2028
  executingStep = false;
2233
- /**
2234
- * an executed step whose result hasn't been submitted to QStash yet.
2235
- *
2236
- * Set when a step which can produce its result in-process executes. The
2237
- * submission waits so that the route function can continue and reveal
2238
- * what comes next: if that is a single step with step-level settings,
2239
- * the settings ride on this submission and no step config request is
2240
- * needed, since the delivery of the submission is what executes it.
2241
- *
2242
- * Flushed when the next step is reached (see `addStep`) or when the
2243
- * route function ends (see `flushPendingStep` in `serve`).
2244
- */
2245
- pendingStep;
2246
- /**
2247
- * configuration QStash applied to the delivery being handled. A step
2248
- * with step-level settings is settled by comparing its settings against
2249
- * this.
2250
- */
2251
- effectiveConfig;
2252
2029
  /**
2253
2030
  * @param context workflow context
2254
2031
  * @param steps list of steps
@@ -2256,17 +2033,14 @@ var AutoExecutor = class _AutoExecutor {
2256
2033
  * @param dispatchLifecycle lifecycle event dispatcher
2257
2034
  * @param telemetry optional telemetry information
2258
2035
  * @param invokeCount optional invoke count
2259
- * @param effectiveConfig configuration QStash applied to the delivery
2260
- * being handled
2261
2036
  */
2262
- constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry2, invokeCount, effectiveConfig) {
2037
+ constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry2, invokeCount) {
2263
2038
  this.context = context;
2264
2039
  this.steps = steps;
2265
2040
  this.dispatchDebug = dispatchDebug;
2266
2041
  this.dispatchLifecycle = dispatchLifecycle;
2267
2042
  this.telemetry = telemetry2;
2268
2043
  this.invokeCount = invokeCount ?? 0;
2269
- this.effectiveConfig = effectiveConfig ?? { hasStepConfig: false };
2270
2044
  this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
2271
2045
  }
2272
2046
  /**
@@ -2301,15 +2075,6 @@ var AutoExecutor = class _AutoExecutor {
2301
2075
  lazyStepList.push(stepInfo);
2302
2076
  const index = this.indexInCurrentList++;
2303
2077
  const requestComplete = this.deferExecution().then(async () => {
2304
- const submitted = await this.submitPendingStep(
2305
- lazyStepList.length === 1 ? lazyStepList[0].stepSettings : void 0
2306
- );
2307
- if (submitted.isErr()) {
2308
- throw submitted.error;
2309
- }
2310
- if (submitted.value.result === "submitted-step") {
2311
- throw submitted.value.abort;
2312
- }
2313
2078
  if (!this.promises.has(lazyStepList)) {
2314
2079
  const promise2 = this.getExecutionPromise(lazyStepList);
2315
2080
  this.promises.set(lazyStepList, promise2);
@@ -2363,100 +2128,18 @@ var AutoExecutor = class _AutoExecutor {
2363
2128
  }
2364
2129
  return parsedOut;
2365
2130
  }
2366
- const mismatch = lazyStep.stepSettings ? describeStepSettingsMismatch(lazyStep.stepSettings, this.effectiveConfig) : void 0;
2367
- if (mismatch) {
2368
- if (!this.effectiveConfig.hasStepConfig) {
2369
- await publishStepConfigRequest({
2370
- context: this.context,
2371
- lazyStep,
2372
- targetStep: this.stepCount,
2373
- invokeCount: this.invokeCount,
2374
- telemetry: this.telemetry,
2375
- dispatchDebug: this.dispatchDebug
2376
- });
2377
- throw new WorkflowAbort(lazyStep.stepName);
2378
- } else {
2379
- await this.dispatchDebug("onWarning", {
2380
- 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.`
2381
- });
2382
- }
2383
- }
2384
- const resultStep = await executeStep({
2385
- lazyStep,
2386
- stepId: this.stepCount,
2387
- concurrency: NO_CONCURRENCY,
2388
- dispatchLifecycle: this.dispatchLifecycle
2389
- });
2390
- if (lazyStep.supportsDeferredSubmission) {
2391
- this.pendingStep = { status: "held", lazyStep, resultStep };
2392
- return lazyStep.parseOut({
2393
- ...resultStep,
2394
- out: resultStep.out === void 0 ? void 0 : JSON.stringify(resultStep.out)
2395
- });
2396
- }
2397
- await submitStepResult({
2131
+ const resultStep = await submitSingleStep({
2398
2132
  context: this.context,
2399
2133
  lazyStep,
2400
- resultStep,
2134
+ stepId: this.stepCount,
2401
2135
  invokeCount: this.invokeCount,
2402
- concurrency: NO_CONCURRENCY,
2136
+ concurrency: 1,
2403
2137
  telemetry: this.telemetry,
2404
- dispatchDebug: this.dispatchDebug
2138
+ dispatchDebug: this.dispatchDebug,
2139
+ dispatchLifecycle: this.dispatchLifecycle
2405
2140
  });
2406
2141
  throw new WorkflowAbort(lazyStep.stepName, resultStep);
2407
2142
  }
2408
- /**
2409
- * Submits the result of the step being held, if there is one, and
2410
- * returns the abort the caller has to throw to end the invocation.
2411
- *
2412
- * Returns undefined when no step is being held, which is the caller's
2413
- * signal that there is nothing to end. Throws instead of returning
2414
- * when the submission itself fails, so that error reaches the caller
2415
- * rather than an abort claiming the step was submitted.
2416
- *
2417
- * Callers which arrive while a submission is already under way (the
2418
- * steps of a parallel group, added together) wait for that one and get
2419
- * the same abort, rather than submitting a second time.
2420
- *
2421
- * The next step's settings are attached whenever it has any, without
2422
- * checking them against the current delivery: the executor only knows
2423
- * the configuration of the delivery in hand, which inside a
2424
- * delivery is the *previous* step's, so such a check would be wrong
2425
- * exactly when two steps with settings follow each other.
2426
- *
2427
- * @param nextStepSettings step-level settings of the next step
2428
- * @returns `submitted-step` with the abort which ends this invocation,
2429
- * or `no-pending-step` when nothing was held and there is nothing to
2430
- * end
2431
- */
2432
- async submitPendingStep(nextStepSettings) {
2433
- if (!this.pendingStep) {
2434
- return ok({ result: "no-pending-step" });
2435
- }
2436
- try {
2437
- if (this.pendingStep.status === "submitting") {
2438
- return ok({ result: "submitted-step", abort: await this.pendingStep.submitted });
2439
- }
2440
- const { lazyStep, resultStep } = this.pendingStep;
2441
- const submitted = (async () => {
2442
- await submitStepResult({
2443
- context: this.context,
2444
- lazyStep,
2445
- resultStep,
2446
- invokeCount: this.invokeCount,
2447
- concurrency: NO_CONCURRENCY,
2448
- telemetry: this.telemetry,
2449
- dispatchDebug: this.dispatchDebug,
2450
- nextStepSettings
2451
- });
2452
- return new WorkflowAbort(lazyStep.stepName, resultStep);
2453
- })();
2454
- this.pendingStep = { status: "submitting", submitted };
2455
- return ok({ result: "submitted-step", abort: await submitted });
2456
- } catch (error) {
2457
- return err(error);
2458
- }
2459
- }
2460
2143
  /**
2461
2144
  * Runs steps in parallel.
2462
2145
  *
@@ -2505,20 +2188,15 @@ var AutoExecutor = class _AutoExecutor {
2505
2188
  validateStep(parallelSteps[stepIndex], planStep);
2506
2189
  try {
2507
2190
  const parallelStep = parallelSteps[stepIndex];
2508
- const resultStep = await executeStep({
2509
- lazyStep: parallelStep,
2510
- stepId: planStep.targetStep,
2511
- concurrency: parallelSteps.length,
2512
- dispatchLifecycle: this.dispatchLifecycle
2513
- });
2514
- await submitStepResult({
2191
+ const resultStep = await submitSingleStep({
2515
2192
  context: this.context,
2516
2193
  lazyStep: parallelStep,
2517
- resultStep,
2194
+ stepId: planStep.targetStep,
2518
2195
  invokeCount: this.invokeCount,
2519
2196
  concurrency: parallelSteps.length,
2520
2197
  telemetry: this.telemetry,
2521
- dispatchDebug: this.dispatchDebug
2198
+ dispatchDebug: this.dispatchDebug,
2199
+ dispatchLifecycle: this.dispatchLifecycle
2522
2200
  });
2523
2201
  throw new WorkflowAbort(parallelStep.stepName, resultStep);
2524
2202
  } catch (error) {
@@ -3134,46 +2812,6 @@ var WorkflowContext = class {
3134
2812
  * `1` on the first retry, `2` on the second, and so on.
3135
2813
  */
3136
2814
  retried;
3137
- /**
3138
- * Configuration QStash applied to the request being handled.
3139
- *
3140
- * This is the configuration of *this delivery*, not of the run: it is
3141
- * the configuration the run was triggered with, except inside the
3142
- * delivery which executes a step that has step-level settings, where
3143
- * it is that step's settings. The fields below expose it; the executor
3144
- * gets it directly rather than reaching through the context.
3145
- */
3146
- effectiveConfig;
3147
- /**
3148
- * Flow control QStash applied to the request being handled, if any.
3149
- *
3150
- * This is the flow control of the request in hand, which is the one the
3151
- * run was triggered with except inside a step carrying its own.
3152
- */
3153
- get flowControl() {
3154
- return this.effectiveConfig.flowControl;
3155
- }
3156
- /**
3157
- * Retry limit QStash applied to the request being handled, if it
3158
- * reported one.
3159
- *
3160
- * Not to be confused with {@link retried}, which is how many retries
3161
- * have already happened.
3162
- *
3163
- * @see {@link flowControl} for what "the request being handled" means
3164
- */
3165
- get retries() {
3166
- return this.effectiveConfig.retries;
3167
- }
3168
- /**
3169
- * Retry delay expression QStash applied to the request being handled,
3170
- * if any.
3171
- *
3172
- * @see {@link flowControl} for what "the request being handled" means
3173
- */
3174
- get retryDelay() {
3175
- return this.effectiveConfig.retryDelay;
3176
- }
3177
2815
  constructor({
3178
2816
  qstashClient,
3179
2817
  workflowRunId,
@@ -3187,8 +2825,7 @@ var WorkflowContext = class {
3187
2825
  invokeCount,
3188
2826
  label,
3189
2827
  retried,
3190
- middlewareManager,
3191
- effectiveConfig
2828
+ middlewareManager
3192
2829
  }) {
3193
2830
  this.qstashClient = qstashClient;
3194
2831
  this.workflowRunId = workflowRunId;
@@ -3200,7 +2837,6 @@ var WorkflowContext = class {
3200
2837
  this.env = env ?? {};
3201
2838
  this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
3202
2839
  this.retried = retried ?? 0;
3203
- this.effectiveConfig = effectiveConfig ?? { hasStepConfig: false };
3204
2840
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
3205
2841
  middlewareManagerInstance.assignContext(this);
3206
2842
  this.executor = new AutoExecutor(
@@ -3209,8 +2845,7 @@ var WorkflowContext = class {
3209
2845
  middlewareManagerInstance.dispatchDebug.bind(middlewareManagerInstance),
3210
2846
  middlewareManagerInstance.dispatchLifecycle.bind(middlewareManagerInstance),
3211
2847
  telemetry2,
3212
- invokeCount,
3213
- this.effectiveConfig
2848
+ invokeCount
3214
2849
  );
3215
2850
  }
3216
2851
  /**
@@ -3236,35 +2871,13 @@ var WorkflowContext = class {
3236
2871
  * ])
3237
2872
  * ```
3238
2873
  *
3239
- * Step-level settings can be passed as a third argument, overriding
3240
- * the settings the workflow run was triggered with for this step only:
3241
- *
3242
- * ```typescript
3243
- * const result = await context.run(
3244
- * "step 1",
3245
- * () => {
3246
- * return "result"
3247
- * },
3248
- * {
3249
- * flowControl: { key: "custom-key", parallelism: 3 },
3250
- * retries: 5,
3251
- * }
3252
- * )
3253
- * ```
3254
- *
3255
2874
  * @param stepName name of the step
3256
2875
  * @param stepFunction step function to be executed
3257
- * @param stepSettings step-level settings for this step
3258
2876
  * @returns result of the step function
3259
2877
  */
3260
- async run(stepName, stepFunction, stepSettings) {
3261
- if (stepSettings) {
3262
- validateFlowControl(stepSettings.flowControl);
3263
- }
2878
+ async run(stepName, stepFunction) {
3264
2879
  const wrappedStepFunction = (() => this.executor.wrapStep(stepName, stepFunction));
3265
- return await this.addStep(
3266
- new LazyFunctionStep(this, stepName, wrappedStepFunction, stepSettings)
3267
- );
2880
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
3268
2881
  }
3269
2882
  /**
3270
2883
  * Stops the execution for the duration provided.
@@ -3487,7 +3100,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3487
3100
  *
3488
3101
  * @param routeFunction
3489
3102
  */
3490
- static async tryAuthentication(routeFunction, context, effectiveConfig) {
3103
+ static async tryAuthentication(routeFunction, context) {
3491
3104
  const disabledContext = new _DisabledWorkflowContext({
3492
3105
  qstashClient: new import_qstash10.Client({
3493
3106
  baseUrl: "disabled-client",
@@ -3502,10 +3115,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3502
3115
  initialPayload: context.requestPayload,
3503
3116
  env: context.env,
3504
3117
  label: context.labels,
3505
- retried: context.retried,
3506
- // the route function runs for real here until it reaches a step, so
3507
- // it observes the same configuration as it will on the real context
3508
- effectiveConfig
3118
+ retried: context.retried
3509
3119
  });
3510
3120
  try {
3511
3121
  await routeFunction(disabledContext);
@@ -3722,7 +3332,6 @@ var handleFailure = async ({
3722
3332
  }
3723
3333
  const userHeaders = recreateUserHeaders(request.headers);
3724
3334
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3725
- const effectiveConfig = getEffectiveConfig(request.headers);
3726
3335
  const workflowContext = new WorkflowContext({
3727
3336
  qstashClient,
3728
3337
  workflowRunId,
@@ -3736,13 +3345,11 @@ var handleFailure = async ({
3736
3345
  label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
3737
3346
  retried,
3738
3347
  workflowRunCreatedAt: workflowCreatedAt,
3739
- middlewareManager: void 0,
3740
- effectiveConfig
3348
+ middlewareManager: void 0
3741
3349
  });
3742
3350
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
3743
3351
  routeFunction,
3744
- workflowContext,
3745
- effectiveConfig
3352
+ workflowContext
3746
3353
  );
3747
3354
  if (authCheck.isErr()) {
3748
3355
  await dispatchDebug?.("onError", {
@@ -4231,28 +3838,26 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
4231
3838
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
4232
3839
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
4233
3840
  const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
4234
- const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
4235
- const effectiveConfig = getEffectiveConfig(request.headers);
3841
+ const workflowRunCreatedAtHeader = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
3842
+ const workflowRunCreatedAt = workflowRunCreatedAtHeader ? Number(workflowRunCreatedAtHeader) : isFirstInvocation ? Date.now() : 0;
4236
3843
  const workflowContext = new WorkflowContext({
4237
3844
  qstashClient: regionalClient,
4238
3845
  workflowRunId,
4239
3846
  initialPayload: isThirdPartyCallResult(request) ? JSON.parse(rawInitialPayload) : initialPayloadParser(rawInitialPayload),
4240
3847
  headers: recreateUserHeaders(request.headers),
4241
3848
  steps,
4242
- effectiveConfig,
4243
3849
  url: workflowUrl,
4244
3850
  env,
4245
3851
  telemetry: telemetry2,
4246
3852
  invokeCount,
4247
3853
  label,
4248
3854
  retried,
4249
- workflowRunCreatedAt: Number(workflowRunCreatedAt),
3855
+ workflowRunCreatedAt,
4250
3856
  middlewareManager
4251
3857
  });
4252
3858
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
4253
3859
  routeFunction,
4254
- workflowContext,
4255
- effectiveConfig
3860
+ workflowContext
4256
3861
  );
4257
3862
  if (authCheck.isErr()) {
4258
3863
  throw authCheck.error;
@@ -4289,23 +3894,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
4289
3894
  if (steps.length === 1) {
4290
3895
  await middlewareManager.dispatchLifecycle("runStarted", {});
4291
3896
  }
4292
- let outcome;
4293
- try {
4294
- outcome = { ran: true, result: await routeFunction(workflowContext) };
4295
- } catch (error) {
4296
- outcome = { ran: false, error };
4297
- }
4298
- const submitted = await flushPendingStep(workflowContext);
4299
- if (submitted.isErr()) {
4300
- throw submitted.error;
4301
- }
4302
- if (submitted.value.result === "submitted-step") {
4303
- throw submitted.value.abort;
4304
- }
4305
- if (!outcome.ran) {
4306
- throw outcome.error;
4307
- }
4308
- return outcome.result;
3897
+ return await routeFunction(workflowContext);
4309
3898
  },
4310
3899
  onCleanup: async (result2) => {
4311
3900
  await middlewareManager.dispatchLifecycle("runCompleted", {