@upstash/workflow 0.2.15 → 0.2.17

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/index.js CHANGED
@@ -104,7 +104,7 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
104
104
  var DEFAULT_CONTENT_TYPE = "application/json";
105
105
  var NO_CONCURRENCY = 1;
106
106
  var DEFAULT_RETRIES = 3;
107
- var VERSION = "v0.2.15";
107
+ var VERSION = "v0.2.17";
108
108
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
109
109
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
110
110
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -634,6 +634,7 @@ var triggerFirstInvocation = async (params) => {
634
634
  workflowUrl: workflowContext.url,
635
635
  failureUrl: workflowContext.failureUrl,
636
636
  retries: workflowContext.retries,
637
+ retryDelay: workflowContext.retryDelay,
637
638
  telemetry,
638
639
  flowControl: workflowContext.flowControl,
639
640
  useJSONContent: useJSONContent ?? false
@@ -763,6 +764,7 @@ var handleThirdPartyCallResult = async ({
763
764
  workflowUrl,
764
765
  failureUrl,
765
766
  retries,
767
+ retryDelay,
766
768
  telemetry,
767
769
  flowControl,
768
770
  debug
@@ -833,6 +835,7 @@ ${atob(callbackMessage.body ?? "")}`
833
835
  workflowUrl,
834
836
  failureUrl,
835
837
  retries,
838
+ retryDelay,
836
839
  telemetry,
837
840
  flowControl
838
841
  },
@@ -983,7 +986,8 @@ var BaseLazyStep = class _BaseLazyStep {
983
986
  workflowRunId: context.workflowRunId,
984
987
  workflowUrl: context.url,
985
988
  failureUrl: context.failureUrl,
986
- retries: context.retries,
989
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
990
+ retryDelay: context.retryDelay,
987
991
  useJSONContent: false,
988
992
  telemetry,
989
993
  flowControl: context.flowControl
@@ -1002,6 +1006,9 @@ var BaseLazyStep = class _BaseLazyStep {
1002
1006
  body,
1003
1007
  headers,
1004
1008
  method: "POST",
1009
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1010
+ retryDelay: context.retryDelay,
1011
+ flowControl: context.flowControl,
1005
1012
  url: context.url
1006
1013
  }
1007
1014
  ]);
@@ -1072,6 +1079,9 @@ var LazySleepStep = class extends BaseLazyStep {
1072
1079
  headers,
1073
1080
  method: "POST",
1074
1081
  url: context.url,
1082
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1083
+ retryDelay: context.retryDelay,
1084
+ flowControl: context.flowControl,
1075
1085
  delay: isParallel ? void 0 : this.sleep
1076
1086
  }
1077
1087
  ]);
@@ -1114,6 +1124,9 @@ var LazySleepUntilStep = class extends BaseLazyStep {
1114
1124
  headers,
1115
1125
  method: "POST",
1116
1126
  url: context.url,
1127
+ retries: DEFAULT_RETRIES === context.retries ? void 0 : context.retries,
1128
+ retryDelay: context.retryDelay,
1129
+ flowControl: context.flowControl,
1117
1130
  notBefore: isParallel ? void 0 : this.sleepUntil
1118
1131
  }
1119
1132
  ]);
@@ -1125,17 +1138,19 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1125
1138
  body;
1126
1139
  headers;
1127
1140
  retries;
1141
+ retryDelay;
1128
1142
  timeout;
1129
1143
  flowControl;
1130
1144
  stepType = "Call";
1131
1145
  allowUndefinedOut = false;
1132
- constructor(stepName, url, method, body, headers, retries, timeout, flowControl) {
1146
+ constructor(stepName, url, method, body, headers, retries, retryDelay, timeout, flowControl) {
1133
1147
  super(stepName);
1134
1148
  this.url = url;
1135
1149
  this.method = method;
1136
1150
  this.body = body;
1137
1151
  this.headers = headers;
1138
1152
  this.retries = retries;
1153
+ this.retryDelay = retryDelay;
1139
1154
  this.timeout = timeout;
1140
1155
  this.flowControl = flowControl;
1141
1156
  }
@@ -1210,6 +1225,9 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1210
1225
  getHeaders({ context, telemetry, invokeCount, step }) {
1211
1226
  const { headers, contentType } = super.getHeaders({ context, telemetry, invokeCount, step });
1212
1227
  headers["Upstash-Retries"] = this.retries.toString();
1228
+ if (this.retryDelay) {
1229
+ headers["Upstash-Retry-Delay"] = this.retryDelay;
1230
+ }
1213
1231
  headers[WORKFLOW_FEATURE_HEADER] = "WF_NoDelete,InitialBody";
1214
1232
  if (this.flowControl) {
1215
1233
  const { flowControlKey, flowControlValue } = prepareFlowControl(this.flowControl);
@@ -1231,7 +1249,7 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1231
1249
  "Upstash-Callback-Workflow-CallType": "fromCallback",
1232
1250
  "Upstash-Callback-Workflow-Init": "false",
1233
1251
  "Upstash-Callback-Workflow-Url": context.url,
1234
- "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody",
1252
+ "Upstash-Callback-Feature-Set": "LazyFetch,InitialBody,WF_DetectTrigger",
1235
1253
  "Upstash-Callback-Forward-Upstash-Workflow-Callback": "true",
1236
1254
  "Upstash-Callback-Forward-Upstash-Workflow-StepId": step.stepId.toString(),
1237
1255
  "Upstash-Callback-Forward-Upstash-Workflow-StepName": this.stepName,
@@ -1249,7 +1267,10 @@ var LazyCallStep = class _LazyCallStep extends BaseLazyStep {
1249
1267
  headers,
1250
1268
  body: JSON.stringify(this.body),
1251
1269
  method: this.method,
1252
- url: this.url
1270
+ url: this.url,
1271
+ retries: DEFAULT_RETRIES === this.retries ? void 0 : this.retries,
1272
+ retryDelay: this.retryDelay,
1273
+ flowControl: this.flowControl
1253
1274
  }
1254
1275
  ]);
1255
1276
  }
@@ -1378,6 +1399,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1378
1399
  headers = {},
1379
1400
  workflowRunId,
1380
1401
  retries,
1402
+ retryDelay,
1381
1403
  flowControl
1382
1404
  }) {
1383
1405
  super(stepName);
@@ -1387,6 +1409,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1387
1409
  headers,
1388
1410
  workflowRunId: getWorkflowRunId(workflowRunId),
1389
1411
  retries,
1412
+ retryDelay,
1390
1413
  flowControl
1391
1414
  };
1392
1415
  const { workflowId } = workflow;
@@ -1431,6 +1454,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1431
1454
  workflowUrl: context.url,
1432
1455
  failureUrl: context.failureUrl,
1433
1456
  retries: context.retries,
1457
+ retryDelay: context.retryDelay,
1434
1458
  telemetry,
1435
1459
  flowControl: context.flowControl,
1436
1460
  useJSONContent: false
@@ -1456,11 +1480,13 @@ var LazyInvokeStep = class extends BaseLazyStep {
1456
1480
  headers = {},
1457
1481
  workflowRunId = getWorkflowRunId(),
1458
1482
  retries,
1483
+ retryDelay,
1459
1484
  flowControl
1460
1485
  } = this.params;
1461
1486
  const newUrl = context.url.replace(/[^/]+$/, this.workflowId);
1462
1487
  const {
1463
1488
  retries: workflowRetries,
1489
+ retryDelay: workflowRetryDelay,
1464
1490
  failureFunction,
1465
1491
  failureUrl,
1466
1492
  useJSONContent,
@@ -1472,6 +1498,7 @@ var LazyInvokeStep = class extends BaseLazyStep {
1472
1498
  workflowRunId,
1473
1499
  workflowUrl: newUrl,
1474
1500
  retries: retries ?? workflowRetries,
1501
+ retryDelay: retryDelay ?? workflowRetryDelay,
1475
1502
  telemetry,
1476
1503
  failureUrl: failureFunction ? newUrl : failureUrl,
1477
1504
  flowControl: flowControl ?? workflowFlowControl,
@@ -1538,6 +1565,7 @@ var WorkflowHeaders = class {
1538
1565
  getHeaders() {
1539
1566
  this.addBaseHeaders();
1540
1567
  this.addRetries();
1568
+ this.addRetryDelay();
1541
1569
  this.addFlowControl();
1542
1570
  this.addUserHeaders();
1543
1571
  this.addInvokeCount();
@@ -1551,7 +1579,7 @@ var WorkflowHeaders = class {
1551
1579
  [WORKFLOW_INIT_HEADER]: this.initHeaderValue,
1552
1580
  [WORKFLOW_ID_HEADER]: this.workflowConfig.workflowRunId,
1553
1581
  [WORKFLOW_URL_HEADER]: this.workflowConfig.workflowUrl,
1554
- [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody",
1582
+ [WORKFLOW_FEATURE_HEADER]: "LazyFetch,InitialBody,WF_DetectTrigger",
1555
1583
  [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
1556
1584
  ...this.workflowConfig.telemetry ? getTelemetryHeaders(this.workflowConfig.telemetry) : {},
1557
1585
  ...this.workflowConfig.telemetry && this.stepInfo?.lazyStep instanceof LazyCallStep && this.stepInfo.lazyStep.headers[AGENT_NAME_HEADER] ? { [TELEMETRY_HEADER_AGENT]: "true" } : {}
@@ -1583,6 +1611,16 @@ var WorkflowHeaders = class {
1583
1611
  this.headers.failureHeaders["Retries"] = retries;
1584
1612
  }
1585
1613
  }
1614
+ addRetryDelay() {
1615
+ if (this.workflowConfig.retryDelay === void 0 || this.workflowConfig.retryDelay === "") {
1616
+ return;
1617
+ }
1618
+ const retryDelay = this.workflowConfig.retryDelay.toString();
1619
+ this.headers.workflowHeaders["Retry-Delay"] = retryDelay;
1620
+ if (this.workflowConfig.failureUrl) {
1621
+ this.headers.failureHeaders["Retry-Delay"] = retryDelay;
1622
+ }
1623
+ }
1586
1624
  addFlowControl() {
1587
1625
  if (!this.workflowConfig.flowControl) {
1588
1626
  return;
@@ -1617,10 +1655,13 @@ var WorkflowHeaders = class {
1617
1655
  this.headers.failureHeaders["Workflow-Init"] = "false";
1618
1656
  this.headers.failureHeaders["Workflow-Url"] = this.workflowConfig.workflowUrl;
1619
1657
  this.headers.failureHeaders["Workflow-Calltype"] = "failureCall";
1620
- this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody";
1658
+ this.headers.failureHeaders["Feature-Set"] = "LazyFetch,InitialBody,WF_DetectTrigger";
1621
1659
  if (this.workflowConfig.retries !== void 0 && this.workflowConfig.retries !== DEFAULT_RETRIES) {
1622
1660
  this.headers.failureHeaders["Retries"] = this.workflowConfig.retries.toString();
1623
1661
  }
1662
+ if (this.workflowConfig.retryDelay !== void 0 && this.workflowConfig.retryDelay !== "") {
1663
+ this.headers.failureHeaders["Retry-Delay"] = this.workflowConfig.retryDelay.toString();
1664
+ }
1624
1665
  }
1625
1666
  addContentType() {
1626
1667
  if (this.workflowConfig.useJSONContent) {
@@ -1702,6 +1743,7 @@ var submitParallelSteps = async ({
1702
1743
  workflowUrl: context.url,
1703
1744
  failureUrl: context.failureUrl,
1704
1745
  retries: context.retries,
1746
+ retryDelay: context.retryDelay,
1705
1747
  flowControl: context.flowControl,
1706
1748
  telemetry
1707
1749
  },
@@ -2122,7 +2164,7 @@ var BaseWorkflowApi = class {
2122
2164
  */
2123
2165
  async callApi(stepName, settings) {
2124
2166
  const { url, appendHeaders, method } = getProviderInfo(settings.api);
2125
- const { method: userMethod, body, headers = {}, retries = 0, timeout } = settings;
2167
+ const { method: userMethod, body, headers = {}, retries = 0, retryDelay, timeout } = settings;
2126
2168
  return await this.context.call(stepName, {
2127
2169
  url,
2128
2170
  method: userMethod ?? method,
@@ -2132,6 +2174,7 @@ var BaseWorkflowApi = class {
2132
2174
  ...headers
2133
2175
  },
2134
2176
  retries,
2177
+ retryDelay,
2135
2178
  timeout
2136
2179
  });
2137
2180
  }
@@ -2221,6 +2264,7 @@ var fetchWithContextCall = async (context, agentCallParams, ...params) => {
2221
2264
  body,
2222
2265
  timeout: agentCallParams?.timeout,
2223
2266
  retries: agentCallParams?.retries,
2267
+ retryDelay: agentCallParams?.retryDelay,
2224
2268
  flowControl: agentCallParams?.flowControl
2225
2269
  });
2226
2270
  const responseHeaders = new Headers(
@@ -2665,6 +2709,37 @@ var WorkflowContext = class {
2665
2709
  * Number of retries
2666
2710
  */
2667
2711
  retries;
2712
+ /**
2713
+ * Delay between retries.
2714
+ *
2715
+ * By default, the `retryDelay` is exponential backoff.
2716
+ * More details can be found in: https://upstash.com/docs/qstash/features/retry.
2717
+ *
2718
+ * The `retryDelay` option allows you to customize the delay (in milliseconds) between retry attempts when message delivery fails.
2719
+ *
2720
+ * You can use mathematical expressions and the following built-in functions to calculate the delay dynamically.
2721
+ * The special variable `retried` represents the current retry attempt count (starting from 0).
2722
+ *
2723
+ * Supported functions:
2724
+ * - `pow`
2725
+ * - `sqrt`
2726
+ * - `abs`
2727
+ * - `exp`
2728
+ * - `floor`
2729
+ * - `ceil`
2730
+ * - `round`
2731
+ * - `min`
2732
+ * - `max`
2733
+ *
2734
+ * Examples of valid `retryDelay` values:
2735
+ * ```ts
2736
+ * 1000 // 1 second
2737
+ * 1000 * (1 + retried) // 1 second multiplied by the current retry attempt
2738
+ * pow(2, retried) // 2 to the power of the current retry attempt
2739
+ * max(10, pow(2, retried)) // The greater of 10 or 2^retried
2740
+ * ```
2741
+ */
2742
+ retryDelay;
2668
2743
  /**
2669
2744
  * Settings for controlling the number of active requests
2670
2745
  * and number of requests per second with the same key.
@@ -2681,6 +2756,7 @@ var WorkflowContext = class {
2681
2756
  initialPayload,
2682
2757
  env,
2683
2758
  retries,
2759
+ retryDelay,
2684
2760
  telemetry,
2685
2761
  invokeCount,
2686
2762
  flowControl
@@ -2694,6 +2770,7 @@ var WorkflowContext = class {
2694
2770
  this.requestPayload = initialPayload;
2695
2771
  this.env = env ?? {};
2696
2772
  this.retries = retries ?? DEFAULT_RETRIES;
2773
+ this.retryDelay = retryDelay;
2697
2774
  this.flowControl = flowControl;
2698
2775
  this.executor = new AutoExecutor(this, this.steps, telemetry, invokeCount, debug);
2699
2776
  }
@@ -2775,6 +2852,7 @@ var WorkflowContext = class {
2775
2852
  settings.body,
2776
2853
  settings.headers || {},
2777
2854
  settings.retries || 0,
2855
+ settings.retryDelay,
2778
2856
  settings.timeout,
2779
2857
  settings.flowControl ?? settings.workflow.options.flowControl
2780
2858
  );
@@ -2785,6 +2863,7 @@ var WorkflowContext = class {
2785
2863
  body,
2786
2864
  headers = {},
2787
2865
  retries = 0,
2866
+ retryDelay,
2788
2867
  timeout,
2789
2868
  flowControl
2790
2869
  } = settings;
@@ -2795,6 +2874,7 @@ var WorkflowContext = class {
2795
2874
  body,
2796
2875
  headers,
2797
2876
  retries,
2877
+ retryDelay,
2798
2878
  timeout,
2799
2879
  flowControl
2800
2880
  );
@@ -2805,7 +2885,7 @@ var WorkflowContext = class {
2805
2885
  * Pauses workflow execution until a specific event occurs or a timeout is reached.
2806
2886
  *
2807
2887
  *```ts
2808
- * const result = await workflow.waitForEvent("payment-confirmed", {
2888
+ * const result = await workflow.waitForEvent("payment-confirmed", "payment.confirmed", {
2809
2889
  * timeout: "5m"
2810
2890
  * });
2811
2891
  *```
@@ -2831,7 +2911,7 @@ var WorkflowContext = class {
2831
2911
  * @param stepName
2832
2912
  * @param eventId - Unique identifier for the event to wait for
2833
2913
  * @param options - Configuration options.
2834
- * @returns `{ timeout: boolean, eventData: unknown }`.
2914
+ * @returns `{ timeout: boolean, eventData: TEventData }`.
2835
2915
  * The `timeout` property specifies if the workflow has timed out. The `eventData`
2836
2916
  * is the data passed when notifying this workflow of an event.
2837
2917
  */
@@ -2991,6 +3071,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2991
3071
  initialPayload: context.requestPayload,
2992
3072
  env: context.env,
2993
3073
  retries: context.retries,
3074
+ retryDelay: context.retryDelay,
2994
3075
  flowControl: context.flowControl
2995
3076
  });
2996
3077
  try {
@@ -2999,6 +3080,9 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2999
3080
  if (error instanceof WorkflowAbort && error.stepName === this.disabledMessage || error instanceof WorkflowNonRetryableError) {
3000
3081
  return ok("step-found");
3001
3082
  }
3083
+ console.warn(
3084
+ "Upstash Workflow: Received an error while authorizing request. Please avoid throwing errors before the first step of your workflow."
3085
+ );
3002
3086
  return err(error);
3003
3087
  }
3004
3088
  return ok("run-ended");
@@ -3140,9 +3224,9 @@ var parseRequest = async (requestPayload, isFirstInvocation, workflowRunId, requ
3140
3224
  };
3141
3225
  }
3142
3226
  };
3143
- var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, flowControl, debug) => {
3227
+ var handleFailure = async (request, requestPayload, qstashClient, initialPayloadParser, routeFunction, failureFunction, env, retries, retryDelay, flowControl, debug) => {
3144
3228
  if (request.headers.get(WORKFLOW_FAILURE_HEADER) !== "true") {
3145
- return ok("not-failure-callback");
3229
+ return ok({ result: "not-failure-callback" });
3146
3230
  }
3147
3231
  if (!failureFunction) {
3148
3232
  return err(
@@ -3154,7 +3238,17 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3154
3238
  try {
3155
3239
  const { status, header, body, url, sourceBody, workflowRunId } = JSON.parse(requestPayload);
3156
3240
  const decodedBody = body ? decodeBase64(body) : "{}";
3157
- const errorPayload = JSON.parse(decodedBody);
3241
+ let errorMessage = "";
3242
+ try {
3243
+ const errorPayload = JSON.parse(decodedBody);
3244
+ if (errorPayload.message) {
3245
+ errorMessage = errorPayload.message;
3246
+ }
3247
+ } catch {
3248
+ }
3249
+ if (!errorMessage) {
3250
+ errorMessage = `Couldn't parse 'failResponse' in 'failureFunction', received: '${decodedBody}'`;
3251
+ }
3158
3252
  const workflowContext = new WorkflowContext({
3159
3253
  qstashClient,
3160
3254
  workflowRunId,
@@ -3166,6 +3260,7 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3166
3260
  debug,
3167
3261
  env,
3168
3262
  retries,
3263
+ retryDelay,
3169
3264
  flowControl,
3170
3265
  telemetry: void 0
3171
3266
  // not going to make requests in authentication check
@@ -3180,16 +3275,16 @@ var handleFailure = async (request, requestPayload, qstashClient, initialPayload
3180
3275
  } else if (authCheck.value === "run-ended") {
3181
3276
  return err(new WorkflowError("Not authorized to run the failure function."));
3182
3277
  }
3183
- await failureFunction({
3278
+ const failureResponse = await failureFunction({
3184
3279
  context: workflowContext,
3185
3280
  failStatus: status,
3186
- failResponse: errorPayload.message,
3281
+ failResponse: errorMessage,
3187
3282
  failHeaders: header
3188
3283
  });
3284
+ return ok({ result: "is-failure-callback", response: failureResponse });
3189
3285
  } catch (error) {
3190
3286
  return err(error);
3191
3287
  }
3192
- return ok("is-failure-callback");
3193
3288
  };
3194
3289
 
3195
3290
  // src/serve/options.ts
@@ -3205,8 +3300,8 @@ var processOptions = (options) => {
3205
3300
  baseUrl: environment.QSTASH_URL,
3206
3301
  token: environment.QSTASH_TOKEN
3207
3302
  }),
3208
- onStepFinish: (workflowRunId, finishCondition) => {
3209
- if (finishCondition === "auth-fail") {
3303
+ onStepFinish: (workflowRunId, _finishCondition, detailedFinishCondition) => {
3304
+ if (detailedFinishCondition?.condition === "auth-fail") {
3210
3305
  console.error(AUTH_FAIL_MESSAGE);
3211
3306
  return new Response(
3212
3307
  JSON.stringify({
@@ -3214,19 +3309,33 @@ var processOptions = (options) => {
3214
3309
  workflowRunId
3215
3310
  }),
3216
3311
  {
3217
- status: 400
3312
+ status: 400,
3313
+ headers: {
3314
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3315
+ }
3218
3316
  }
3219
3317
  );
3220
- } else if (finishCondition instanceof WorkflowNonRetryableError) {
3221
- return new Response(JSON.stringify(formatWorkflowError(finishCondition)), {
3318
+ } else if (detailedFinishCondition?.condition === "non-retryable-error") {
3319
+ return new Response(JSON.stringify(formatWorkflowError(detailedFinishCondition.result)), {
3222
3320
  headers: {
3223
- "Upstash-NonRetryable-Error": "true"
3321
+ "Upstash-NonRetryable-Error": "true",
3322
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3224
3323
  },
3225
3324
  status: 489
3226
3325
  });
3326
+ } else if (detailedFinishCondition?.condition === "failure-callback") {
3327
+ return new Response(detailedFinishCondition.result ?? void 0, {
3328
+ status: 200,
3329
+ headers: {
3330
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3331
+ }
3332
+ });
3227
3333
  }
3228
3334
  return new Response(JSON.stringify({ workflowRunId }), {
3229
- status: 200
3335
+ status: 200,
3336
+ headers: {
3337
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3338
+ }
3230
3339
  });
3231
3340
  },
3232
3341
  initialPayloadParser: (initialRequest) => {
@@ -3300,6 +3409,7 @@ var serveBase = (routeFunction, telemetry, options) => {
3300
3409
  baseUrl,
3301
3410
  env,
3302
3411
  retries,
3412
+ retryDelay,
3303
3413
  useJSONContent,
3304
3414
  disableTelemetry,
3305
3415
  flowControl,
@@ -3330,10 +3440,14 @@ var serveBase = (routeFunction, telemetry, options) => {
3330
3440
  debug
3331
3441
  );
3332
3442
  if (workflowRunEnded) {
3333
- return onStepFinish(workflowRunId, "workflow-already-ended");
3443
+ return onStepFinish(workflowRunId, "workflow-already-ended", {
3444
+ condition: "workflow-already-ended"
3445
+ });
3334
3446
  }
3335
3447
  if (isLastDuplicate) {
3336
- return onStepFinish(workflowRunId, "duplicate-step");
3448
+ return onStepFinish(workflowRunId, "duplicate-step", {
3449
+ condition: "duplicate-step"
3450
+ });
3337
3451
  }
3338
3452
  const failureCheck = await handleFailure(
3339
3453
  request,
@@ -3344,14 +3458,18 @@ var serveBase = (routeFunction, telemetry, options) => {
3344
3458
  failureFunction,
3345
3459
  env,
3346
3460
  retries,
3461
+ retryDelay,
3347
3462
  flowControl,
3348
3463
  debug
3349
3464
  );
3350
3465
  if (failureCheck.isErr()) {
3351
3466
  throw failureCheck.error;
3352
- } else if (failureCheck.value === "is-failure-callback") {
3467
+ } else if (failureCheck.value.result === "is-failure-callback") {
3353
3468
  await debug?.log("WARN", "RESPONSE_DEFAULT", "failureFunction executed");
3354
- return onStepFinish(workflowRunId, "failure-callback");
3469
+ return onStepFinish(workflowRunId, "failure-callback", {
3470
+ condition: "failure-callback",
3471
+ result: failureCheck.value.response
3472
+ });
3355
3473
  }
3356
3474
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
3357
3475
  const workflowContext = new WorkflowContext({
@@ -3365,6 +3483,7 @@ var serveBase = (routeFunction, telemetry, options) => {
3365
3483
  debug,
3366
3484
  env,
3367
3485
  retries,
3486
+ retryDelay,
3368
3487
  telemetry,
3369
3488
  invokeCount,
3370
3489
  flowControl
@@ -3380,7 +3499,8 @@ var serveBase = (routeFunction, telemetry, options) => {
3380
3499
  await debug?.log("ERROR", "ERROR", { error: AUTH_FAIL_MESSAGE });
3381
3500
  return onStepFinish(
3382
3501
  isFirstInvocation ? "no-workflow-id" : workflowContext.workflowRunId,
3383
- "auth-fail"
3502
+ "auth-fail",
3503
+ { condition: "auth-fail" }
3384
3504
  );
3385
3505
  }
3386
3506
  const callReturnCheck = await handleThirdPartyCallResult({
@@ -3390,6 +3510,7 @@ var serveBase = (routeFunction, telemetry, options) => {
3390
3510
  workflowUrl,
3391
3511
  failureUrl: workflowFailureUrl,
3392
3512
  retries,
3513
+ retryDelay,
3393
3514
  flowControl,
3394
3515
  telemetry,
3395
3516
  debug
@@ -3417,19 +3538,28 @@ var serveBase = (routeFunction, telemetry, options) => {
3417
3538
  debug
3418
3539
  });
3419
3540
  if (result.isOk() && result.value instanceof WorkflowNonRetryableError) {
3420
- return onStepFinish(workflowRunId, result.value);
3541
+ return onStepFinish(workflowRunId, result.value, {
3542
+ condition: "non-retryable-error",
3543
+ result: result.value
3544
+ });
3421
3545
  }
3422
3546
  if (result.isErr()) {
3423
3547
  await debug?.log("ERROR", "ERROR", { error: result.error.message });
3424
3548
  throw result.error;
3425
3549
  }
3426
3550
  await debug?.log("INFO", "RESPONSE_WORKFLOW");
3427
- return onStepFinish(workflowContext.workflowRunId, "success");
3551
+ return onStepFinish(workflowContext.workflowRunId, "success", {
3552
+ condition: "success"
3553
+ });
3428
3554
  } else if (callReturnCheck.value === "workflow-ended") {
3429
- return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended");
3555
+ return onStepFinish(workflowContext.workflowRunId, "workflow-already-ended", {
3556
+ condition: "workflow-already-ended"
3557
+ });
3430
3558
  }
3431
3559
  await debug?.log("INFO", "RESPONSE_DEFAULT");
3432
- return onStepFinish("no-workflow-id", "fromCallback");
3560
+ return onStepFinish("no-workflow-id", "fromCallback", {
3561
+ condition: "fromCallback"
3562
+ });
3433
3563
  };
3434
3564
  const safeHandler = async (request) => {
3435
3565
  try {
@@ -3444,11 +3574,17 @@ var serveBase = (routeFunction, telemetry, options) => {
3444
3574
  Original error: '${formattedError.message}'`;
3445
3575
  console.error(errorMessage);
3446
3576
  return new Response(errorMessage, {
3447
- status: 500
3577
+ status: 500,
3578
+ headers: {
3579
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3580
+ }
3448
3581
  });
3449
3582
  }
3450
3583
  return new Response(JSON.stringify(formattedError), {
3451
- status: 500
3584
+ status: 500,
3585
+ headers: {
3586
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3587
+ }
3452
3588
  });
3453
3589
  }
3454
3590
  };
@@ -3523,6 +3659,20 @@ var DLQ = class _DLQ {
3523
3659
  }
3524
3660
  return workflowRuns[0];
3525
3661
  }
3662
+ /**
3663
+ * Retry the failure callback of a workflow run whose failureUrl/failureFunction
3664
+ * request has failed.
3665
+ *
3666
+ * @param dlqId - The ID of the DLQ message to retry.
3667
+ * @returns
3668
+ */
3669
+ async retryFailureFunction({ dlqId }) {
3670
+ const response = await this.client.http.request({
3671
+ path: ["v2", "workflows", "dlq", "callback", dlqId],
3672
+ method: "POST"
3673
+ });
3674
+ return response;
3675
+ }
3526
3676
  static handleDLQOptions(options) {
3527
3677
  const { dlqId, flowControl, retries } = options;
3528
3678
  const headers = {};
@@ -3681,13 +3831,14 @@ var Client4 = class {
3681
3831
  const finalWorkflowRunId = getWorkflowRunId(option.workflowRunId);
3682
3832
  const context = new WorkflowContext({
3683
3833
  qstashClient: this.client,
3684
- // @ts-expect-error headers type mismatch
3834
+ // @ts-expect-error header type mismatch because of bun
3685
3835
  headers: new Headers(option.headers ?? {}),
3686
3836
  initialPayload: option.body,
3687
3837
  steps: [],
3688
3838
  url: option.url,
3689
3839
  workflowRunId: finalWorkflowRunId,
3690
3840
  retries: option.retries,
3841
+ retryDelay: option.retryDelay,
3691
3842
  telemetry: { sdk: SDK_TELEMETRY },
3692
3843
  flowControl: option.flowControl,
3693
3844
  failureUrl
package/index.mjs CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  prepareFlowControl,
14
14
  serve,
15
15
  triggerFirstInvocation
16
- } from "./chunk-AC5CQCN3.mjs";
16
+ } from "./chunk-RP7G4UD5.mjs";
17
17
 
18
18
  // src/client/index.ts
19
19
  import { Client as QStashClient } from "@upstash/qstash";
@@ -73,6 +73,20 @@ var DLQ = class _DLQ {
73
73
  }
74
74
  return workflowRuns[0];
75
75
  }
76
+ /**
77
+ * Retry the failure callback of a workflow run whose failureUrl/failureFunction
78
+ * request has failed.
79
+ *
80
+ * @param dlqId - The ID of the DLQ message to retry.
81
+ * @returns
82
+ */
83
+ async retryFailureFunction({ dlqId }) {
84
+ const response = await this.client.http.request({
85
+ path: ["v2", "workflows", "dlq", "callback", dlqId],
86
+ method: "POST"
87
+ });
88
+ return response;
89
+ }
76
90
  static handleDLQOptions(options) {
77
91
  const { dlqId, flowControl, retries } = options;
78
92
  const headers = {};
@@ -231,13 +245,14 @@ var Client = class {
231
245
  const finalWorkflowRunId = getWorkflowRunId(option.workflowRunId);
232
246
  const context = new WorkflowContext({
233
247
  qstashClient: this.client,
234
- // @ts-expect-error headers type mismatch
248
+ // @ts-expect-error header type mismatch because of bun
235
249
  headers: new Headers(option.headers ?? {}),
236
250
  initialPayload: option.body,
237
251
  steps: [],
238
252
  url: option.url,
239
253
  workflowRunId: finalWorkflowRunId,
240
254
  retries: option.retries,
255
+ retryDelay: option.retryDelay,
241
256
  telemetry: { sdk: SDK_TELEMETRY },
242
257
  flowControl: option.flowControl,
243
258
  failureUrl
package/nextjs.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
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--R_3XZXz.mjs';
3
+ import { s as serveManyBase } from './serve-many-DgDSOvQs.mjs';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';
package/nextjs.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
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--R_3XZXz.js';
3
+ import { s as serveManyBase } from './serve-many-B3DfoTFt.js';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
  import 'ai';