@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/h3.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as h3 from 'h3';
2
- import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.mjs';
3
- import { s as serveManyBase } from './serve-many-AFwJPR3S.mjs';
2
+ import { R as RouteFunction, n as PublicServeOptions, x as InvokableWorkflow } from './types-B7_5AkKQ.mjs';
3
+ import { s as serveManyBase } from './serve-many-CEUYWQvV.mjs';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';
package/h3.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as h3 from 'h3';
2
- import { R as RouteFunction, n as PublicServeOptions, w as InvokableWorkflow } from './types-Dd-3bPoU.js';
3
- import { s as serveManyBase } from './serve-many-AaKSQyi7.js';
2
+ import { R as RouteFunction, n as PublicServeOptions, x as InvokableWorkflow } from './types-B7_5AkKQ.js';
3
+ import { s as serveManyBase } from './serve-many-BObe3pdI.js';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';
package/h3.js CHANGED
@@ -398,12 +398,13 @@ var WORKFLOW_URL_HEADER = "Upstash-Workflow-Url";
398
398
  var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
399
399
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
400
400
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
401
+ var WORKFLOW_LABEL_HEADER = "Upstash-Label";
401
402
  var WORKFLOW_PROTOCOL_VERSION = "1";
402
403
  var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
403
404
  var DEFAULT_CONTENT_TYPE = "application/json";
404
405
  var NO_CONCURRENCY = 1;
405
406
  var DEFAULT_RETRIES = 3;
406
- var VERSION = "v0.2.15";
407
+ var VERSION = "v0.2.18";
407
408
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
408
409
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
409
410
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -933,6 +934,7 @@ var triggerFirstInvocation = async (params) => {
933
934
  workflowUrl: workflowContext.url,
934
935
  failureUrl: workflowContext.failureUrl,
935
936
  retries: workflowContext.retries,
937
+ retryDelay: workflowContext.retryDelay,
936
938
  telemetry: telemetry2,
937
939
  flowControl: workflowContext.flowControl,
938
940
  useJSONContent: useJSONContent ?? false
@@ -946,6 +948,9 @@ var triggerFirstInvocation = async (params) => {
946
948
  if (useJSONContent) {
947
949
  headers["content-type"] = "application/json";
948
950
  }
951
+ if (workflowContext.label) {
952
+ headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
953
+ }
949
954
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
950
955
  return {
951
956
  headers,
@@ -1046,10 +1051,11 @@ var recreateUserHeaders = (headers) => {
1046
1051
  const pairs = headers.entries();
1047
1052
  for (const [header, value] of pairs) {
1048
1053
  const headerLowerCase = header.toLowerCase();
1049
- if (!headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
1054
+ const isUserHeader = !headerLowerCase.startsWith("upstash-workflow-") && // https://vercel.com/docs/edge-network/headers/request-headers#x-vercel-id
1050
1055
  !headerLowerCase.startsWith("x-vercel-") && !headerLowerCase.startsWith("x-forwarded-") && // https://blog.cloudflare.com/preventing-request-loops-using-cdn-loop/
1051
1056
  headerLowerCase !== "cf-connecting-ip" && headerLowerCase !== "cdn-loop" && headerLowerCase !== "cf-ew-via" && headerLowerCase !== "cf-ray" && // For Render https://render.com
1052
- headerLowerCase !== "render-proxy-ttl") {
1057
+ headerLowerCase !== "render-proxy-ttl" || headerLowerCase === WORKFLOW_LABEL_HEADER.toLocaleLowerCase();
1058
+ if (isUserHeader) {
1053
1059
  filteredHeaders.append(header, value);
1054
1060
  }
1055
1061
  }
@@ -1062,6 +1068,7 @@ var handleThirdPartyCallResult = async ({
1062
1068
  workflowUrl,
1063
1069
  failureUrl,
1064
1070
  retries,
1071
+ retryDelay,
1065
1072
  telemetry: telemetry2,
1066
1073
  flowControl,
1067
1074
  debug
@@ -1132,6 +1139,7 @@ ${atob(callbackMessage.body ?? "")}`
1132
1139
  workflowUrl,
1133
1140
  failureUrl,
1134
1141
  retries,
1142
+ retryDelay,
1135
1143
  telemetry: telemetry2,
1136
1144
  flowControl
1137
1145
  },
@@ -1282,7 +1290,8 @@ var BaseLazyStep = class _BaseLazyStep {
1282
1290
  workflowRunId: context.workflowRunId,
1283
1291
  workflowUrl: context.url,
1284
1292
  failureUrl: context.failureUrl,
1285
- retries: context.retries,
1293
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1294
+ retryDelay: context.retryDelay,
1286
1295
  useJSONContent: false,
1287
1296
  telemetry: telemetry2,
1288
1297
  flowControl: context.flowControl
@@ -1301,6 +1310,9 @@ var BaseLazyStep = class _BaseLazyStep {
1301
1310
  body,
1302
1311
  headers,
1303
1312
  method: "POST",
1313
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1314
+ retryDelay: context.retryDelay,
1315
+ flowControl: context.flowControl,
1304
1316
  url: context.url
1305
1317
  }
1306
1318
  ]);
@@ -1371,6 +1383,9 @@ var LazySleepStep = class extends BaseLazyStep {
1371
1383
  headers,
1372
1384
  method: "POST",
1373
1385
  url: context.url,
1386
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1387
+ retryDelay: context.retryDelay,
1388
+ flowControl: context.flowControl,
1374
1389
  delay: isParallel ? void 0 : this.sleep
1375
1390
  }
1376
1391
  ]);
@@ -1413,6 +1428,9 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1413
1428
  headers,
1414
1429
  method: "POST",
1415
1430
  url: context.url,
1431
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1432
+ retryDelay: context.retryDelay,
1433
+ flowControl: context.flowControl,
1416
1434
  notBefore: isParallel ? void 0 : this.sleepUntil
1417
1435
  }
1418
1436
  ]);
@@ -1424,17 +1442,19 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1424
1442
  body;
1425
1443
  headers;
1426
1444
  retries;
1445
+ retryDelay;
1427
1446
  timeout;
1428
1447
  flowControl;
1429
1448
  stepType = "Call";
1430
1449
  allowUndefinedOut = false;
1431
- constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
1450
+ constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl) {
1432
1451
  super(stepName);
1433
1452
  this.url = url;
1434
1453
  this.method = method;
1435
1454
  this.body = body;
1436
1455
  this.headers = headers;
1437
1456
  this.retries = retries;
1457
+ this.retryDelay = retryDelay;
1438
1458
  this.timeout = timeout;
1439
1459
  this.flowControl = flowControl;
1440
1460
  }
@@ -1509,6 +1529,9 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1509
1529
  getHeaders({ context, telemetry: telemetry2, invokeCount, step }) {
1510
1530
  const { headers, contentType } = super.getHeaders({ context, telemetry: telemetry2, invokeCount, step });
1511
1531
  headers["Upstash-Retries"] = this.retries.toString();
1532
+ if (this.retryDelay) {
1533
+ headers["Upstash-Retry-Delay"] = this.retryDelay;
1534
+ }
1512
1535
  headers[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
1513
1536
  if (this.flowControl) {
1514
1537
  const { flowControlKey, flowControlValue } = prepareFlowControl(this.flowControl);
@@ -1530,7 +1553,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1530
1553
  "Upstash-Callback-Workflow-CallType": "fromCallback",
1531
1554
  "Upstash-Callback-Workflow-Init": "false",
1532
1555
  "Upstash-Callback-Workflow-Url": context.url,
1533
- "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
1556
+ "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger",
1534
1557
  "Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
1535
1558
  "Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
1536
1559
  "Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
@@ -1548,7 +1571,10 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1548
1571
  headers,
1549
1572
  body: JSON.stringify(this.body),
1550
1573
  method: this.method,
1551
- url: this.url
1574
+ url: this.url,
1575
+ retries: DEFAULT_RETRIES === this.retries ? void 0 : this.retries,
1576
+ retryDelay: this.retryDelay,
1577
+ flowControl: this.flowControl
1552
1578
  }
1553
1579
  ]);
1554
1580
  }
@@ -1677,6 +1703,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1677
1703
  headers = {},
1678
1704
  workflowRunId,
1679
1705
  retries,
1706
+ retryDelay,
1680
1707
  flowControl
1681
1708
  }) {
1682
1709
  super(stepName);
@@ -1686,6 +1713,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1686
1713
  headers,
1687
1714
  workflowRunId: getWorkflowRunId(workflowRunId),
1688
1715
  retries,
1716
+ retryDelay,
1689
1717
  flowControl
1690
1718
  };
1691
1719
  const { workflowId } = workflow;
@@ -1730,6 +1758,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1730
1758
  workflowUrl: context.url,
1731
1759
  failureUrl: context.failureUrl,
1732
1760
  retries: context.retries,
1761
+ retryDelay: context.retryDelay,
1733
1762
  telemetry: telemetry2,
1734
1763
  flowControl: context.flowControl,
1735
1764
  useJSONContent: false
@@ -1755,11 +1784,13 @@ var LazyInvokeStep = class extends BaseLazyStep {
1755
1784
  headers = {},
1756
1785
  workflowRunId = getWorkflowRunId(),
1757
1786
  retries,
1787
+ retryDelay,
1758
1788
  flowControl
1759
1789
  } = this.params;
1760
1790
  const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
1761
1791
  const {
1762
1792
  retries: workflowRetries,
1793
+ retryDelay: workflowRetryDelay,
1763
1794
  failureFunction,
1764
1795
  failureUrl,
1765
1796
  useJSONContent,
@@ -1771,6 +1802,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1771
1802
  workflowRunId,
1772
1803
  workflowUrl: newUrl,
1773
1804
  retries: retries ?? workflowRetries,
1805
+ retryDelay: retryDelay ?? workflowRetryDelay,
1774
1806
  telemetry: telemetry2,
1775
1807
  failureUrl: failureFunction ? newUrl : failureUrl,
1776
1808
  flowControl: flowControl ?? workflowFlowControl,
@@ -1837,6 +1869,7 @@ var WorkflowHeaders = class {
1837
1869
  getHeaders() {
1838
1870
  this.addBaseHeaders();
1839
1871
  this.addRetries();
1872
+ this.addRetryDelay();
1840
1873
  this.addFlowControl();
1841
1874
  this.addUserHeaders();
1842
1875
  this.addInvokeCount();
@@ -1850,7 +1883,7 @@ var WorkflowHeaders = class {
1850
1883
  [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
1851
1884
  [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
1852
1885
  [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
1853
- [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
1886
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger",
1854
1887
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1855
1888
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {},
1856
1889
  ...this.workflowConfig.telemetry && this.stepInfo?.lazyStep instanceof LazyCallStep && this.stepInfo.lazyStep.headers[AGENT_NAME_HEADER] ? { [TELEMETRY_HEADER_AGENT]: "true" } : {}
@@ -1882,6 +1915,16 @@ var WorkflowHeaders = class {
1882
1915
  this.headers.failureHeaders["Retries"] = retries;
1883
1916
  }
1884
1917
  }
1918
+ addRetryDelay() {
1919
+ if (this.workflowConfig.retryDelay === void 0 || this.workflowConfig.retryDelay === "") {
1920
+ return;
1921
+ }
1922
+ const retryDelay = this.workflowConfig.retryDelay.toString();
1923
+ this.headers.workflowHeaders["Retry-Delay"] = retryDelay;
1924
+ if (this.workflowConfig.failureUrl) {
1925
+ this.headers.failureHeaders["Retry-Delay"] = retryDelay;
1926
+ }
1927
+ }
1885
1928
  addFlowControl() {
1886
1929
  if (!this.workflowConfig.flowControl) {
1887
1930
  return;
@@ -1916,10 +1959,13 @@ var WorkflowHeaders = class {
1916
1959
  this.headers.failureHeaders["Workflow-Init"] = "false";
1917
1960
  this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
1918
1961
  this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
1919
- this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody";
1962
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger";
1920
1963
  if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
1921
1964
  this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
1922
1965
  }
1966
+ if (this.workflowConfig.retryDelay !== void 0 && this.workflowConfig.retryDelay !== "") {
1967
+ this.headers.failureHeaders["Retry-Delay"] = this.workflowConfig.retryDelay.toString();
1968
+ }
1923
1969
  }
1924
1970
  addContentType() {
1925
1971
  if (this.workflowConfig.useJSONContent) {
@@ -2001,6 +2047,7 @@ var submitParallelSteps = async ({
2001
2047
  workflowUrl: context.url,
2002
2048
  failureUrl: context.failureUrl,
2003
2049
  retries: context.retries,
2050
+ retryDelay: context.retryDelay,
2004
2051
  flowControl: context.flowControl,
2005
2052
  telemetry: telemetry2
2006
2053
  },
@@ -2421,7 +2468,7 @@ var BaseWorkflowApi = class {
2421
2468
  */
2422
2469
  async callApi(stepName, settings) {
2423
2470
  const { url, appendHeaders, method } = getProviderInfo(settings.api);
2424
- const { method: userMethod, body, headers = {}, retries = 0, timeout } = settings;
2471
+ const { method: userMethod, body, headers = {}, retries = 0, retryDelay, timeout } = settings;
2425
2472
  return await this.context.call(stepName, {
2426
2473
  url,
2427
2474
  method: userMethod ?? method,
@@ -2431,6 +2478,7 @@ var BaseWorkflowApi = class {
2431
2478
  ...headers
2432
2479
  },
2433
2480
  retries,
2481
+ retryDelay,
2434
2482
  timeout
2435
2483
  });
2436
2484
  }
@@ -2520,6 +2568,7 @@ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
2520
2568
  body,
2521
2569
  timeout: agentCallParams?.timeout,
2522
2570
  retries: agentCallParams?.retries,
2571
+ retryDelay: agentCallParams?.retryDelay,
2523
2572
  flowControl: agentCallParams?.flowControl
2524
2573
  });
2525
2574
  const responseHeaders = new Headers(
@@ -2848,7 +2897,10 @@ var serveManyBase = ({
2848
2897
  return new Response(
2849
2898
  `Unexpected request in serveMany. workflowId not set. Please update the URL of your request.`,
2850
2899
  {
2851
- status: 404
2900
+ status: 404,
2901
+ headers: {
2902
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
2903
+ }
2852
2904
  }
2853
2905
  );
2854
2906
  }
@@ -2857,7 +2909,10 @@ var serveManyBase = ({
2857
2909
  return new Response(
2858
2910
  `No workflows in serveMany found for '${pickedWorkflowId}'. Please update the URL of your request.`,
2859
2911
  {
2860
- status: 404
2912
+ status: 404,
2913
+ headers: {
2914
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
2915
+ }
2861
2916
  }
2862
2917
  );
2863
2918
  }
@@ -2994,11 +3049,58 @@ var WorkflowContext = class {
2994
3049
  * Number of retries
2995
3050
  */
2996
3051
  retries;
3052
+ /**
3053
+ * Delay between retries.
3054
+ *
3055
+ * By default, the `retryDelay` is exponential backoff.
3056
+ * More details can be found in: https://upstash.com/docs/qstash/features/retry.
3057
+ *
3058
+ * The `retryDelay` option allows you to customize the delay (in milliseconds) between retry attempts when message delivery fails.
3059
+ *
3060
+ * You can use mathematical expressions and the following built-in functions to calculate the delay dynamically.
3061
+ * The special variable `retried` represents the current retry attempt count (starting from 0).
3062
+ *
3063
+ * Supported functions:
3064
+ * - `pow`
3065
+ * - `sqrt`
3066
+ * - `abs`
3067
+ * - `exp`
3068
+ * - `floor`
3069
+ * - `ceil`
3070
+ * - `round`
3071
+ * - `min`
3072
+ * - `max`
3073
+ *
3074
+ * Examples of valid `retryDelay` values:
3075
+ * ```ts
3076
+ * 1000 // 1 second
3077
+ * 1000 * (1 + retried) // 1 second multiplied by the current retry attempt
3078
+ * pow(2, retried) // 2 to the power of the current retry attempt
3079
+ * max(10, pow(2, retried)) // The greater of 10 or 2^retried
3080
+ * ```
3081
+ */
3082
+ retryDelay;
2997
3083
  /**
2998
3084
  * Settings for controlling the number of active requests
2999
3085
  * and number of requests per second with the same key.
3000
3086
  */
3001
3087
  flowControl;
3088
+ /**
3089
+ * Label to apply to the workflow run.
3090
+ *
3091
+ * Can be used to filter the workflow run logs.
3092
+ *
3093
+ * Can be set by passing a `label` parameter when triggering the workflow
3094
+ * with `client.trigger`:
3095
+ *
3096
+ * ```ts
3097
+ * await client.trigger({
3098
+ * url: "https://workflow-endpoint.com",
3099
+ * label: "my-label"
3100
+ * });
3101
+ * ```
3102
+ */
3103
+ label;
3002
3104
  constructor({
3003
3105
  qstashClient,
3004
3106
  workflowRunId,
@@ -3010,9 +3112,11 @@ var WorkflowContext = class {
3010
3112
  initialPayload,
3011
3113
  env,
3012
3114
  retries,
3115
+ retryDelay,
3013
3116
  telemetry: telemetry2,
3014
3117
  invokeCount,
3015
- flowControl
3118
+ flowControl,
3119
+ label
3016
3120
  }) {
3017
3121
  this.qstashClient = qstashClient;
3018
3122
  this.workflowRunId = workflowRunId;
@@ -3023,7 +3127,9 @@ var WorkflowContext = class {
3023
3127
  this.requestPayload = initialPayload;
3024
3128
  this.env = env ?? {};
3025
3129
  this.retries = retries ?? DEFAULT_RETRIES;
3130
+ this.retryDelay = retryDelay;
3026
3131
  this.flowControl = flowControl;
3132
+ this.label = label;
3027
3133
  this.executor = new AutoExecutor(this, this.steps, telemetry2, invokeCount, debug);
3028
3134
  }
3029
3135
  /**
@@ -3104,6 +3210,7 @@ var WorkflowContext = class {
3104
3210
  settings.body,
3105
3211
  settings.headers || {},
3106
3212
  settings.retries || 0,
3213
+ settings.retryDelay,
3107
3214
  settings.timeout,
3108
3215
  settings.flowControl ?? settings.workflow.options.flowControl
3109
3216
  );
@@ -3114,6 +3221,7 @@ var WorkflowContext = class {
3114
3221
  body,
3115
3222
  headers = {},
3116
3223
  retries = 0,
3224
+ retryDelay,
3117
3225
  timeout,
3118
3226
  flowControl
3119
3227
  } = settings;
@@ -3124,6 +3232,7 @@ var WorkflowContext = class {
3124
3232
  body,
3125
3233
  headers,
3126
3234
  retries,
3235
+ retryDelay,
3127
3236
  timeout,
3128
3237
  flowControl
3129
3238
  );
@@ -3134,7 +3243,7 @@ var WorkflowContext = class {
3134
3243
  * Pauses workflow execution until a specific event occurs or a timeout is reached.
3135
3244
  *
3136
3245
  *```ts
3137
- * const result = await workflow.waitForEvent("payment-confirmed", {
3246
+ * const result = await workflow.waitForEvent("payment-confirmed", "payment.confirmed", {
3138
3247
  * timeout: "5m"
3139
3248
  * });
3140
3249
  *```
@@ -3160,7 +3269,7 @@ var WorkflowContext = class {
3160
3269
  * @param stepName
3161
3270
  * @param eventId - Unique identifier for the event to wait for
3162
3271
  * @param options - Configuration options.
3163
- * @returns `{ timeout: boolean, eventData: unknown }`.
3272
+ * @returns `{ timeout: boolean, eventData: TEventData }`.
3164
3273
  * The `timeout` property specifies if the workflow has timed out. The `eventData`
3165
3274
  * is the data passed when notifying this workflow of an event.
3166
3275
  */
@@ -3320,7 +3429,9 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3320
3429
  initialPayload: context.requestPayload,
3321
3430
  env: context.env,
3322
3431
  retries: context.retries,
3323
- flowControl: context.flowControl
3432
+ retryDelay: context.retryDelay,
3433
+ flowControl: context.flowControl,
3434
+ label: context.label
3324
3435
  });
3325
3436
  try {
3326
3437
  await routeFunction(disabledContext);
@@ -3328,6 +3439,9 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3328
3439
  if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
3329
3440
  return ok("step-found");
3330
3441
  }
3442
+ console.warn(
3443
+ "Upstash Workflow: Received an error while authorizing request. Please avoid throwing errors before the first step of your workflow."
3444
+ );
3331
3445
  return err(error);
3332
3446
  }
3333
3447
  return ok("run-ended");
@@ -3469,9 +3583,9 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
3469
3583
  };
3470
3584
  }
3471
3585
  };
3472
- var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, flowControl, debug) => {
3586
+ var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, retryDelay, flowControl, debug) => {
3473
3587
  if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
3474
- return ok("not-failure-callback");
3588
+ return ok({ result: "not-failure-callback" });
3475
3589
  }
3476
3590
  if (!failureFunction) {
3477
3591
  return err(
@@ -3494,20 +3608,23 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3494
3608
  if (!errorMessage) {
3495
3609
  errorMessage = `Couldn't parse 'failResponse' in 'failureFunction', received: '${decodedBody}'`;
3496
3610
  }
3611
+ const userHeaders = recreateUserHeaders(request.headers);
3497
3612
  const workflowContext = new WorkflowContext({
3498
3613
  qstashClient,
3499
3614
  workflowRunId,
3500
3615
  initialPayload: sourceBody ? initialPayloadParser(decodeBase64(sourceBody)) : void 0,
3501
- headers: recreateUserHeaders(request.headers),
3616
+ headers: userHeaders,
3502
3617
  steps: [],
3503
3618
  url,
3504
3619
  failureUrl: url,
3505
3620
  debug,
3506
3621
  env,
3507
3622
  retries,
3623
+ retryDelay,
3508
3624
  flowControl,
3509
- telemetry: void 0
3625
+ telemetry: void 0,
3510
3626
  // not going to make requests in authentication check
3627
+ label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0
3511
3628
  });
3512
3629
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
3513
3630
  routeFunction,
@@ -3519,16 +3636,16 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3519
3636
  } else if (authCheck.value === "run-ended") {
3520
3637
  return err(new WorkflowError("Not authorized to run the failure function."));
3521
3638
  }
3522
- await failureFunction({
3639
+ const failureResponse = await failureFunction({
3523
3640
  context: workflowContext,
3524
3641
  failStatus: status,
3525
3642
  failResponse: errorMessage,
3526
3643
  failHeaders: header
3527
3644
  });
3645
+ return ok({ result: "is-failure-callback", response: failureResponse });
3528
3646
  } catch (error) {
3529
3647
  return err(error);
3530
3648
  }
3531
- return ok("is-failure-callback");
3532
3649
  };
3533
3650
 
3534
3651
  // src/serve/options.ts
@@ -3544,8 +3661,8 @@ var processOptions = (options) => {
3544
3661
  baseUrl: environment.QSTASH_URL,
3545
3662
  token: environment.QSTASH_TOKEN
3546
3663
  }),
3547
- onStepFinish: (workflowRunId, finishCondition) => {
3548
- if (finishCondition === "auth-fail") {
3664
+ onStepFinish: (workflowRunId, _finishCondition, detailedFinishCondition) => {
3665
+ if (detailedFinishCondition?.condition === "auth-fail") {
3549
3666
  console.error(AUTH_FAIL_MESSAGE);
3550
3667
  return new Response(
3551
3668
  JSON.stringify({
@@ -3553,19 +3670,33 @@ var processOptions = (options) => {
3553
3670
  workflowRunId
3554
3671
  }),
3555
3672
  {
3556
- status: 400
3673
+ status: 400,
3674
+ headers: {
3675
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3676
+ }
3557
3677
  }
3558
3678
  );
3559
- } else if (finishCondition instanceof WorkflowNonRetryableError) {
3560
- return new Response(JSON.stringify(formatWorkflowError(finishCondition)), {
3679
+ } else if (detailedFinishCondition?.condition === "non-retryable-error") {
3680
+ return new Response(JSON.stringify(formatWorkflowError(detailedFinishCondition.result)), {
3561
3681
  headers: {
3562
- "Upstash-NonRetryable-Error": "true"
3682
+ "Upstash-NonRetryable-Error": "true",
3683
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3563
3684
  },
3564
3685
  status: 489
3565
3686
  });
3687
+ } else if (detailedFinishCondition?.condition === "failure-callback") {
3688
+ return new Response(detailedFinishCondition.result ?? void 0, {
3689
+ status: 200,
3690
+ headers: {
3691
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3692
+ }
3693
+ });
3566
3694
  }
3567
3695
  return new Response(JSON.stringify({ workflowRunId }), {
3568
- status: 200
3696
+ status: 200,
3697
+ headers: {
3698
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3699
+ }
3569
3700
  });
3570
3701
  },
3571
3702
  initialPayloadParser: (initialRequest) => {
@@ -3639,6 +3770,7 @@ var serveBase = (routeFunction, telemetry2, options) => {
3639
3770
  baseUrl,
3640
3771
  env,
3641
3772
  retries,
3773
+ retryDelay,
3642
3774
  useJSONContent,
3643
3775
  disableTelemetry,
3644
3776
  flowControl,
@@ -3669,10 +3801,14 @@ var serveBase = (routeFunction, telemetry2, options) => {
3669
3801
  debug
3670
3802
  );
3671
3803
  if (workflowRunEnded) {
3672
- return onStepFinish(workflowRunId, "workflow-already-ended");
3804
+ return onStepFinish(workflowRunId, "workflow-already-ended", {
3805
+ condition: "workflow-already-ended"
3806
+ });
3673
3807
  }
3674
3808
  if (isLastDuplicate) {
3675
- return onStepFinish(workflowRunId, "duplicate-step");
3809
+ return onStepFinish(workflowRunId, "duplicate-step", {
3810
+ condition: "duplicate-step"
3811
+ });
3676
3812
  }
3677
3813
  const failureCheck = await handleFailure(
3678
3814
  request,
@@ -3683,16 +3819,21 @@ var serveBase = (routeFunction, telemetry2, options) => {
3683
3819
  failureFunction,
3684
3820
  env,
3685
3821
  retries,
3822
+ retryDelay,
3686
3823
  flowControl,
3687
3824
  debug
3688
3825
  );
3689
3826
  if (failureCheck.isErr()) {
3690
3827
  throw failureCheck.error;
3691
- } else if (failureCheck.value === "is-failure-callback") {
3828
+ } else if (failureCheck.value.result === "is-failure-callback") {
3692
3829
  await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
3693
- return onStepFinish(workflowRunId, "failure-callback");
3830
+ return onStepFinish(workflowRunId, "failure-callback", {
3831
+ condition: "failure-callback",
3832
+ result: failureCheck.value.response
3833
+ });
3694
3834
  }
3695
3835
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
3836
+ const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
3696
3837
  const workflowContext = new WorkflowContext({
3697
3838
  qstashClient,
3698
3839
  workflowRunId,
@@ -3704,9 +3845,11 @@ var serveBase = (routeFunction, telemetry2, options) => {
3704
3845
  debug,
3705
3846
  env,
3706
3847
  retries,
3848
+ retryDelay,
3707
3849
  telemetry: telemetry2,
3708
3850
  invokeCount,
3709
- flowControl
3851
+ flowControl,
3852
+ label
3710
3853
  });
3711
3854
  const authCheck = await DisabledWorkflowContext.tryAuthentication(
3712
3855
  routeFunction,
@@ -3719,7 +3862,8 @@ var serveBase = (routeFunction, telemetry2, options) => {
3719
3862
  await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
3720
3863
  return onStepFinish(
3721
3864
  isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
3722
- "auth-fail"
3865
+ "auth-fail",
3866
+ { condition: "auth-fail" }
3723
3867
  );
3724
3868
  }
3725
3869
  const callReturnCheck = await handleThirdPartyCallResult({
@@ -3729,6 +3873,7 @@ var serveBase = (routeFunction, telemetry2, options) => {
3729
3873
  workflowUrl,
3730
3874
  failureUrl: workflowFailureUrl,
3731
3875
  retries,
3876
+ retryDelay,
3732
3877
  flowControl,
3733
3878
  telemetry: telemetry2,
3734
3879
  debug
@@ -3756,19 +3901,28 @@ var serveBase = (routeFunction, telemetry2, options) => {
3756
3901
  debug
3757
3902
  });
3758
3903
  if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3759
- return onStepFinish(workflowRunId, result.value);
3904
+ return onStepFinish(workflowRunId, result.value, {
3905
+ condition: "non-retryable-error",
3906
+ result: result.value
3907
+ });
3760
3908
  }
3761
3909
  if (result.isErr()) {
3762
3910
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3763
3911
  throw result.error;
3764
3912
  }
3765
3913
  await debug?.log("INFO", "RESPONSE_WORKFLOW");
3766
- return onStepFinish(workflowContext.workflowRunId, "success");
3914
+ return onStepFinish(workflowContext.workflowRunId, "success", {
3915
+ condition: "success"
3916
+ });
3767
3917
  } else if (callReturnCheck.value === "workflow-ended") {
3768
- return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended");
3918
+ return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended", {
3919
+ condition: "workflow-already-ended"
3920
+ });
3769
3921
  }
3770
3922
  await debug?.log("INFO", "RESPONSE_DEFAULT");
3771
- return onStepFinish("no-workflow-id", "fromCallback");
3923
+ return onStepFinish("no-workflow-id", "fromCallback", {
3924
+ condition: "fromCallback"
3925
+ });
3772
3926
  };
3773
3927
  const safeHandler = async (request) => {
3774
3928
  try {
@@ -3783,11 +3937,17 @@ var serveBase = (routeFunction, telemetry2, options) => {
3783
3937
  Original error: '${formattedError.message}'`;
3784
3938
  console.error(errorMessage);
3785
3939
  return new Response(errorMessage, {
3786
- status: 500
3940
+ status: 500,
3941
+ headers: {
3942
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3943
+ }
3787
3944
  });
3788
3945
  }
3789
3946
  return new Response(JSON.stringify(formattedError), {
3790
- status: 500
3947
+ status: 500,
3948
+ headers: {
3949
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3950
+ }
3791
3951
  });
3792
3952
  }
3793
3953
  };