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