@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/h3.js CHANGED
@@ -526,14 +526,6 @@ var WORKFLOW_CREATED_AT_HEADER = "Upstash-Workflow-CreatedAt";
526
526
  var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
527
527
  var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
528
528
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
529
- var WORKFLOW_FEATURE_SET = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
530
- var WORKFLOW_STEP_CONFIG_CALL_TYPE = "stepConfig";
531
- var WORKFLOW_STEP_CONFIG_HEADER = "Upstash-Workflow-Step-Config";
532
- var FLOW_CONTROL_KEY_HEADER = "Upstash-Flow-Control-Key";
533
- var FLOW_CONTROL_VALUE_HEADER = "Upstash-Flow-Control-Value";
534
- var RETRIES_HEADER = "Upstash-Retries";
535
- var RETRY_DELAY_HEADER = "Upstash-Retry-Delay";
536
- var WORKFLOW_STEP_CONFIG_FEATURE = "WF_StepConfig";
537
529
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
538
530
  var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
539
531
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
@@ -551,6 +543,102 @@ var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
551
543
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
552
544
  var TELEMETRY_HEADER_RUNTIME = "Upstash-Telemetry-Runtime";
553
545
 
546
+ // src/context/auto-executor.ts
547
+ var import_qstash5 = require("@upstash/qstash");
548
+
549
+ // src/qstash/headers.ts
550
+ var import_qstash4 = require("@upstash/qstash");
551
+
552
+ // src/utils.ts
553
+ var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
554
+ var NANOID_LENGTH = 21;
555
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
556
+ function validateLabel(label) {
557
+ if (label === void 0) return;
558
+ const labels = Array.isArray(label) ? label : [label];
559
+ if (labels.length === 0) {
560
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
561
+ }
562
+ for (const value of labels) {
563
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
564
+ throw new WorkflowNonRetryableError(
565
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
566
+ );
567
+ }
568
+ }
569
+ }
570
+ function serializeLabel(label) {
571
+ return Array.isArray(label) ? label.join(",") : label;
572
+ }
573
+ function validateFlowControl(flowControl) {
574
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
575
+ throw new WorkflowNonRetryableError(
576
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
577
+ );
578
+ }
579
+ }
580
+ function getRandomInt() {
581
+ return Math.floor(Math.random() * NANOID_CHARS.length);
582
+ }
583
+ function nanoid(length = NANOID_LENGTH) {
584
+ return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
585
+ }
586
+ function getWorkflowRunId(id) {
587
+ return `wfr_${id ?? nanoid()}`;
588
+ }
589
+ function decodeBase64(base64) {
590
+ const binString = atob(base64);
591
+ try {
592
+ const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
593
+ return new TextDecoder().decode(intArray);
594
+ } catch (error) {
595
+ console.warn(
596
+ `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
597
+ );
598
+ return binString;
599
+ }
600
+ }
601
+ function getUserIdFromToken(qstashClient) {
602
+ try {
603
+ const token = qstashClient.token;
604
+ const decodedToken = decodeBase64(token);
605
+ const tokenPayload = JSON.parse(decodedToken);
606
+ const userId = tokenPayload.UserID;
607
+ if (!userId) {
608
+ throw new WorkflowError("QStash token payload does not contain userId");
609
+ }
610
+ return userId;
611
+ } catch (error) {
612
+ throw new WorkflowError(
613
+ `Failed to decode QStash token while running create webhook step: ${error.message}`
614
+ );
615
+ }
616
+ }
617
+ function getQStashUrl(qstashClient) {
618
+ try {
619
+ const requester = qstashClient.http;
620
+ const baseUrl = requester.baseUrl;
621
+ if (!baseUrl) {
622
+ throw new WorkflowError("QStash client does not have a baseUrl");
623
+ }
624
+ return baseUrl;
625
+ } catch (error) {
626
+ throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
627
+ }
628
+ }
629
+ function getEventId() {
630
+ return `evt_${nanoid(15)}`;
631
+ }
632
+ function stringifyBody(body) {
633
+ if (body === void 0) {
634
+ return void 0;
635
+ }
636
+ if (typeof body === "string") {
637
+ return body;
638
+ }
639
+ return JSON.stringify(body);
640
+ }
641
+
554
642
  // node_modules/neverthrow/dist/index.es.js
555
643
  var defaultErrorConfig = {
556
644
  withStackTrace: false
@@ -966,102 +1054,6 @@ var Err = class {
966
1054
  };
967
1055
  var fromThrowable = Result.fromThrowable;
968
1056
 
969
- // src/context/auto-executor.ts
970
- var import_qstash5 = require("@upstash/qstash");
971
-
972
- // src/qstash/headers.ts
973
- var import_qstash4 = require("@upstash/qstash");
974
-
975
- // src/utils.ts
976
- var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
977
- var NANOID_LENGTH = 21;
978
- var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
979
- function validateLabel(label) {
980
- if (label === void 0) return;
981
- const labels = Array.isArray(label) ? label : [label];
982
- if (labels.length === 0) {
983
- throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
984
- }
985
- for (const value of labels) {
986
- if (!RESOURCE_NAME_PATTERN.test(value)) {
987
- throw new WorkflowNonRetryableError(
988
- `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
989
- );
990
- }
991
- }
992
- }
993
- function serializeLabel(label) {
994
- return Array.isArray(label) ? label.join(",") : label;
995
- }
996
- function validateFlowControl(flowControl) {
997
- if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
998
- throw new WorkflowNonRetryableError(
999
- `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
1000
- );
1001
- }
1002
- }
1003
- function getRandomInt() {
1004
- return Math.floor(Math.random() * NANOID_CHARS.length);
1005
- }
1006
- function nanoid(length = NANOID_LENGTH) {
1007
- return Array.from({ length }).map(() => NANOID_CHARS[getRandomInt()]).join("");
1008
- }
1009
- function getWorkflowRunId(id) {
1010
- return `wfr_${id ?? nanoid()}`;
1011
- }
1012
- function decodeBase64(base64) {
1013
- const binString = atob(base64);
1014
- try {
1015
- const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
1016
- return new TextDecoder().decode(intArray);
1017
- } catch (error) {
1018
- console.warn(
1019
- `Upstash Qstash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
1020
- );
1021
- return binString;
1022
- }
1023
- }
1024
- function getUserIdFromToken(qstashClient) {
1025
- try {
1026
- const token = qstashClient.token;
1027
- const decodedToken = decodeBase64(token);
1028
- const tokenPayload = JSON.parse(decodedToken);
1029
- const userId = tokenPayload.UserID;
1030
- if (!userId) {
1031
- throw new WorkflowError("QStash token payload does not contain userId");
1032
- }
1033
- return userId;
1034
- } catch (error) {
1035
- throw new WorkflowError(
1036
- `Failed to decode QStash token while running create webhook step: ${error.message}`
1037
- );
1038
- }
1039
- }
1040
- function getQStashUrl(qstashClient) {
1041
- try {
1042
- const requester = qstashClient.http;
1043
- const baseUrl = requester.baseUrl;
1044
- if (!baseUrl) {
1045
- throw new WorkflowError("QStash client does not have a baseUrl");
1046
- }
1047
- return baseUrl;
1048
- } catch (error) {
1049
- throw new WorkflowError(`Failed to get QStash URL from client: ${error.message}`);
1050
- }
1051
- }
1052
- function getEventId() {
1053
- return `evt_${nanoid(15)}`;
1054
- }
1055
- function stringifyBody(body) {
1056
- if (body === void 0) {
1057
- return void 0;
1058
- }
1059
- if (typeof body === "string") {
1060
- return body;
1061
- }
1062
- return JSON.stringify(body);
1063
- }
1064
-
1065
1057
  // src/types.ts
1066
1058
  var StepTypes = [
1067
1059
  "Initial",
@@ -1101,6 +1093,10 @@ var triggerFirstInvocation = async (params) => {
1101
1093
  workflowConfig: {
1102
1094
  workflowRunId: workflowContext.workflowRunId,
1103
1095
  workflowUrl: workflowContext.url,
1096
+ // the run doesn't exist yet, so the trigger time is sent when the creation time
1097
+ // is not known. serve and client.trigger set it on the context already, so a
1098
+ // retry of this request carries the same value and is deduplicated.
1099
+ workflowRunCreatedAt: workflowContext.workflowRunCreatedAt || Date.now(),
1104
1100
  failureUrl,
1105
1101
  retries,
1106
1102
  retryDelay,
@@ -1167,10 +1163,6 @@ var triggerFirstInvocation = async (params) => {
1167
1163
  return err(error_);
1168
1164
  }
1169
1165
  };
1170
- var flushPendingStep = async (workflowContext) => {
1171
- const { executor } = workflowContext;
1172
- return await executor.submitPendingStep();
1173
- };
1174
1166
  var triggerRouteFunction = async ({
1175
1167
  onCleanup,
1176
1168
  onStep,
@@ -1208,7 +1200,10 @@ var triggerWorkflowDelete = async (workflowContext, result, cancel = false, disp
1208
1200
  path: ["v2", "workflows", "runs", `${workflowContext.workflowRunId}?cancel=${cancel}`],
1209
1201
  method: "DELETE",
1210
1202
  parseResponseAsJson: false,
1211
- body: JSON.stringify(result)
1203
+ body: JSON.stringify(result),
1204
+ // with the creation time, QStash deletes the run only if it is the same run.
1205
+ // a late delete of a previous run can't delete a new run with the same id.
1206
+ headers: workflowContext.workflowRunCreatedAt ? { [WORKFLOW_CREATED_AT_HEADER]: workflowContext.workflowRunCreatedAt.toString() } : void 0
1212
1207
  });
1213
1208
  await dispatchDebug?.("onInfo", {
1214
1209
  info: `Workflow run ${workflowContext.workflowRunId} deleted from QStash successfully.`
@@ -1285,6 +1280,7 @@ ${atob(callbackMessage.body ?? "")}`
1285
1280
  const concurrentString = request.headers.get("Upstash-Workflow-Concurrent");
1286
1281
  const contentType = request.headers.get("Upstash-Workflow-ContentType");
1287
1282
  const invokeCount = request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER);
1283
+ const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
1288
1284
  if (!(workflowRunId && stepIdString && stepName && StepTypes.includes(stepType) && concurrentString && contentType)) {
1289
1285
  throw new Error(
1290
1286
  `Missing info in callback message source header: ${JSON.stringify({
@@ -1302,6 +1298,7 @@ ${atob(callbackMessage.body ?? "")}`
1302
1298
  workflowConfig: {
1303
1299
  workflowRunId,
1304
1300
  workflowUrl,
1301
+ workflowRunCreatedAt: Number(workflowRunCreatedAt ?? "0"),
1305
1302
  telemetry: telemetry2
1306
1303
  },
1307
1304
  invokeCount: Number(invokeCount)
@@ -1378,29 +1375,8 @@ If you want to disable QStash Verification, you should clear env variables QSTAS
1378
1375
  var BaseLazyStep = class _BaseLazyStep {
1379
1376
  stepName;
1380
1377
  context;
1381
- /**
1382
- * step-level settings (flow control, retries etc.) which override the
1383
- * settings the workflow run was triggered with, for this step only.
1384
- */
1385
- stepSettings;
1386
- /**
1387
- * whether this step's result can be submitted after the route function
1388
- * has moved on, instead of right away.
1389
- *
1390
- * Enabled for steps whose `getResultStep` produces the final `out` —
1391
- * which is not the same as "needs no server round trip":
1392
- * `LazyCreateWebhookStep` builds its result in `getBody` and returns
1393
- * `out: undefined` from `getResultStep`, so deferring it would hand
1394
- * `undefined` to the route function.
1395
- *
1396
- * Deferring lets the route function continue and reveal the next step,
1397
- * so that step's settings can ride on this step's submission instead
1398
- * of needing a step config request of their own.
1399
- */
1400
- supportsDeferredSubmission = false;
1401
- constructor(context, stepName, stepSettings) {
1378
+ constructor(context, stepName) {
1402
1379
  this.context = context;
1403
- this.stepSettings = stepSettings;
1404
1380
  if (!stepName) {
1405
1381
  throw new WorkflowError(
1406
1382
  "A workflow step name cannot be undefined or an empty string. Please provide a name for your workflow step."
@@ -1464,18 +1440,13 @@ var BaseLazyStep = class _BaseLazyStep {
1464
1440
  step.out = JSON.stringify(step.out);
1465
1441
  return JSON.stringify(step);
1466
1442
  }
1467
- getHeaders({
1468
- context,
1469
- telemetry: telemetry2,
1470
- invokeCount,
1471
- step,
1472
- stepSettings
1473
- }) {
1443
+ getHeaders({ context, telemetry: telemetry2, invokeCount, step }) {
1474
1444
  return getHeaders({
1475
1445
  initHeaderValue: "false",
1476
1446
  workflowConfig: {
1477
1447
  workflowRunId: context.workflowRunId,
1478
1448
  workflowUrl: context.url,
1449
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1479
1450
  useJSONContent: false,
1480
1451
  telemetry: telemetry2
1481
1452
  },
@@ -1483,8 +1454,7 @@ var BaseLazyStep = class _BaseLazyStep {
1483
1454
  stepInfo: {
1484
1455
  step,
1485
1456
  lazyStep: this
1486
- },
1487
- stepSettings
1457
+ }
1488
1458
  });
1489
1459
  }
1490
1460
  async submitStep({ context, body, headers }) {
@@ -1502,9 +1472,8 @@ var LazyFunctionStep = class extends BaseLazyStep {
1502
1472
  stepFunction;
1503
1473
  stepType = "Run";
1504
1474
  allowUndefinedOut = true;
1505
- supportsDeferredSubmission = true;
1506
- constructor(context, stepName, stepFunction, stepSettings) {
1507
- super(context, stepName, stepSettings);
1475
+ constructor(context, stepName, stepFunction) {
1476
+ super(context, stepName);
1508
1477
  this.stepFunction = stepFunction;
1509
1478
  }
1510
1479
  getPlanStep(concurrent, targetStep) {
@@ -1534,7 +1503,6 @@ var LazySleepStep = class extends BaseLazyStep {
1534
1503
  sleep;
1535
1504
  stepType = "SleepFor";
1536
1505
  allowUndefinedOut = true;
1537
- supportsDeferredSubmission = true;
1538
1506
  constructor(context, stepName, sleep) {
1539
1507
  super(context, stepName);
1540
1508
  this.sleep = sleep;
@@ -1574,7 +1542,6 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1574
1542
  sleepUntil;
1575
1543
  stepType = "SleepUntil";
1576
1544
  allowUndefinedOut = true;
1577
- supportsDeferredSubmission = true;
1578
1545
  constructor(context, stepName, sleepUntil) {
1579
1546
  super(context, stepName);
1580
1547
  this.sleepUntil = sleepUntil;
@@ -1807,6 +1774,8 @@ var LazyWaitEventStep = class extends BaseLazyStep {
1807
1774
  ) : {},
1808
1775
  // note: using WORKFLOW_ID_HEADER doesn't work, because Runid -> RunId:
1809
1776
  "Upstash-Workflow-Runid": [context.workflowRunId],
1777
+ // same for WORKFLOW_CREATED_AT_HEADER, because Createdat -> CreatedAt:
1778
+ ...context.workflowRunCreatedAt ? { "Upstash-Workflow-Createdat": [context.workflowRunCreatedAt.toString()] } : {},
1810
1779
  [WORKFLOW_INIT_HEADER]: ["false"],
1811
1780
  [WORKFLOW_URL_HEADER]: [context.url],
1812
1781
  "Upstash-Workflow-CallType": ["step"]
@@ -1909,6 +1878,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1909
1878
  workflowConfig: {
1910
1879
  workflowRunId: context.workflowRunId,
1911
1880
  workflowUrl: context.url,
1881
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1912
1882
  telemetry: telemetry2,
1913
1883
  useJSONContent: false
1914
1884
  },
@@ -1918,6 +1888,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1918
1888
  invokerHeaders[key] = value;
1919
1889
  });
1920
1890
  invokerHeaders["Upstash-Workflow-Runid"] = context.workflowRunId;
1891
+ if (context.workflowRunCreatedAt) {
1892
+ invokerHeaders["Upstash-Workflow-Createdat"] = context.workflowRunCreatedAt.toString();
1893
+ }
1921
1894
  const request = {
1922
1895
  body: stringifyBody(this.params.body),
1923
1896
  headers: Object.fromEntries(
@@ -1946,6 +1919,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1946
1919
  workflowConfig: {
1947
1920
  workflowRunId: getWorkflowRunId(workflowRunId),
1948
1921
  workflowUrl: newUrl,
1922
+ // the invoked run doesn't exist yet, so the creation time of the invoker run is sent.
1923
+ // it separates the invocations made by different runs of the invoker.
1924
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
1949
1925
  retries,
1950
1926
  retryDelay,
1951
1927
  telemetry: telemetry2,
@@ -2067,7 +2043,6 @@ var WorkflowHeaders = class {
2067
2043
  invokeCount;
2068
2044
  initHeaderValue;
2069
2045
  stepInfo;
2070
- stepSettings;
2071
2046
  headers;
2072
2047
  /**
2073
2048
  * @param params workflow header parameters
@@ -2077,20 +2052,17 @@ var WorkflowHeaders = class {
2077
2052
  workflowConfig,
2078
2053
  invokeCount,
2079
2054
  initHeaderValue,
2080
- stepInfo,
2081
- stepSettings
2055
+ stepInfo
2082
2056
  }) {
2083
2057
  this.userHeaders = userHeaders;
2084
2058
  this.workflowConfig = workflowConfig;
2085
2059
  this.invokeCount = invokeCount;
2086
2060
  this.initHeaderValue = initHeaderValue;
2087
2061
  this.stepInfo = stepInfo;
2088
- this.stepSettings = stepSettings;
2089
2062
  this.headers = {
2090
2063
  rawHeaders: {},
2091
2064
  workflowHeaders: {},
2092
- failureHeaders: {},
2093
- stepSettingsHeaders: {}
2065
+ failureHeaders: {}
2094
2066
  };
2095
2067
  }
2096
2068
  getHeaders() {
@@ -2101,7 +2073,6 @@ var WorkflowHeaders = class {
2101
2073
  this.addUserHeaders();
2102
2074
  this.addInvokeCount();
2103
2075
  this.addFailureUrl();
2104
- this.addStepSettings();
2105
2076
  const contentType = this.addContentType();
2106
2077
  return this.prefixHeaders(contentType);
2107
2078
  }
@@ -2111,10 +2082,13 @@ var WorkflowHeaders = class {
2111
2082
  [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
2112
2083
  [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
2113
2084
  [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
2114
- [WORKFLOW_FEATURE_HEADER]: WORKFLOW_FEATURE_SET,
2085
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig",
2115
2086
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
2116
2087
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {}
2117
2088
  };
2089
+ if (this.workflowConfig.workflowRunCreatedAt) {
2090
+ this.headers.rawHeaders[WORKFLOW_CREATED_AT_HEADER] = this.workflowConfig.workflowRunCreatedAt.toString();
2091
+ }
2118
2092
  if (this.stepInfo?.lazyStep.stepType !== "Call") {
2119
2093
  this.headers.rawHeaders[`Upstash-Forward-${WORKFLOW_PROTOCOL_VERSION_HEADER}`] = WORKFLOW_PROTOCOL_VERSION;
2120
2094
  }
@@ -2189,7 +2163,7 @@ var WorkflowHeaders = class {
2189
2163
  this.headers.failureHeaders["Workflow-Init"] = "false";
2190
2164
  this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
2191
2165
  this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
2192
- this.headers.failureHeaders["Feature-Set"] = WORKFLOW_FEATURE_SET;
2166
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger,WF_TriggerOnConfig";
2193
2167
  if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
2194
2168
  this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
2195
2169
  }
@@ -2197,42 +2171,6 @@ var WorkflowHeaders = class {
2197
2171
  this.headers.failureHeaders["Retry-Delay"] = this.workflowConfig.retryDelay.toString();
2198
2172
  }
2199
2173
  }
2200
- /**
2201
- * Applies the step-level settings of a step to the message.
2202
- *
2203
- * These headers configure the message itself, so that QStash uses them
2204
- * instead of the settings the run was triggered with. The delivery of
2205
- * the message is what executes the step, which is how a step's
2206
- * settings reach it.
2207
- *
2208
- * When any setting is present the feature set is extended with
2209
- * `WF_StepConfig`, which is what tells QStash to keep them. QStash
2210
- * reports that back on the delivery as `Upstash-Workflow-Step-Config`.
2211
- */
2212
- addStepSettings() {
2213
- if (!this.stepSettings) {
2214
- return;
2215
- }
2216
- const headers = {};
2217
- if (this.stepSettings.flowControl) {
2218
- const { flowControlKey, flowControlValue } = prepareFlowControl(
2219
- this.stepSettings.flowControl
2220
- );
2221
- headers[FLOW_CONTROL_KEY_HEADER] = flowControlKey;
2222
- headers[FLOW_CONTROL_VALUE_HEADER] = flowControlValue;
2223
- }
2224
- if (this.stepSettings.retries !== void 0) {
2225
- headers[RETRIES_HEADER] = this.stepSettings.retries.toString();
2226
- }
2227
- if (this.stepSettings.retryDelay) {
2228
- headers[RETRY_DELAY_HEADER] = this.stepSettings.retryDelay;
2229
- }
2230
- if (Object.keys(headers).length === 0) {
2231
- return;
2232
- }
2233
- headers[WORKFLOW_FEATURE_HEADER] = `${WORKFLOW_FEATURE_SET},${WORKFLOW_STEP_CONFIG_FEATURE}`;
2234
- this.headers.stepSettingsHeaders = headers;
2235
- }
2236
2174
  addContentType() {
2237
2175
  if (this.workflowConfig.useJSONContent) {
2238
2176
  this.headers.rawHeaders["content-type"] = "application/json";
@@ -2246,17 +2184,14 @@ var WorkflowHeaders = class {
2246
2184
  return contentType;
2247
2185
  }
2248
2186
  prefixHeaders(contentType) {
2249
- const { rawHeaders, workflowHeaders, failureHeaders, stepSettingsHeaders } = this.headers;
2187
+ const { rawHeaders, workflowHeaders, failureHeaders } = this.headers;
2250
2188
  const isCall = this.stepInfo?.lazyStep.stepType === "Call";
2251
2189
  return {
2252
2190
  headers: {
2253
2191
  ...rawHeaders,
2254
2192
  ...addPrefixToHeaders(workflowHeaders, isCall ? "Upstash-Callback-" : "Upstash-"),
2255
2193
  ...addPrefixToHeaders(failureHeaders, "Upstash-Failure-Callback-"),
2256
- ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {},
2257
- // last, so they override the run's settings above. Never
2258
- // prefixed: they configure this message, not its callback.
2259
- ...stepSettingsHeaders
2194
+ ...isCall ? addPrefixToHeaders(failureHeaders, "Upstash-Callback-Failure-Callback-") : {}
2260
2195
  },
2261
2196
  contentType
2262
2197
  };
@@ -2307,16 +2242,16 @@ var submitParallelSteps = async ({
2307
2242
  info: `Submitting ${planSteps.length} parallel steps.`
2308
2243
  });
2309
2244
  const result = await context.qstashClient.batch(
2310
- planSteps.map((planStep, index) => {
2245
+ planSteps.map((planStep) => {
2311
2246
  const { headers } = getHeaders({
2312
2247
  initHeaderValue: "false",
2313
2248
  workflowConfig: {
2314
2249
  workflowRunId: context.workflowRunId,
2315
2250
  workflowUrl: context.url,
2251
+ workflowRunCreatedAt: context.workflowRunCreatedAt,
2316
2252
  telemetry: telemetry2
2317
2253
  },
2318
- invokeCount,
2319
- stepSettings: steps[index].stepSettings
2254
+ invokeCount
2320
2255
  });
2321
2256
  return {
2322
2257
  headers,
@@ -2335,38 +2270,31 @@ var submitParallelSteps = async ({
2335
2270
  }
2336
2271
  throw new WorkflowAbort(planSteps[0].stepName, planSteps[0]);
2337
2272
  };
2338
- var executeStep = async ({
2273
+ var submitSingleStep = async ({
2274
+ context,
2339
2275
  lazyStep,
2340
2276
  stepId,
2277
+ invokeCount,
2341
2278
  concurrency,
2279
+ telemetry: telemetry2,
2280
+ dispatchDebug,
2342
2281
  dispatchLifecycle
2343
2282
  }) => {
2344
2283
  await dispatchLifecycle("beforeExecution", {
2345
2284
  stepName: lazyStep.stepName
2346
2285
  });
2286
+ let resultStep;
2347
2287
  try {
2348
- return await lazyStep.getResultStep(concurrency, stepId);
2288
+ resultStep = await lazyStep.getResultStep(concurrency, stepId);
2349
2289
  } catch (error) {
2350
2290
  attachStepNameToError(error, lazyStep.stepName);
2351
2291
  throw error;
2352
2292
  }
2353
- };
2354
- var submitStepResult = async ({
2355
- context,
2356
- lazyStep,
2357
- resultStep,
2358
- invokeCount,
2359
- concurrency,
2360
- telemetry: telemetry2,
2361
- dispatchDebug,
2362
- nextStepSettings
2363
- }) => {
2364
2293
  const { headers } = lazyStep.getHeaders({
2365
2294
  context,
2366
2295
  step: resultStep,
2367
2296
  invokeCount,
2368
- telemetry: telemetry2,
2369
- stepSettings: nextStepSettings
2297
+ telemetry: telemetry2
2370
2298
  });
2371
2299
  const body = lazyStep.getBody({
2372
2300
  context,
@@ -2391,138 +2319,6 @@ var submitStepResult = async ({
2391
2319
  }
2392
2320
  return resultStep;
2393
2321
  };
2394
- var publishStepConfigRequest = async ({
2395
- context,
2396
- lazyStep,
2397
- targetStep,
2398
- invokeCount,
2399
- telemetry: telemetry2,
2400
- dispatchDebug
2401
- }) => {
2402
- const { headers } = getHeaders({
2403
- initHeaderValue: "false",
2404
- workflowConfig: {
2405
- workflowRunId: context.workflowRunId,
2406
- workflowUrl: context.url,
2407
- telemetry: telemetry2
2408
- },
2409
- invokeCount,
2410
- stepSettings: lazyStep.stepSettings
2411
- });
2412
- await dispatchDebug("onInfo", {
2413
- info: `Step "${lazyStep.stepName}" (${targetStep}) has step-level settings which the current delivery does not carry. Requesting a delivery which does.`
2414
- });
2415
- const result = await context.qstashClient.publishJSON({
2416
- headers: {
2417
- ...headers,
2418
- "Upstash-Workflow-CallType": WORKFLOW_STEP_CONFIG_CALL_TYPE
2419
- },
2420
- method: "POST",
2421
- body: { targetStep, invokeCount },
2422
- url: context.url,
2423
- contentBasedDeduplication: true
2424
- });
2425
- if (result?.deduplicated) {
2426
- await dispatchDebug("onWarning", {
2427
- 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.`
2428
- });
2429
- } else if (result?.messageId) {
2430
- await dispatchDebug("onInfo", {
2431
- info: `Requested a delivery under the settings of step "${lazyStep.stepName}" with messageId: ${result.messageId}.`
2432
- });
2433
- }
2434
- };
2435
-
2436
- // src/qstash/step-config.ts
2437
- var DEFAULT_PARALLELISM = 0;
2438
- var DEFAULT_RATE = 0;
2439
- var DEFAULT_PERIOD_SECONDS = 1;
2440
- var SECONDS_PER_UNIT = {
2441
- s: 1,
2442
- m: 60,
2443
- h: 60 * 60,
2444
- d: 24 * 60 * 60
2445
- };
2446
- var durationToSeconds = (duration) => {
2447
- if (typeof duration === "number") {
2448
- return Number.isFinite(duration) ? duration : void 0;
2449
- }
2450
- const match = /^(\d+)([smhd])$/.exec(duration.trim());
2451
- if (match) {
2452
- return Number(match[1]) * SECONDS_PER_UNIT[match[2]];
2453
- }
2454
- const seconds = Number(duration.trim());
2455
- return Number.isFinite(seconds) ? seconds : void 0;
2456
- };
2457
- var normalizeFlowControl = (flowControl) => {
2458
- const period = flowControl.period === void 0 ? void 0 : durationToSeconds(flowControl.period);
2459
- return {
2460
- key: flowControl.key,
2461
- parallelism: flowControl.parallelism ?? DEFAULT_PARALLELISM,
2462
- rate: flowControl.rate ?? flowControl.ratePerSecond ?? DEFAULT_RATE,
2463
- period: period ?? DEFAULT_PERIOD_SECONDS
2464
- };
2465
- };
2466
- var parseFlowControlHeaders = (key, value) => {
2467
- if (!key) {
2468
- return void 0;
2469
- }
2470
- const flowControl = {
2471
- key,
2472
- parallelism: DEFAULT_PARALLELISM,
2473
- rate: DEFAULT_RATE,
2474
- period: DEFAULT_PERIOD_SECONDS
2475
- };
2476
- for (const entry of (value ?? "").split(",")) {
2477
- const [name, rawValue] = entry.split("=").map((part) => part.trim());
2478
- if (!name || rawValue === void 0) {
2479
- continue;
2480
- }
2481
- switch (name) {
2482
- case "parallelism": {
2483
- flowControl.parallelism = Number(rawValue);
2484
- break;
2485
- }
2486
- case "rate": {
2487
- flowControl.rate = Number(rawValue);
2488
- break;
2489
- }
2490
- case "period": {
2491
- flowControl.period = durationToSeconds(rawValue) ?? DEFAULT_PERIOD_SECONDS;
2492
- break;
2493
- }
2494
- }
2495
- }
2496
- return flowControl;
2497
- };
2498
- var getEffectiveConfig = (headers) => {
2499
- const retriesHeader = headers.get(RETRIES_HEADER);
2500
- return {
2501
- flowControl: parseFlowControlHeaders(
2502
- headers.get(FLOW_CONTROL_KEY_HEADER),
2503
- headers.get(FLOW_CONTROL_VALUE_HEADER)
2504
- ),
2505
- retries: retriesHeader === null ? void 0 : Number(retriesHeader),
2506
- retryDelay: headers.get(RETRY_DELAY_HEADER) ?? void 0,
2507
- hasStepConfig: headers.get(WORKFLOW_STEP_CONFIG_HEADER) === "true"
2508
- };
2509
- };
2510
- var describeStepSettingsMismatch = (stepSettings, effectiveConfig) => {
2511
- if (stepSettings.flowControl) {
2512
- const wanted = normalizeFlowControl(stepSettings.flowControl);
2513
- const applied = effectiveConfig.flowControl;
2514
- if (!applied || applied.key !== wanted.key || applied.parallelism !== wanted.parallelism || applied.rate !== wanted.rate || applied.period !== wanted.period) {
2515
- return `flow control: expected ${JSON.stringify(wanted)}, delivery has ${JSON.stringify(applied)}`;
2516
- }
2517
- }
2518
- if (stepSettings.retries !== void 0 && effectiveConfig.retries !== void 0 && stepSettings.retries !== effectiveConfig.retries) {
2519
- return `retries: expected ${stepSettings.retries}, delivery has ${effectiveConfig.retries}`;
2520
- }
2521
- if (stepSettings.retryDelay !== void 0 && stepSettings.retryDelay !== effectiveConfig.retryDelay) {
2522
- return `retry delay: expected '${stepSettings.retryDelay}', delivery has '${effectiveConfig.retryDelay ?? ""}'`;
2523
- }
2524
- return void 0;
2525
- };
2526
2322
 
2527
2323
  // src/context/auto-executor.ts
2528
2324
  var AutoExecutor = class _AutoExecutor {
@@ -2539,25 +2335,6 @@ var AutoExecutor = class _AutoExecutor {
2539
2335
  stepCount = 0;
2540
2336
  planStepCount = 0;
2541
2337
  executingStep = false;
2542
- /**
2543
- * an executed step whose result hasn't been submitted to QStash yet.
2544
- *
2545
- * Set when a step which can produce its result in-process executes. The
2546
- * submission waits so that the route function can continue and reveal
2547
- * what comes next: if that is a single step with step-level settings,
2548
- * the settings ride on this submission and no step config request is
2549
- * needed, since the delivery of the submission is what executes it.
2550
- *
2551
- * Flushed when the next step is reached (see `addStep`) or when the
2552
- * route function ends (see `flushPendingStep` in `serve`).
2553
- */
2554
- pendingStep;
2555
- /**
2556
- * configuration QStash applied to the delivery being handled. A step
2557
- * with step-level settings is settled by comparing its settings against
2558
- * this.
2559
- */
2560
- effectiveConfig;
2561
2338
  /**
2562
2339
  * @param context workflow context
2563
2340
  * @param steps list of steps
@@ -2565,17 +2342,14 @@ var AutoExecutor = class _AutoExecutor {
2565
2342
  * @param dispatchLifecycle lifecycle event dispatcher
2566
2343
  * @param telemetry optional telemetry information
2567
2344
  * @param invokeCount optional invoke count
2568
- * @param effectiveConfig configuration QStash applied to the delivery
2569
- * being handled
2570
2345
  */
2571
- constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry2, invokeCount, effectiveConfig) {
2346
+ constructor(context, steps, dispatchDebug, dispatchLifecycle, telemetry2, invokeCount) {
2572
2347
  this.context = context;
2573
2348
  this.steps = steps;
2574
2349
  this.dispatchDebug = dispatchDebug;
2575
2350
  this.dispatchLifecycle = dispatchLifecycle;
2576
2351
  this.telemetry = telemetry2;
2577
2352
  this.invokeCount = invokeCount ?? 0;
2578
- this.effectiveConfig = effectiveConfig ?? { hasStepConfig: false };
2579
2353
  this.nonPlanStepCount = this.steps.filter((step) => !step.targetStep).length;
2580
2354
  }
2581
2355
  /**
@@ -2610,15 +2384,6 @@ var AutoExecutor = class _AutoExecutor {
2610
2384
  lazyStepList.push(stepInfo);
2611
2385
  const index = this.indexInCurrentList++;
2612
2386
  const requestComplete = this.deferExecution().then(async () => {
2613
- const submitted = await this.submitPendingStep(
2614
- lazyStepList.length === 1 ? lazyStepList[0].stepSettings : void 0
2615
- );
2616
- if (submitted.isErr()) {
2617
- throw submitted.error;
2618
- }
2619
- if (submitted.value.result === "submitted-step") {
2620
- throw submitted.value.abort;
2621
- }
2622
2387
  if (!this.promises.has(lazyStepList)) {
2623
2388
  const promise2 = this.getExecutionPromise(lazyStepList);
2624
2389
  this.promises.set(lazyStepList, promise2);
@@ -2672,100 +2437,18 @@ var AutoExecutor = class _AutoExecutor {
2672
2437
  }
2673
2438
  return parsedOut;
2674
2439
  }
2675
- const mismatch = lazyStep.stepSettings ? describeStepSettingsMismatch(lazyStep.stepSettings, this.effectiveConfig) : void 0;
2676
- if (mismatch) {
2677
- if (!this.effectiveConfig.hasStepConfig) {
2678
- await publishStepConfigRequest({
2679
- context: this.context,
2680
- lazyStep,
2681
- targetStep: this.stepCount,
2682
- invokeCount: this.invokeCount,
2683
- telemetry: this.telemetry,
2684
- dispatchDebug: this.dispatchDebug
2685
- });
2686
- throw new WorkflowAbort(lazyStep.stepName);
2687
- } else {
2688
- await this.dispatchDebug("onWarning", {
2689
- 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.`
2690
- });
2691
- }
2692
- }
2693
- const resultStep = await executeStep({
2694
- lazyStep,
2695
- stepId: this.stepCount,
2696
- concurrency: NO_CONCURRENCY,
2697
- dispatchLifecycle: this.dispatchLifecycle
2698
- });
2699
- if (lazyStep.supportsDeferredSubmission) {
2700
- this.pendingStep = { status: "held", lazyStep, resultStep };
2701
- return lazyStep.parseOut({
2702
- ...resultStep,
2703
- out: resultStep.out === void 0 ? void 0 : JSON.stringify(resultStep.out)
2704
- });
2705
- }
2706
- await submitStepResult({
2440
+ const resultStep = await submitSingleStep({
2707
2441
  context: this.context,
2708
2442
  lazyStep,
2709
- resultStep,
2443
+ stepId: this.stepCount,
2710
2444
  invokeCount: this.invokeCount,
2711
- concurrency: NO_CONCURRENCY,
2445
+ concurrency: 1,
2712
2446
  telemetry: this.telemetry,
2713
- dispatchDebug: this.dispatchDebug
2447
+ dispatchDebug: this.dispatchDebug,
2448
+ dispatchLifecycle: this.dispatchLifecycle
2714
2449
  });
2715
2450
  throw new WorkflowAbort(lazyStep.stepName, resultStep);
2716
2451
  }
2717
- /**
2718
- * Submits the result of the step being held, if there is one, and
2719
- * returns the abort the caller has to throw to end the invocation.
2720
- *
2721
- * Returns undefined when no step is being held, which is the caller's
2722
- * signal that there is nothing to end. Throws instead of returning
2723
- * when the submission itself fails, so that error reaches the caller
2724
- * rather than an abort claiming the step was submitted.
2725
- *
2726
- * Callers which arrive while a submission is already under way (the
2727
- * steps of a parallel group, added together) wait for that one and get
2728
- * the same abort, rather than submitting a second time.
2729
- *
2730
- * The next step's settings are attached whenever it has any, without
2731
- * checking them against the current delivery: the executor only knows
2732
- * the configuration of the delivery in hand, which inside a
2733
- * delivery is the *previous* step's, so such a check would be wrong
2734
- * exactly when two steps with settings follow each other.
2735
- *
2736
- * @param nextStepSettings step-level settings of the next step
2737
- * @returns `submitted-step` with the abort which ends this invocation,
2738
- * or `no-pending-step` when nothing was held and there is nothing to
2739
- * end
2740
- */
2741
- async submitPendingStep(nextStepSettings) {
2742
- if (!this.pendingStep) {
2743
- return ok({ result: "no-pending-step" });
2744
- }
2745
- try {
2746
- if (this.pendingStep.status === "submitting") {
2747
- return ok({ result: "submitted-step", abort: await this.pendingStep.submitted });
2748
- }
2749
- const { lazyStep, resultStep } = this.pendingStep;
2750
- const submitted = (async () => {
2751
- await submitStepResult({
2752
- context: this.context,
2753
- lazyStep,
2754
- resultStep,
2755
- invokeCount: this.invokeCount,
2756
- concurrency: NO_CONCURRENCY,
2757
- telemetry: this.telemetry,
2758
- dispatchDebug: this.dispatchDebug,
2759
- nextStepSettings
2760
- });
2761
- return new WorkflowAbort(lazyStep.stepName, resultStep);
2762
- })();
2763
- this.pendingStep = { status: "submitting", submitted };
2764
- return ok({ result: "submitted-step", abort: await submitted });
2765
- } catch (error) {
2766
- return err(error);
2767
- }
2768
- }
2769
2452
  /**
2770
2453
  * Runs steps in parallel.
2771
2454
  *
@@ -2814,20 +2497,15 @@ var AutoExecutor = class _AutoExecutor {
2814
2497
  validateStep(parallelSteps[stepIndex], planStep);
2815
2498
  try {
2816
2499
  const parallelStep = parallelSteps[stepIndex];
2817
- const resultStep = await executeStep({
2818
- lazyStep: parallelStep,
2819
- stepId: planStep.targetStep,
2820
- concurrency: parallelSteps.length,
2821
- dispatchLifecycle: this.dispatchLifecycle
2822
- });
2823
- await submitStepResult({
2500
+ const resultStep = await submitSingleStep({
2824
2501
  context: this.context,
2825
2502
  lazyStep: parallelStep,
2826
- resultStep,
2503
+ stepId: planStep.targetStep,
2827
2504
  invokeCount: this.invokeCount,
2828
2505
  concurrency: parallelSteps.length,
2829
2506
  telemetry: this.telemetry,
2830
- dispatchDebug: this.dispatchDebug
2507
+ dispatchDebug: this.dispatchDebug,
2508
+ dispatchLifecycle: this.dispatchLifecycle
2831
2509
  });
2832
2510
  throw new WorkflowAbort(parallelStep.stepName, resultStep);
2833
2511
  } catch (error) {
@@ -3443,46 +3121,6 @@ var WorkflowContext = class {
3443
3121
  * `1` on the first retry, `2` on the second, and so on.
3444
3122
  */
3445
3123
  retried;
3446
- /**
3447
- * Configuration QStash applied to the request being handled.
3448
- *
3449
- * This is the configuration of *this delivery*, not of the run: it is
3450
- * the configuration the run was triggered with, except inside the
3451
- * delivery which executes a step that has step-level settings, where
3452
- * it is that step's settings. The fields below expose it; the executor
3453
- * gets it directly rather than reaching through the context.
3454
- */
3455
- effectiveConfig;
3456
- /**
3457
- * Flow control QStash applied to the request being handled, if any.
3458
- *
3459
- * This is the flow control of the request in hand, which is the one the
3460
- * run was triggered with except inside a step carrying its own.
3461
- */
3462
- get flowControl() {
3463
- return this.effectiveConfig.flowControl;
3464
- }
3465
- /**
3466
- * Retry limit QStash applied to the request being handled, if it
3467
- * reported one.
3468
- *
3469
- * Not to be confused with {@link retried}, which is how many retries
3470
- * have already happened.
3471
- *
3472
- * @see {@link flowControl} for what "the request being handled" means
3473
- */
3474
- get retries() {
3475
- return this.effectiveConfig.retries;
3476
- }
3477
- /**
3478
- * Retry delay expression QStash applied to the request being handled,
3479
- * if any.
3480
- *
3481
- * @see {@link flowControl} for what "the request being handled" means
3482
- */
3483
- get retryDelay() {
3484
- return this.effectiveConfig.retryDelay;
3485
- }
3486
3124
  constructor({
3487
3125
  qstashClient,
3488
3126
  workflowRunId,
@@ -3496,8 +3134,7 @@ var WorkflowContext = class {
3496
3134
  invokeCount,
3497
3135
  label,
3498
3136
  retried,
3499
- middlewareManager,
3500
- effectiveConfig
3137
+ middlewareManager
3501
3138
  }) {
3502
3139
  this.qstashClient = qstashClient;
3503
3140
  this.workflowRunId = workflowRunId;
@@ -3509,7 +3146,6 @@ var WorkflowContext = class {
3509
3146
  this.env = env ?? {};
3510
3147
  this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
3511
3148
  this.retried = retried ?? 0;
3512
- this.effectiveConfig = effectiveConfig ?? { hasStepConfig: false };
3513
3149
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
3514
3150
  middlewareManagerInstance.assignContext(this);
3515
3151
  this.executor = new AutoExecutor(
@@ -3518,8 +3154,7 @@ var WorkflowContext = class {
3518
3154
  middlewareManagerInstance.dispatchDebug.bind(middlewareManagerInstance),
3519
3155
  middlewareManagerInstance.dispatchLifecycle.bind(middlewareManagerInstance),
3520
3156
  telemetry2,
3521
- invokeCount,
3522
- this.effectiveConfig
3157
+ invokeCount
3523
3158
  );
3524
3159
  }
3525
3160
  /**
@@ -3545,35 +3180,13 @@ var WorkflowContext = class {
3545
3180
  * ])
3546
3181
  * ```
3547
3182
  *
3548
- * Step-level settings can be passed as a third argument, overriding
3549
- * the settings the workflow run was triggered with for this step only:
3550
- *
3551
- * ```typescript
3552
- * const result = await context.run(
3553
- * "step 1",
3554
- * () => {
3555
- * return "result"
3556
- * },
3557
- * {
3558
- * flowControl: { key: "custom-key", parallelism: 3 },
3559
- * retries: 5,
3560
- * }
3561
- * )
3562
- * ```
3563
- *
3564
3183
  * @param stepName name of the step
3565
3184
  * @param stepFunction step function to be executed
3566
- * @param stepSettings step-level settings for this step
3567
3185
  * @returns result of the step function
3568
3186
  */
3569
- async run(stepName, stepFunction, stepSettings) {
3570
- if (stepSettings) {
3571
- validateFlowControl(stepSettings.flowControl);
3572
- }
3187
+ async run(stepName, stepFunction) {
3573
3188
  const wrappedStepFunction = (() => this.executor.wrapStep(stepName, stepFunction));
3574
- return await this.addStep(
3575
- new LazyFunctionStep(this, stepName, wrappedStepFunction, stepSettings)
3576
- );
3189
+ return await this.addStep(new LazyFunctionStep(this, stepName, wrappedStepFunction));
3577
3190
  }
3578
3191
  /**
3579
3192
  * Stops the execution for the duration provided.
@@ -3796,7 +3409,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3796
3409
  *
3797
3410
  * @param routeFunction
3798
3411
  */
3799
- static async tryAuthentication(routeFunction, context, effectiveConfig) {
3412
+ static async tryAuthentication(routeFunction, context) {
3800
3413
  const disabledContext = new _DisabledWorkflowContext({
3801
3414
  qstashClient: new import_qstash10.Client({
3802
3415
  baseUrl: "disabled-client",
@@ -3811,10 +3424,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3811
3424
  initialPayload: context.requestPayload,
3812
3425
  env: context.env,
3813
3426
  label: context.labels,
3814
- retried: context.retried,
3815
- // the route function runs for real here until it reaches a step, so
3816
- // it observes the same configuration as it will on the real context
3817
- effectiveConfig
3427
+ retried: context.retried
3818
3428
  });
3819
3429
  try {
3820
3430
  await routeFunction(disabledContext);
@@ -4031,7 +3641,6 @@ var handleFailure = async ({
4031
3641
  }
4032
3642
  const userHeaders = recreateUserHeaders(request.headers);
4033
3643
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
4034
- const effectiveConfig = getEffectiveConfig(request.headers);
4035
3644
  const workflowContext = new WorkflowContext({
4036
3645
  qstashClient,
4037
3646
  workflowRunId,
@@ -4045,13 +3654,11 @@ var handleFailure = async ({
4045
3654
  label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
4046
3655
  retried,
4047
3656
  workflowRunCreatedAt: workflowCreatedAt,
4048
- middlewareManager: void 0,
4049
- effectiveConfig
3657
+ middlewareManager: void 0
4050
3658
  });
4051
3659
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
4052
3660
  routeFunction,
4053
- workflowContext,
4054
- effectiveConfig
3661
+ workflowContext
4055
3662
  );
4056
3663
  if (authCheck.isErr()) {
4057
3664
  await dispatchDebug?.("onError", {
@@ -4540,28 +4147,26 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
4540
4147
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
4541
4148
  const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
4542
4149
  const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
4543
- const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
4544
- const effectiveConfig = getEffectiveConfig(request.headers);
4150
+ const workflowRunCreatedAtHeader = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
4151
+ const workflowRunCreatedAt = workflowRunCreatedAtHeader ? Number(workflowRunCreatedAtHeader) : isFirstInvocation ? Date.now() : 0;
4545
4152
  const workflowContext = new WorkflowContext({
4546
4153
  qstashClient: regionalClient,
4547
4154
  workflowRunId,
4548
4155
  initialPayload: isThirdPartyCallResult(request) ? JSON.parse(rawInitialPayload) : initialPayloadParser(rawInitialPayload),
4549
4156
  headers: recreateUserHeaders(request.headers),
4550
4157
  steps,
4551
- effectiveConfig,
4552
4158
  url: workflowUrl,
4553
4159
  env,
4554
4160
  telemetry: telemetry2,
4555
4161
  invokeCount,
4556
4162
  label,
4557
4163
  retried,
4558
- workflowRunCreatedAt: Number(workflowRunCreatedAt),
4164
+ workflowRunCreatedAt,
4559
4165
  middlewareManager
4560
4166
  });
4561
4167
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
4562
4168
  routeFunction,
4563
- workflowContext,
4564
- effectiveConfig
4169
+ workflowContext
4565
4170
  );
4566
4171
  if (authCheck.isErr()) {
4567
4172
  throw authCheck.error;
@@ -4598,23 +4203,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
4598
4203
  if (steps.length === 1) {
4599
4204
  await middlewareManager.dispatchLifecycle("runStarted", {});
4600
4205
  }
4601
- let outcome;
4602
- try {
4603
- outcome = { ran: true, result: await routeFunction(workflowContext) };
4604
- } catch (error) {
4605
- outcome = { ran: false, error };
4606
- }
4607
- const submitted = await flushPendingStep(workflowContext);
4608
- if (submitted.isErr()) {
4609
- throw submitted.error;
4610
- }
4611
- if (submitted.value.result === "submitted-step") {
4612
- throw submitted.value.abort;
4613
- }
4614
- if (!outcome.ran) {
4615
- throw outcome.error;
4616
- }
4617
- return outcome.result;
4206
+ return await routeFunction(workflowContext);
4618
4207
  },
4619
4208
  onCleanup: async (result2) => {
4620
4209
  await middlewareManager.dispatchLifecycle("runCompleted", {