@upstash/workflow 1.3.0 → 1.3.2-rc

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 -2
  2. package/astro.d.ts +2 -2
  3. package/astro.js +81 -14
  4. package/astro.mjs +1 -1
  5. package/{chunk-G24J5PCC.mjs → chunk-ICDNN4UW.mjs} +84 -14
  6. package/cloudflare.d.mts +2 -2
  7. package/cloudflare.d.ts +2 -2
  8. package/cloudflare.js +81 -14
  9. package/cloudflare.mjs +1 -1
  10. package/express.d.mts +2 -2
  11. package/express.d.ts +2 -2
  12. package/express.js +81 -14
  13. package/express.mjs +1 -1
  14. package/h3.d.mts +2 -2
  15. package/h3.d.ts +2 -2
  16. package/h3.js +81 -14
  17. package/h3.mjs +1 -1
  18. package/hono.d.mts +2 -2
  19. package/hono.d.ts +2 -2
  20. package/hono.js +81 -14
  21. package/hono.mjs +1 -1
  22. package/index.d.mts +43 -7
  23. package/index.d.ts +43 -7
  24. package/index.js +84 -15
  25. package/index.mjs +8 -3
  26. package/nextjs.d.mts +2 -2
  27. package/nextjs.d.ts +2 -2
  28. package/nextjs.js +81 -14
  29. package/nextjs.mjs +1 -1
  30. package/package.json +1 -1
  31. package/react-router.d.mts +2 -2
  32. package/react-router.d.ts +2 -2
  33. package/react-router.js +81 -14
  34. package/react-router.mjs +1 -1
  35. package/{serve-many-D3D9uE4u.d.mts → serve-many-CG3BFvO3.d.mts} +1 -1
  36. package/{serve-many-kPOasiyb.d.ts → serve-many-iJF1IUXk.d.ts} +1 -1
  37. package/solidjs.d.mts +1 -1
  38. package/solidjs.d.ts +1 -1
  39. package/solidjs.js +81 -14
  40. package/solidjs.mjs +1 -1
  41. package/svelte.d.mts +2 -2
  42. package/svelte.d.ts +2 -2
  43. package/svelte.js +81 -14
  44. package/svelte.mjs +1 -1
  45. package/tanstack.d.mts +2 -2
  46. package/tanstack.d.ts +2 -2
  47. package/tanstack.js +81 -14
  48. package/tanstack.mjs +1 -1
  49. package/{types-B_E1VAK6.d.ts → types-CekOpKvz.d.mts} +14 -6
  50. package/{types-B_E1VAK6.d.mts → types-CekOpKvz.d.ts} +14 -6
package/express.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as express_serve_static_core from 'express-serve-static-core';
2
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
2
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
3
3
  import { Router } from 'express';
4
- import { s as serveManyBase } from './serve-many-D3D9uE4u.mjs';
4
+ import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
 
package/express.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as express_serve_static_core from 'express-serve-static-core';
2
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.js';
2
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
3
3
  import { Router } from 'express';
4
- import { s as serveManyBase } from './serve-many-kPOasiyb.js';
4
+ import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
 
package/express.js CHANGED
@@ -39,12 +39,13 @@ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
39
39
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
40
40
  var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
41
41
  var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
42
+ var WORKFLOW_ERROR_STEP_NAME_HEADER = "Upstash-Error-Step-Name";
42
43
  var WORKFLOW_PROTOCOL_VERSION = "1";
43
44
  var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
44
45
  var DEFAULT_CONTENT_TYPE = "application/json";
45
46
  var NO_CONCURRENCY = 1;
46
47
  var DEFAULT_RETRIES = 3;
47
- var VERSION = "v1.2.1";
48
+ var VERSION = "v1.3.2";
48
49
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
49
50
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
50
51
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -127,6 +128,22 @@ var formatWorkflowError = (error) => {
127
128
  message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
128
129
  };
129
130
  };
131
+ var attachStepNameToError = (error, stepName) => {
132
+ if (typeof error !== "object" || error === null) return;
133
+ if ("errorStepName" in error) return;
134
+ if (!Object.isExtensible(error)) return;
135
+ try {
136
+ error.errorStepName = stepName;
137
+ } catch {
138
+ }
139
+ };
140
+ var getStepNameFromError = (error) => {
141
+ if (typeof error === "object" && error !== null) {
142
+ const stepName = error.errorStepName;
143
+ return typeof stepName === "string" ? stepName : void 0;
144
+ }
145
+ return void 0;
146
+ };
130
147
  function getConstructorName(obj) {
131
148
  if (obj === null || obj === void 0) {
132
149
  return null;
@@ -216,6 +233,31 @@ var import_qstash4 = require("@upstash/qstash");
216
233
  // src/utils.ts
217
234
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
218
235
  var NANOID_LENGTH = 21;
236
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
237
+ function validateLabel(label) {
238
+ if (label === void 0) return;
239
+ const labels = Array.isArray(label) ? label : [label];
240
+ if (labels.length === 0) {
241
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
242
+ }
243
+ for (const value of labels) {
244
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
245
+ throw new WorkflowNonRetryableError(
246
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
247
+ );
248
+ }
249
+ }
250
+ }
251
+ function serializeLabel(label) {
252
+ return Array.isArray(label) ? label.join(",") : label;
253
+ }
254
+ function validateFlowControl(flowControl) {
255
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
256
+ throw new WorkflowNonRetryableError(
257
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
258
+ );
259
+ }
260
+ }
219
261
  function getRandomInt() {
220
262
  return Math.floor(Math.random() * NANOID_CHARS.length);
221
263
  }
@@ -751,8 +793,8 @@ var triggerFirstInvocation = async (params) => {
751
793
  if (unknownSdk) {
752
794
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
753
795
  }
754
- if (workflowContext.label) {
755
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
796
+ if (workflowContext.labels.length > 0) {
797
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
756
798
  }
757
799
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
758
800
  return {
@@ -1554,8 +1596,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1554
1596
  });
1555
1597
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1556
1598
  if (label) {
1557
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1558
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1599
+ const labelHeader = serializeLabel(label);
1600
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1601
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1559
1602
  }
1560
1603
  return { headers: triggerHeaders, contentType };
1561
1604
  }
@@ -1898,7 +1941,13 @@ var submitSingleStep = async ({
1898
1941
  await dispatchLifecycle("beforeExecution", {
1899
1942
  stepName: lazyStep.stepName
1900
1943
  });
1901
- const resultStep = await lazyStep.getResultStep(concurrency, stepId);
1944
+ let resultStep;
1945
+ try {
1946
+ resultStep = await lazyStep.getResultStep(concurrency, stepId);
1947
+ } catch (error) {
1948
+ attachStepNameToError(error, lazyStep.stepName);
1949
+ throw error;
1950
+ }
1902
1951
  const { headers } = lazyStep.getHeaders({
1903
1952
  context,
1904
1953
  step: resultStep,
@@ -2121,9 +2170,11 @@ var AutoExecutor = class _AutoExecutor {
2121
2170
  if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400 || isInstanceOf(error, import_qstash5.QstashError) && error.status === 412) {
2122
2171
  throw error;
2123
2172
  }
2124
- throw new WorkflowError(
2173
+ const wrappedError = new WorkflowError(
2125
2174
  `Error submitting steps to QStash in partial parallel step execution: ${error}`
2126
2175
  );
2176
+ attachStepNameToError(wrappedError, parallelSteps[stepIndex].stepName);
2177
+ throw wrappedError;
2127
2178
  }
2128
2179
  break;
2129
2180
  }
@@ -2696,9 +2747,10 @@ var WorkflowContext = class {
2696
2747
  */
2697
2748
  env;
2698
2749
  /**
2699
- * Label to apply to the workflow run.
2750
+ * Labels attached to the workflow run.
2700
2751
  *
2701
- * Can be used to filter the workflow run logs.
2752
+ * Can be used to filter the workflow run logs. A run can have multiple
2753
+ * labels when triggered with `label: string[]`.
2702
2754
  *
2703
2755
  * Can be set by passing a `label` parameter when triggering the workflow
2704
2756
  * with `client.trigger`:
@@ -2706,11 +2758,20 @@ var WorkflowContext = class {
2706
2758
  * ```ts
2707
2759
  * await client.trigger({
2708
2760
  * url: "https://workflow-endpoint.com",
2709
- * label: "my-label"
2761
+ * label: ["label-1", "label-2"]
2710
2762
  * });
2711
2763
  * ```
2712
2764
  */
2713
- label;
2765
+ labels;
2766
+ /**
2767
+ * Label of the workflow run.
2768
+ *
2769
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2770
+ * only returns the first one.
2771
+ */
2772
+ get label() {
2773
+ return this.labels[0];
2774
+ }
2714
2775
  /**
2715
2776
  * Number of times QStash has retried delivering the current request.
2716
2777
  *
@@ -2741,7 +2802,7 @@ var WorkflowContext = class {
2741
2802
  this.headers = headers;
2742
2803
  this.requestPayload = initialPayload;
2743
2804
  this.env = env ?? {};
2744
- this.label = label;
2805
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2745
2806
  this.retried = retried ?? 0;
2746
2807
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2747
2808
  middlewareManagerInstance.assignContext(this);
@@ -2822,8 +2883,10 @@ var WorkflowContext = class {
2822
2883
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2823
2884
  }
2824
2885
  async call(stepName, settings) {
2886
+ validateFlowControl(settings.flowControl);
2825
2887
  let callStep;
2826
2888
  if ("workflow" in settings) {
2889
+ validateLabel(settings.label);
2827
2890
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2828
2891
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2829
2892
  callStep = new LazyCallStep({
@@ -2931,6 +2994,8 @@ var WorkflowContext = class {
2931
2994
  );
2932
2995
  }
2933
2996
  async invoke(stepName, settings) {
2997
+ validateLabel(settings.label);
2998
+ validateFlowControl(settings.flowControl);
2934
2999
  return await this.addStep(
2935
3000
  new LazyInvokeStep(this, stepName, settings)
2936
3001
  );
@@ -3016,7 +3081,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3016
3081
  url: context.url,
3017
3082
  initialPayload: context.requestPayload,
3018
3083
  env: context.env,
3019
- label: context.label,
3084
+ label: context.labels,
3020
3085
  retried: context.retried
3021
3086
  });
3022
3087
  try {
@@ -3854,10 +3919,12 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
3854
3919
  await middlewareManager.dispatchDebug("onError", {
3855
3920
  error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
3856
3921
  });
3922
+ const stepName = getStepNameFromError(error)?.replace(/[\u0000-\u001F\u007F]+/g, " ").trim();
3857
3923
  return new Response(JSON.stringify(formattedError), {
3858
3924
  status: 500,
3859
3925
  headers: {
3860
- [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
3926
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
3927
+ ...stepName ? { [WORKFLOW_ERROR_STEP_NAME_HEADER]: stepName } : {}
3861
3928
  }
3862
3929
  });
3863
3930
  }
package/express.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-G24J5PCC.mjs";
5
+ } from "./chunk-ICDNN4UW.mjs";
6
6
 
7
7
  // platforms/express.ts
8
8
  import {
package/h3.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as h3 from 'h3';
2
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
3
- import { s as serveManyBase } from './serve-many-D3D9uE4u.mjs';
2
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
3
+ import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
 
package/h3.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as h3 from 'h3';
2
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.js';
3
- import { s as serveManyBase } from './serve-many-kPOasiyb.js';
2
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
3
+ import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
4
4
  import '@upstash/qstash';
5
5
  import 'zod';
6
6
 
package/h3.js CHANGED
@@ -412,6 +412,22 @@ var formatWorkflowError = (error) => {
412
412
  message: `An error occured while executing workflow: '${typeof error === "string" ? error : JSON.stringify(error)}'`
413
413
  };
414
414
  };
415
+ var attachStepNameToError = (error, stepName) => {
416
+ if (typeof error !== "object" || error === null) return;
417
+ if ("errorStepName" in error) return;
418
+ if (!Object.isExtensible(error)) return;
419
+ try {
420
+ error.errorStepName = stepName;
421
+ } catch {
422
+ }
423
+ };
424
+ var getStepNameFromError = (error) => {
425
+ if (typeof error === "object" && error !== null) {
426
+ const stepName = error.errorStepName;
427
+ return typeof stepName === "string" ? stepName : void 0;
428
+ }
429
+ return void 0;
430
+ };
415
431
  function getConstructorName(obj) {
416
432
  if (obj === null || obj === void 0) {
417
433
  return null;
@@ -505,12 +521,13 @@ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
505
521
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
506
522
  var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
507
523
  var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
524
+ var WORKFLOW_ERROR_STEP_NAME_HEADER = "Upstash-Error-Step-Name";
508
525
  var WORKFLOW_PROTOCOL_VERSION = "1";
509
526
  var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
510
527
  var DEFAULT_CONTENT_TYPE = "application/json";
511
528
  var NO_CONCURRENCY = 1;
512
529
  var DEFAULT_RETRIES = 3;
513
- var VERSION = "v1.2.1";
530
+ var VERSION = "v1.3.2";
514
531
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
515
532
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
516
533
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -525,6 +542,31 @@ var import_qstash4 = require("@upstash/qstash");
525
542
  // src/utils.ts
526
543
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
527
544
  var NANOID_LENGTH = 21;
545
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
546
+ function validateLabel(label) {
547
+ if (label === void 0) return;
548
+ const labels = Array.isArray(label) ? label : [label];
549
+ if (labels.length === 0) {
550
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
551
+ }
552
+ for (const value of labels) {
553
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
554
+ throw new WorkflowNonRetryableError(
555
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
556
+ );
557
+ }
558
+ }
559
+ }
560
+ function serializeLabel(label) {
561
+ return Array.isArray(label) ? label.join(",") : label;
562
+ }
563
+ function validateFlowControl(flowControl) {
564
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
565
+ throw new WorkflowNonRetryableError(
566
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
567
+ );
568
+ }
569
+ }
528
570
  function getRandomInt() {
529
571
  return Math.floor(Math.random() * NANOID_CHARS.length);
530
572
  }
@@ -1060,8 +1102,8 @@ var triggerFirstInvocation = async (params) => {
1060
1102
  if (unknownSdk) {
1061
1103
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
1062
1104
  }
1063
- if (workflowContext.label) {
1064
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
1105
+ if (workflowContext.labels.length > 0) {
1106
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
1065
1107
  }
1066
1108
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
1067
1109
  return {
@@ -1863,8 +1905,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1863
1905
  });
1864
1906
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1865
1907
  if (label) {
1866
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1867
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1908
+ const labelHeader = serializeLabel(label);
1909
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1910
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1868
1911
  }
1869
1912
  return { headers: triggerHeaders, contentType };
1870
1913
  }
@@ -2207,7 +2250,13 @@ var submitSingleStep = async ({
2207
2250
  await dispatchLifecycle("beforeExecution", {
2208
2251
  stepName: lazyStep.stepName
2209
2252
  });
2210
- const resultStep = await lazyStep.getResultStep(concurrency, stepId);
2253
+ let resultStep;
2254
+ try {
2255
+ resultStep = await lazyStep.getResultStep(concurrency, stepId);
2256
+ } catch (error) {
2257
+ attachStepNameToError(error, lazyStep.stepName);
2258
+ throw error;
2259
+ }
2211
2260
  const { headers } = lazyStep.getHeaders({
2212
2261
  context,
2213
2262
  step: resultStep,
@@ -2430,9 +2479,11 @@ var AutoExecutor = class _AutoExecutor {
2430
2479
  if (isInstanceOf(error, WorkflowAbort) || isInstanceOf(error, import_qstash5.QstashError) && error.status === 400 || isInstanceOf(error, import_qstash5.QstashError) && error.status === 412) {
2431
2480
  throw error;
2432
2481
  }
2433
- throw new WorkflowError(
2482
+ const wrappedError = new WorkflowError(
2434
2483
  `Error submitting steps to QStash in partial parallel step execution: ${error}`
2435
2484
  );
2485
+ attachStepNameToError(wrappedError, parallelSteps[stepIndex].stepName);
2486
+ throw wrappedError;
2436
2487
  }
2437
2488
  break;
2438
2489
  }
@@ -3005,9 +3056,10 @@ var WorkflowContext = class {
3005
3056
  */
3006
3057
  env;
3007
3058
  /**
3008
- * Label to apply to the workflow run.
3059
+ * Labels attached to the workflow run.
3009
3060
  *
3010
- * Can be used to filter the workflow run logs.
3061
+ * Can be used to filter the workflow run logs. A run can have multiple
3062
+ * labels when triggered with `label: string[]`.
3011
3063
  *
3012
3064
  * Can be set by passing a `label` parameter when triggering the workflow
3013
3065
  * with `client.trigger`:
@@ -3015,11 +3067,20 @@ var WorkflowContext = class {
3015
3067
  * ```ts
3016
3068
  * await client.trigger({
3017
3069
  * url: "https://workflow-endpoint.com",
3018
- * label: "my-label"
3070
+ * label: ["label-1", "label-2"]
3019
3071
  * });
3020
3072
  * ```
3021
3073
  */
3022
- label;
3074
+ labels;
3075
+ /**
3076
+ * Label of the workflow run.
3077
+ *
3078
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
3079
+ * only returns the first one.
3080
+ */
3081
+ get label() {
3082
+ return this.labels[0];
3083
+ }
3023
3084
  /**
3024
3085
  * Number of times QStash has retried delivering the current request.
3025
3086
  *
@@ -3050,7 +3111,7 @@ var WorkflowContext = class {
3050
3111
  this.headers = headers;
3051
3112
  this.requestPayload = initialPayload;
3052
3113
  this.env = env ?? {};
3053
- this.label = label;
3114
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
3054
3115
  this.retried = retried ?? 0;
3055
3116
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
3056
3117
  middlewareManagerInstance.assignContext(this);
@@ -3131,8 +3192,10 @@ var WorkflowContext = class {
3131
3192
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
3132
3193
  }
3133
3194
  async call(stepName, settings) {
3195
+ validateFlowControl(settings.flowControl);
3134
3196
  let callStep;
3135
3197
  if ("workflow" in settings) {
3198
+ validateLabel(settings.label);
3136
3199
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
3137
3200
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
3138
3201
  callStep = new LazyCallStep({
@@ -3240,6 +3303,8 @@ var WorkflowContext = class {
3240
3303
  );
3241
3304
  }
3242
3305
  async invoke(stepName, settings) {
3306
+ validateLabel(settings.label);
3307
+ validateFlowControl(settings.flowControl);
3243
3308
  return await this.addStep(
3244
3309
  new LazyInvokeStep(this, stepName, settings)
3245
3310
  );
@@ -3325,7 +3390,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3325
3390
  url: context.url,
3326
3391
  initialPayload: context.requestPayload,
3327
3392
  env: context.env,
3328
- label: context.label,
3393
+ label: context.labels,
3329
3394
  retried: context.retried
3330
3395
  });
3331
3396
  try {
@@ -4163,10 +4228,12 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
4163
4228
  await middlewareManager.dispatchDebug("onError", {
4164
4229
  error: isInstanceOf(error, Error) ? error : new Error(formattedError.message)
4165
4230
  });
4231
+ const stepName = getStepNameFromError(error)?.replace(/[\u0000-\u001F\u007F]+/g, " ").trim();
4166
4232
  return new Response(JSON.stringify(formattedError), {
4167
4233
  status: 500,
4168
4234
  headers: {
4169
- [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION
4235
+ [WORKFLOW_PROTOCOL_VERSION_HEADER]: WORKFLOW_PROTOCOL_VERSION,
4236
+ ...stepName ? { [WORKFLOW_ERROR_STEP_NAME_HEADER]: stepName } : {}
4170
4237
  }
4171
4238
  });
4172
4239
  }
package/h3.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-G24J5PCC.mjs";
5
+ } from "./chunk-ICDNN4UW.mjs";
6
6
 
7
7
  // node_modules/defu/dist/defu.mjs
8
8
  function isPlainObject(value) {
package/hono.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Context } from 'hono';
2
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
2
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
3
3
  import { Variables } from 'hono/types';
4
- import { s as serveManyBase } from './serve-many-D3D9uE4u.mjs';
4
+ import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
 
package/hono.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Context } from 'hono';
2
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.js';
2
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
3
3
  import { Variables } from 'hono/types';
4
- import { s as serveManyBase } from './serve-many-kPOasiyb.js';
4
+ import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7