@upstash/workflow 0.2.16 → 0.2.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cloudflare.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.mjs';
2
- import { s as serveManyBase } from './serve-many-AFwJPR3S.mjs';
1
+ import { R as RouteFunction, n as PublicServeOptions, x as InvokableWorkflow } from './types-B7_5AkKQ.mjs';
2
+ import { s as serveManyBase } from './serve-many-CEUYWQvV.mjs';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
  import 'ai';
package/cloudflare.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.js';
2
- import { s as serveManyBase } from './serve-many-AaKSQyi7.js';
1
+ import { R as RouteFunction, n as PublicServeOptions, x as InvokableWorkflow } from './types-B7_5AkKQ.js';
2
+ import { s as serveManyBase } from './serve-many-BObe3pdI.js';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
  import 'ai';
package/cloudflare.js CHANGED
@@ -33,12 +33,13 @@ var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
33
33
  var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
34
34
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
35
35
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
36
+ var WORKFLOW_LABEL_HEADER = "Upstash-Label";
36
37
  var WORKFLOW_PROTOCOL_VERSION = "1";
37
38
  var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
38
39
  var DEFAULT_CONTENT_TYPE = "application/json";
39
40
  var NO_CONCURRENCY = 1;
40
41
  var DEFAULT_RETRIES = 3;
41
- var VERSION = "v0.2.15";
42
+ var VERSION = "v0.2.18";
42
43
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
43
44
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
44
45
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -621,6 +622,7 @@ var triggerFirstInvocation = async (params) => {
621
622
  workflowUrl: workflowContext.url,
622
623
  failureUrl: workflowContext.failureUrl,
623
624
  retries: workflowContext.retries,
625
+ retryDelay: workflowContext.retryDelay,
624
626
  telemetry: telemetry2,
625
627
  flowControl: workflowContext.flowControl,
626
628
  useJSONContent: useJSONContent ?? false
@@ -634,6 +636,9 @@ var triggerFirstInvocation = async (params) => {
634
636
  if (useJSONContent) {
635
637
  headers["content-type"] = "application/json";
636
638
  }
639
+ if (workflowContext.label) {
640
+ headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
641
+ }
637
642
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
638
643
  return {
639
644
  headers,
@@ -734,10 +739,11 @@ var recreateUserHeaders = (headers) => {
734
739
  const pairs = headers.entries();
735
740
  for (const [header, value] of pairs) {
736
741
  const headerLowerCase = header.toLowerCase();
737
- if (!headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
742
+ const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
738
743
  !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
739
744
  headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
740
- headerLowerCase !== "render-proxy-ttl") {
745
+ headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
746
+ if (isUserHeader) {
741
747
  filteredHeaders.append(header, value);
742
748
  }
743
749
  }
@@ -750,6 +756,7 @@ var handleThirdPartyCallResult = async ({
750
756
  workflowUrl,
751
757
  failureUrl,
752
758
  retries,
759
+ retryDelay,
753
760
  telemetry: telemetry2,
754
761
  flowControl,
755
762
  debug
@@ -820,6 +827,7 @@ ${atob(callbackMessage.body ?? "")}`
820
827
  workflowUrl,
821
828
  failureUrl,
822
829
  retries,
830
+ retryDelay,
823
831
  telemetry: telemetry2,
824
832
  flowControl
825
833
  },
@@ -970,7 +978,8 @@ var BaseLazyStep = class _BaseLazyStep {
970
978
  workflowRunId: context.workflowRunId,
971
979
  workflowUrl: context.url,
972
980
  failureUrl: context.failureUrl,
973
- retries: context.retries,
981
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
982
+ retryDelay: context.retryDelay,
974
983
  useJSONContent: false,
975
984
  telemetry: telemetry2,
976
985
  flowControl: context.flowControl
@@ -989,6 +998,9 @@ var BaseLazyStep = class _BaseLazyStep {
989
998
  body,
990
999
  headers,
991
1000
  method: "POST",
1001
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1002
+ retryDelay: context.retryDelay,
1003
+ flowControl: context.flowControl,
992
1004
  url: context.url
993
1005
  }
994
1006
  ]);
@@ -1059,6 +1071,9 @@ var LazySleepStep = class extends BaseLazyStep {
1059
1071
  headers,
1060
1072
  method: "POST",
1061
1073
  url: context.url,
1074
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1075
+ retryDelay: context.retryDelay,
1076
+ flowControl: context.flowControl,
1062
1077
  delay: isParallel ? void 0 : this.sleep
1063
1078
  }
1064
1079
  ]);
@@ -1101,6 +1116,9 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1101
1116
  headers,
1102
1117
  method: "POST",
1103
1118
  url: context.url,
1119
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1120
+ retryDelay: context.retryDelay,
1121
+ flowControl: context.flowControl,
1104
1122
  notBefore: isParallel ? void 0 : this.sleepUntil
1105
1123
  }
1106
1124
  ]);
@@ -1112,17 +1130,19 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1112
1130
  body;
1113
1131
  headers;
1114
1132
  retries;
1133
+ retryDelay;
1115
1134
  timeout;
1116
1135
  flowControl;
1117
1136
  stepType = "Call";
1118
1137
  allowUndefinedOut = false;
1119
- constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
1138
+ constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl) {
1120
1139
  super(stepName);
1121
1140
  this.url = url;
1122
1141
  this.method = method;
1123
1142
  this.body = body;
1124
1143
  this.headers = headers;
1125
1144
  this.retries = retries;
1145
+ this.retryDelay = retryDelay;
1126
1146
  this.timeout = timeout;
1127
1147
  this.flowControl = flowControl;
1128
1148
  }
@@ -1197,6 +1217,9 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1197
1217
  getHeaders({ context, telemetry: telemetry2, invokeCount, step }) {
1198
1218
  const { headers, contentType } = super.getHeaders({ context, telemetry: telemetry2, invokeCount, step });
1199
1219
  headers["Upstash-Retries"] = this.retries.toString();
1220
+ if (this.retryDelay) {
1221
+ headers["Upstash-Retry-Delay"] = this.retryDelay;
1222
+ }
1200
1223
  headers[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
1201
1224
  if (this.flowControl) {
1202
1225
  const { flowControlKey, flowControlValue } = prepareFlowControl(this.flowControl);
@@ -1218,7 +1241,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1218
1241
  "Upstash-Callback-Workflow-CallType": "fromCallback",
1219
1242
  "Upstash-Callback-Workflow-Init": "false",
1220
1243
  "Upstash-Callback-Workflow-Url": context.url,
1221
- "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
1244
+ "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger",
1222
1245
  "Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
1223
1246
  "Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
1224
1247
  "Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
@@ -1236,7 +1259,10 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1236
1259
  headers,
1237
1260
  body: JSON.stringify(this.body),
1238
1261
  method: this.method,
1239
- url: this.url
1262
+ url: this.url,
1263
+ retries: DEFAULT_RETRIES === this.retries ? void 0 : this.retries,
1264
+ retryDelay: this.retryDelay,
1265
+ flowControl: this.flowControl
1240
1266
  }
1241
1267
  ]);
1242
1268
  }
@@ -1365,6 +1391,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1365
1391
  headers = {},
1366
1392
  workflowRunId,
1367
1393
  retries,
1394
+ retryDelay,
1368
1395
  flowControl
1369
1396
  }) {
1370
1397
  super(stepName);
@@ -1374,6 +1401,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1374
1401
  headers,
1375
1402
  workflowRunId: getWorkflowRunId(workflowRunId),
1376
1403
  retries,
1404
+ retryDelay,
1377
1405
  flowControl
1378
1406
  };
1379
1407
  const { workflowId } = workflow;
@@ -1418,6 +1446,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1418
1446
  workflowUrl: context.url,
1419
1447
  failureUrl: context.failureUrl,
1420
1448
  retries: context.retries,
1449
+ retryDelay: context.retryDelay,
1421
1450
  telemetry: telemetry2,
1422
1451
  flowControl: context.flowControl,
1423
1452
  useJSONContent: false
@@ -1443,11 +1472,13 @@ var LazyInvokeStep = class extends BaseLazyStep {
1443
1472
  headers = {},
1444
1473
  workflowRunId = getWorkflowRunId(),
1445
1474
  retries,
1475
+ retryDelay,
1446
1476
  flowControl
1447
1477
  } = this.params;
1448
1478
  const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
1449
1479
  const {
1450
1480
  retries: workflowRetries,
1481
+ retryDelay: workflowRetryDelay,
1451
1482
  failureFunction,
1452
1483
  failureUrl,
1453
1484
  useJSONContent,
@@ -1459,6 +1490,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1459
1490
  workflowRunId,
1460
1491
  workflowUrl: newUrl,
1461
1492
  retries: retries ?? workflowRetries,
1493
+ retryDelay: retryDelay ?? workflowRetryDelay,
1462
1494
  telemetry: telemetry2,
1463
1495
  failureUrl: failureFunction ? newUrl : failureUrl,
1464
1496
  flowControl: flowControl ?? workflowFlowControl,
@@ -1525,6 +1557,7 @@ var WorkflowHeaders = class {
1525
1557
  getHeaders() {
1526
1558
  this.addBaseHeaders();
1527
1559
  this.addRetries();
1560
+ this.addRetryDelay();
1528
1561
  this.addFlowControl();
1529
1562
  this.addUserHeaders();
1530
1563
  this.addInvokeCount();
@@ -1538,7 +1571,7 @@ var WorkflowHeaders = class {
1538
1571
  [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
1539
1572
  [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
1540
1573
  [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
1541
- [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
1574
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger",
1542
1575
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1543
1576
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {},
1544
1577
  ...this.workflowConfig.telemetry && this.stepInfo?.lazyStep instanceof LazyCallStep && this.stepInfo.lazyStep.headers[AGENT_NAME_HEADER] ? { [TELEMETRY_HEADER_AGENT]: "true" } : {}
@@ -1570,6 +1603,16 @@ var WorkflowHeaders = class {
1570
1603
  this.headers.failureHeaders["Retries"] = retries;
1571
1604
  }
1572
1605
  }
1606
+ addRetryDelay() {
1607
+ if (this.workflowConfig.retryDelay === void 0 || this.workflowConfig.retryDelay === "") {
1608
+ return;
1609
+ }
1610
+ const retryDelay = this.workflowConfig.retryDelay.toString();
1611
+ this.headers.workflowHeaders["Retry-Delay"] = retryDelay;
1612
+ if (this.workflowConfig.failureUrl) {
1613
+ this.headers.failureHeaders["Retry-Delay"] = retryDelay;
1614
+ }
1615
+ }
1573
1616
  addFlowControl() {
1574
1617
  if (!this.workflowConfig.flowControl) {
1575
1618
  return;
@@ -1604,10 +1647,13 @@ var WorkflowHeaders = class {
1604
1647
  this.headers.failureHeaders["Workflow-Init"] = "false";
1605
1648
  this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
1606
1649
  this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
1607
- this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody";
1650
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger";
1608
1651
  if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
1609
1652
  this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
1610
1653
  }
1654
+ if (this.workflowConfig.retryDelay !== void 0 && this.workflowConfig.retryDelay !== "") {
1655
+ this.headers.failureHeaders["Retry-Delay"] = this.workflowConfig.retryDelay.toString();
1656
+ }
1611
1657
  }
1612
1658
  addContentType() {
1613
1659
  if (this.workflowConfig.useJSONContent) {
@@ -1689,6 +1735,7 @@ var submitParallelSteps = async ({
1689
1735
  workflowUrl: context.url,
1690
1736
  failureUrl: context.failureUrl,
1691
1737
  retries: context.retries,
1738
+ retryDelay: context.retryDelay,
1692
1739
  flowControl: context.flowControl,
1693
1740
  telemetry: telemetry2
1694
1741
  },
@@ -2109,7 +2156,7 @@ var BaseWorkflowApi = class {
2109
2156
  */
2110
2157
  async callApi(stepName, settings) {
2111
2158
  const { url, appendHeaders, method } = getProviderInfo(settings.api);
2112
- const { method: userMethod, body, headers = {}, retries = 0, timeout } = settings;
2159
+ const { method: userMethod, body, headers = {}, retries = 0, retryDelay, timeout } = settings;
2113
2160
  return await this.context.call(stepName, {
2114
2161
  url,
2115
2162
  method: userMethod ?? method,
@@ -2119,6 +2166,7 @@ var BaseWorkflowApi = class {
2119
2166
  ...headers
2120
2167
  },
2121
2168
  retries,
2169
+ retryDelay,
2122
2170
  timeout
2123
2171
  });
2124
2172
  }
@@ -2208,6 +2256,7 @@ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
2208
2256
  body,
2209
2257
  timeout: agentCallParams?.timeout,
2210
2258
  retries: agentCallParams?.retries,
2259
+ retryDelay: agentCallParams?.retryDelay,
2211
2260
  flowControl: agentCallParams?.flowControl
2212
2261
  });
2213
2262
  const responseHeaders = new Headers(
@@ -2536,7 +2585,10 @@ var serveManyBase = ({
2536
2585
  return new Response(
2537
2586
  `Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
2538
2587
  {
2539
- status: 404
2588
+ status: 404,
2589
+ headers: {
2590
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
2591
+ }
2540
2592
  }
2541
2593
  );
2542
2594
  }
@@ -2545,7 +2597,10 @@ var serveManyBase = ({
2545
2597
  return new Response(
2546
2598
  `No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
2547
2599
  {
2548
- status: 404
2600
+ status: 404,
2601
+ headers: {
2602
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
2603
+ }
2549
2604
  }
2550
2605
  );
2551
2606
  }
@@ -2682,11 +2737,58 @@ var WorkflowContext = class {
2682
2737
  * Number of retries
2683
2738
  */
2684
2739
  retries;
2740
+ /**
2741
+ * Delay between retries.
2742
+ *
2743
+ * By default, the `retryDelay` is exponential backoff.
2744
+ * More details can be found in: https://upstash.com/docs/qstash/features/retry.
2745
+ *
2746
+ * The `retryDelay` option allows you to customize the delay (in milliseconds) between retry attempts when message delivery fails.
2747
+ *
2748
+ * You can use mathematical expressions and the following built-in functions to calculate the delay dynamically.
2749
+ * The special variable `retried` represents the current retry attempt count (starting from 0).
2750
+ *
2751
+ * Supported functions:
2752
+ * - `pow`
2753
+ * - `sqrt`
2754
+ * - `abs`
2755
+ * - `exp`
2756
+ * - `floor`
2757
+ * - `ceil`
2758
+ * - `round`
2759
+ * - `min`
2760
+ * - `max`
2761
+ *
2762
+ * Examples of valid `retryDelay` values:
2763
+ * ```ts
2764
+ * 1000 // 1 second
2765
+ * 1000 * (1 + retried) // 1 second multiplied by the current retry attempt
2766
+ * pow(2, retried) // 2 to the power of the current retry attempt
2767
+ * max(10, pow(2, retried)) // The greater of 10 or 2^retried
2768
+ * ```
2769
+ */
2770
+ retryDelay;
2685
2771
  /**
2686
2772
  * Settings for controlling the number of active requests
2687
2773
  * and number of requests per second with the same key.
2688
2774
  */
2689
2775
  flowControl;
2776
+ /**
2777
+ * Label to apply to the workflow run.
2778
+ *
2779
+ * Can be used to filter the workflow run logs.
2780
+ *
2781
+ * Can be set by passing a `label` parameter when triggering the workflow
2782
+ * with `client.trigger`:
2783
+ *
2784
+ * ```ts
2785
+ * await client.trigger({
2786
+ * url: "https://workflow-endpoint.com",
2787
+ * label: "my-label"
2788
+ * });
2789
+ * ```
2790
+ */
2791
+ label;
2690
2792
  constructor({
2691
2793
  qstashClient,
2692
2794
  workflowRunId,
@@ -2698,9 +2800,11 @@ var WorkflowContext = class {
2698
2800
  initialPayload,
2699
2801
  env,
2700
2802
  retries,
2803
+ retryDelay,
2701
2804
  telemetry: telemetry2,
2702
2805
  invokeCount,
2703
- flowControl
2806
+ flowControl,
2807
+ label
2704
2808
  }) {
2705
2809
  this.qstashClient = qstashClient;
2706
2810
  this.workflowRunId = workflowRunId;
@@ -2711,7 +2815,9 @@ var WorkflowContext = class {
2711
2815
  this.requestPayload = initialPayload;
2712
2816
  this.env = env ?? {};
2713
2817
  this.retries = retries ?? DEFAULT_RETRIES;
2818
+ this.retryDelay = retryDelay;
2714
2819
  this.flowControl = flowControl;
2820
+ this.label = label;
2715
2821
  this.executor = new AutoExecutor(this, this.steps, telemetry2, invokeCount, debug);
2716
2822
  }
2717
2823
  /**
@@ -2792,6 +2898,7 @@ var WorkflowContext = class {
2792
2898
  settings.body,
2793
2899
  settings.headers || {},
2794
2900
  settings.retries || 0,
2901
+ settings.retryDelay,
2795
2902
  settings.timeout,
2796
2903
  settings.flowControl ?? settings.workflow.options.flowControl
2797
2904
  );
@@ -2802,6 +2909,7 @@ var WorkflowContext = class {
2802
2909
  body,
2803
2910
  headers = {},
2804
2911
  retries = 0,
2912
+ retryDelay,
2805
2913
  timeout,
2806
2914
  flowControl
2807
2915
  } = settings;
@@ -2812,6 +2920,7 @@ var WorkflowContext = class {
2812
2920
  body,
2813
2921
  headers,
2814
2922
  retries,
2923
+ retryDelay,
2815
2924
  timeout,
2816
2925
  flowControl
2817
2926
  );
@@ -2822,7 +2931,7 @@ var WorkflowContext = class {
2822
2931
  * Pauses workflow execution until a specific event occurs or a timeout is reached.
2823
2932
  *
2824
2933
  *```ts
2825
- * const result = await workflow.waitForEvent("payment-confirmed", {
2934
+ * const result = await workflow.waitForEvent("payment-confirmed", "payment.confirmed", {
2826
2935
  * timeout: "5m"
2827
2936
  * });
2828
2937
  *```
@@ -2848,7 +2957,7 @@ var WorkflowContext = class {
2848
2957
  * @param stepName
2849
2958
  * @param eventId - Unique identifier for the event to wait for
2850
2959
  * @param options - Configuration options.
2851
- * @returns `{ timeout: boolean, eventData: unknown }`.
2960
+ * @returns `{ timeout: boolean, eventData: TEventData }`.
2852
2961
  * The `timeout` property specifies if the workflow has timed out. The `eventData`
2853
2962
  * is the data passed when notifying this workflow of an event.
2854
2963
  */
@@ -3008,7 +3117,9 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3008
3117
  initialPayload: context.requestPayload,
3009
3118
  env: context.env,
3010
3119
  retries: context.retries,
3011
- flowControl: context.flowControl
3120
+ retryDelay: context.retryDelay,
3121
+ flowControl: context.flowControl,
3122
+ label: context.label
3012
3123
  });
3013
3124
  try {
3014
3125
  await routeFunction(disabledContext);
@@ -3016,6 +3127,9 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3016
3127
  if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
3017
3128
  return ok("step-found");
3018
3129
  }
3130
+ console.warn(
3131
+ "Upstash Workflow: Received an error while authorizing request. Please avoid throwing errors before the first step of your workflow."
3132
+ );
3019
3133
  return err(error);
3020
3134
  }
3021
3135
  return ok("run-ended");
@@ -3157,9 +3271,9 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
3157
3271
  };
3158
3272
  }
3159
3273
  };
3160
- var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, flowControl, debug) => {
3274
+ var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, retryDelay, flowControl, debug) => {
3161
3275
  if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
3162
- return ok("not-failure-callback");
3276
+ return ok({ result: "not-failure-callback" });
3163
3277
  }
3164
3278
  if (!failureFunction) {
3165
3279
  return err(
@@ -3182,20 +3296,23 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3182
3296
  if (!errorMessage) {
3183
3297
  errorMessage = `Couldn't parse 'failResponse' in 'failureFunction', received: '${decodedBody}'`;
3184
3298
  }
3299
+ const userHeaders = recreateUserHeaders(request.headers);
3185
3300
  const workflowContext = new WorkflowContext({
3186
3301
  qstashClient,
3187
3302
  workflowRunId,
3188
3303
  initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
3189
- headers: recreateUserHeaders(request.headers),
3304
+ headers: userHeaders,
3190
3305
  steps: [],
3191
3306
  url,
3192
3307
  failureUrl: url,
3193
3308
  debug,
3194
3309
  env,
3195
3310
  retries,
3311
+ retryDelay,
3196
3312
  flowControl,
3197
- telemetry: void 0
3313
+ telemetry: void 0,
3198
3314
  // not going to make requests in authentication check
3315
+ label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0
3199
3316
  });
3200
3317
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
3201
3318
  routeFunction,
@@ -3207,16 +3324,16 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3207
3324
  } else if (authCheck.value === "run-ended") {
3208
3325
  return err(new WorkflowError("Not authorized to run the failure function."));
3209
3326
  }
3210
- await failureFunction({
3327
+ const failureResponse = await failureFunction({
3211
3328
  context: workflowContext,
3212
3329
  failStatus: status,
3213
3330
  failResponse: errorMessage,
3214
3331
  failHeaders: header
3215
3332
  });
3333
+ return ok({ result: "is-failure-callback", response: failureResponse });
3216
3334
  } catch (error) {
3217
3335
  return err(error);
3218
3336
  }
3219
- return ok("is-failure-callback");
3220
3337
  };
3221
3338
 
3222
3339
  // src/serve/options.ts
@@ -3232,8 +3349,8 @@ var processOptions = (options) => {
3232
3349
  baseUrl: environment.QSTASH_URL,
3233
3350
  token: environment.QSTASH_TOKEN
3234
3351
  }),
3235
- onStepFinish: (workflowRunId, finishCondition) => {
3236
- if (finishCondition === "auth-fail") {
3352
+ onStepFinish: (workflowRunId, _finishCondition, detailedFinishCondition) => {
3353
+ if (detailedFinishCondition?.condition === "auth-fail") {
3237
3354
  console.error(AUTH_FAIL_MESSAGE);
3238
3355
  return new Response(
3239
3356
  JSON.stringify({
@@ -3241,19 +3358,33 @@ var processOptions = (options) => {
3241
3358
  workflowRunId
3242
3359
  }),
3243
3360
  {
3244
- status: 400
3361
+ status: 400,
3362
+ headers: {
3363
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3364
+ }
3245
3365
  }
3246
3366
  );
3247
- } else if (finishCondition instanceof WorkflowNonRetryableError) {
3248
- return new Response(JSON.stringify(formatWorkflowError(finishCondition)), {
3367
+ } else if (detailedFinishCondition?.condition === "non-retryable-error") {
3368
+ return new Response(JSON.stringify(formatWorkflowError(detailedFinishCondition.result)), {
3249
3369
  headers: {
3250
- "Upstash-NonRetryable-Error": "true"
3370
+ "Upstash-NonRetryable-Error": "true",
3371
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3251
3372
  },
3252
3373
  status: 489
3253
3374
  });
3375
+ } else if (detailedFinishCondition?.condition === "failure-callback") {
3376
+ return new Response(detailedFinishCondition.result ?? void 0, {
3377
+ status: 200,
3378
+ headers: {
3379
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3380
+ }
3381
+ });
3254
3382
  }
3255
3383
  return new Response(JSON.stringify({ workflowRunId }), {
3256
- status: 200
3384
+ status: 200,
3385
+ headers: {
3386
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3387
+ }
3257
3388
  });
3258
3389
  },
3259
3390
  initialPayloadParser: (initialRequest) => {
@@ -3327,6 +3458,7 @@ var serveBase = (routeFunction, telemetry2, options) => {
3327
3458
  baseUrl,
3328
3459
  env,
3329
3460
  retries,
3461
+ retryDelay,
3330
3462
  useJSONContent,
3331
3463
  disableTelemetry,
3332
3464
  flowControl,
@@ -3357,10 +3489,14 @@ var serveBase = (routeFunction, telemetry2, options) => {
3357
3489
  debug
3358
3490
  );
3359
3491
  if (workflowRunEnded) {
3360
- return onStepFinish(workflowRunId, "workflow-already-ended");
3492
+ return onStepFinish(workflowRunId, "workflow-already-ended", {
3493
+ condition: "workflow-already-ended"
3494
+ });
3361
3495
  }
3362
3496
  if (isLastDuplicate) {
3363
- return onStepFinish(workflowRunId, "duplicate-step");
3497
+ return onStepFinish(workflowRunId, "duplicate-step", {
3498
+ condition: "duplicate-step"
3499
+ });
3364
3500
  }
3365
3501
  const failureCheck = await handleFailure(
3366
3502
  request,
@@ -3371,16 +3507,21 @@ var serveBase = (routeFunction, telemetry2, options) => {
3371
3507
  failureFunction,
3372
3508
  env,
3373
3509
  retries,
3510
+ retryDelay,
3374
3511
  flowControl,
3375
3512
  debug
3376
3513
  );
3377
3514
  if (failureCheck.isErr()) {
3378
3515
  throw failureCheck.error;
3379
- } else if (failureCheck.value === "is-failure-callback") {
3516
+ } else if (failureCheck.value.result === "is-failure-callback") {
3380
3517
  await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
3381
- return onStepFinish(workflowRunId, "failure-callback");
3518
+ return onStepFinish(workflowRunId, "failure-callback", {
3519
+ condition: "failure-callback",
3520
+ result: failureCheck.value.response
3521
+ });
3382
3522
  }
3383
3523
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
3524
+ const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
3384
3525
  const workflowContext = new WorkflowContext({
3385
3526
  qstashClient,
3386
3527
  workflowRunId,
@@ -3392,9 +3533,11 @@ var serveBase = (routeFunction, telemetry2, options) => {
3392
3533
  debug,
3393
3534
  env,
3394
3535
  retries,
3536
+ retryDelay,
3395
3537
  telemetry: telemetry2,
3396
3538
  invokeCount,
3397
- flowControl
3539
+ flowControl,
3540
+ label
3398
3541
  });
3399
3542
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
3400
3543
  routeFunction,
@@ -3407,7 +3550,8 @@ var serveBase = (routeFunction, telemetry2, options) => {
3407
3550
  await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
3408
3551
  return onStepFinish(
3409
3552
  isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
3410
- "auth-fail"
3553
+ "auth-fail",
3554
+ { condition: "auth-fail" }
3411
3555
  );
3412
3556
  }
3413
3557
  const callReturnCheck = await handleThirdPartyCallResult({
@@ -3417,6 +3561,7 @@ var serveBase = (routeFunction, telemetry2, options) => {
3417
3561
  workflowUrl,
3418
3562
  failureUrl: workflowFailureUrl,
3419
3563
  retries,
3564
+ retryDelay,
3420
3565
  flowControl,
3421
3566
  telemetry: telemetry2,
3422
3567
  debug
@@ -3444,19 +3589,28 @@ var serveBase = (routeFunction, telemetry2, options) => {
3444
3589
  debug
3445
3590
  });
3446
3591
  if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3447
- return onStepFinish(workflowRunId, result.value);
3592
+ return onStepFinish(workflowRunId, result.value, {
3593
+ condition: "non-retryable-error",
3594
+ result: result.value
3595
+ });
3448
3596
  }
3449
3597
  if (result.isErr()) {
3450
3598
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3451
3599
  throw result.error;
3452
3600
  }
3453
3601
  await debug?.log("INFO", "RESPONSE_WORKFLOW");
3454
- return onStepFinish(workflowContext.workflowRunId, "success");
3602
+ return onStepFinish(workflowContext.workflowRunId, "success", {
3603
+ condition: "success"
3604
+ });
3455
3605
  } else if (callReturnCheck.value === "workflow-ended") {
3456
- return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended");
3606
+ return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended", {
3607
+ condition: "workflow-already-ended"
3608
+ });
3457
3609
  }
3458
3610
  await debug?.log("INFO", "RESPONSE_DEFAULT");
3459
- return onStepFinish("no-workflow-id", "fromCallback");
3611
+ return onStepFinish("no-workflow-id", "fromCallback", {
3612
+ condition: "fromCallback"
3613
+ });
3460
3614
  };
3461
3615
  const safeHandler = async (request) => {
3462
3616
  try {
@@ -3471,11 +3625,17 @@ var serveBase = (routeFunction, telemetry2, options) => {
3471
3625
  Original error: '${formattedError.message}'`;
3472
3626
  console.error(errorMessage);
3473
3627
  return new Response(errorMessage, {
3474
- status: 500
3628
+ status: 500,
3629
+ headers: {
3630
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3631
+ }
3475
3632
  });
3476
3633
  }
3477
3634
  return new Response(JSON.stringify(formattedError), {
3478
- status: 500
3635
+ status: 500,
3636
+ headers: {
3637
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3638
+ }
3479
3639
  });
3480
3640
  }
3481
3641
  };