@upstash/workflow 1.3.0 → 1.3.1

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 +50 -10
  4. package/astro.mjs +1 -1
  5. package/{chunk-G24J5PCC.mjs → chunk-CWCCIOXR.mjs} +53 -10
  6. package/cloudflare.d.mts +2 -2
  7. package/cloudflare.d.ts +2 -2
  8. package/cloudflare.js +50 -10
  9. package/cloudflare.mjs +1 -1
  10. package/express.d.mts +2 -2
  11. package/express.d.ts +2 -2
  12. package/express.js +50 -10
  13. package/express.mjs +1 -1
  14. package/h3.d.mts +2 -2
  15. package/h3.d.ts +2 -2
  16. package/h3.js +50 -10
  17. package/h3.mjs +1 -1
  18. package/hono.d.mts +2 -2
  19. package/hono.d.ts +2 -2
  20. package/hono.js +50 -10
  21. package/hono.mjs +1 -1
  22. package/index.d.mts +24 -5
  23. package/index.d.ts +24 -5
  24. package/index.js +53 -11
  25. package/index.mjs +8 -3
  26. package/nextjs.d.mts +2 -2
  27. package/nextjs.d.ts +2 -2
  28. package/nextjs.js +50 -10
  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 +50 -10
  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 +50 -10
  40. package/solidjs.mjs +1 -1
  41. package/svelte.d.mts +2 -2
  42. package/svelte.d.ts +2 -2
  43. package/svelte.js +50 -10
  44. package/svelte.mjs +1 -1
  45. package/tanstack.d.mts +2 -2
  46. package/tanstack.d.ts +2 -2
  47. package/tanstack.js +50 -10
  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/astro.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { APIContext, APIRoute } from 'astro';
2
- import { u as WorkflowContext, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
3
- import { s as serveManyBase } from './serve-many-D3D9uE4u.mjs';
2
+ import { u as WorkflowContext, 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/astro.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { APIContext, APIRoute } from 'astro';
2
- import { u as WorkflowContext, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.js';
3
- import { s as serveManyBase } from './serve-many-kPOasiyb.js';
2
+ import { u as WorkflowContext, 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/astro.js CHANGED
@@ -216,6 +216,31 @@ var import_qstash4 = require("@upstash/qstash");
216
216
  // src/utils.ts
217
217
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
218
218
  var NANOID_LENGTH = 21;
219
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
220
+ function validateLabel(label) {
221
+ if (label === void 0) return;
222
+ const labels = Array.isArray(label) ? label : [label];
223
+ if (labels.length === 0) {
224
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
225
+ }
226
+ for (const value of labels) {
227
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
228
+ throw new WorkflowNonRetryableError(
229
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
230
+ );
231
+ }
232
+ }
233
+ }
234
+ function serializeLabel(label) {
235
+ return Array.isArray(label) ? label.join(",") : label;
236
+ }
237
+ function validateFlowControl(flowControl) {
238
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
239
+ throw new WorkflowNonRetryableError(
240
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
241
+ );
242
+ }
243
+ }
219
244
  function getRandomInt() {
220
245
  return Math.floor(Math.random() * NANOID_CHARS.length);
221
246
  }
@@ -751,8 +776,8 @@ var triggerFirstInvocation = async (params) => {
751
776
  if (unknownSdk) {
752
777
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
753
778
  }
754
- if (workflowContext.label) {
755
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
779
+ if (workflowContext.labels.length > 0) {
780
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
756
781
  }
757
782
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
758
783
  return {
@@ -1554,8 +1579,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1554
1579
  });
1555
1580
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1556
1581
  if (label) {
1557
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1558
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1582
+ const labelHeader = serializeLabel(label);
1583
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1584
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1559
1585
  }
1560
1586
  return { headers: triggerHeaders, contentType };
1561
1587
  }
@@ -2696,9 +2722,10 @@ var WorkflowContext = class {
2696
2722
  */
2697
2723
  env;
2698
2724
  /**
2699
- * Label to apply to the workflow run.
2725
+ * Labels attached to the workflow run.
2700
2726
  *
2701
- * Can be used to filter the workflow run logs.
2727
+ * Can be used to filter the workflow run logs. A run can have multiple
2728
+ * labels when triggered with `label: string[]`.
2702
2729
  *
2703
2730
  * Can be set by passing a `label` parameter when triggering the workflow
2704
2731
  * with `client.trigger`:
@@ -2706,11 +2733,20 @@ var WorkflowContext = class {
2706
2733
  * ```ts
2707
2734
  * await client.trigger({
2708
2735
  * url: "https://workflow-endpoint.com",
2709
- * label: "my-label"
2736
+ * label: ["label-1", "label-2"]
2710
2737
  * });
2711
2738
  * ```
2712
2739
  */
2713
- label;
2740
+ labels;
2741
+ /**
2742
+ * Label of the workflow run.
2743
+ *
2744
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2745
+ * only returns the first one.
2746
+ */
2747
+ get label() {
2748
+ return this.labels[0];
2749
+ }
2714
2750
  /**
2715
2751
  * Number of times QStash has retried delivering the current request.
2716
2752
  *
@@ -2741,7 +2777,7 @@ var WorkflowContext = class {
2741
2777
  this.headers = headers;
2742
2778
  this.requestPayload = initialPayload;
2743
2779
  this.env = env ?? {};
2744
- this.label = label;
2780
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2745
2781
  this.retried = retried ?? 0;
2746
2782
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2747
2783
  middlewareManagerInstance.assignContext(this);
@@ -2822,8 +2858,10 @@ var WorkflowContext = class {
2822
2858
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2823
2859
  }
2824
2860
  async call(stepName, settings) {
2861
+ validateFlowControl(settings.flowControl);
2825
2862
  let callStep;
2826
2863
  if ("workflow" in settings) {
2864
+ validateLabel(settings.label);
2827
2865
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2828
2866
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2829
2867
  callStep = new LazyCallStep({
@@ -2931,6 +2969,8 @@ var WorkflowContext = class {
2931
2969
  );
2932
2970
  }
2933
2971
  async invoke(stepName, settings) {
2972
+ validateLabel(settings.label);
2973
+ validateFlowControl(settings.flowControl);
2934
2974
  return await this.addStep(
2935
2975
  new LazyInvokeStep(this, stepName, settings)
2936
2976
  );
@@ -3016,7 +3056,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3016
3056
  url: context.url,
3017
3057
  initialPayload: context.requestPayload,
3018
3058
  env: context.env,
3019
- label: context.label,
3059
+ label: context.labels,
3020
3060
  retried: context.retried
3021
3061
  });
3022
3062
  try {
package/astro.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-CWCCIOXR.mjs";
6
6
 
7
7
  // platforms/astro.ts
8
8
  var telemetry = {
@@ -342,6 +342,31 @@ function buildBulkActionQueryParameters(request, options) {
342
342
  // src/utils.ts
343
343
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
344
344
  var NANOID_LENGTH = 21;
345
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
346
+ function validateLabel(label) {
347
+ if (label === void 0) return;
348
+ const labels = Array.isArray(label) ? label : [label];
349
+ if (labels.length === 0) {
350
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
351
+ }
352
+ for (const value of labels) {
353
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
354
+ throw new WorkflowNonRetryableError(
355
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
356
+ );
357
+ }
358
+ }
359
+ }
360
+ function serializeLabel(label) {
361
+ return Array.isArray(label) ? label.join(",") : label;
362
+ }
363
+ function validateFlowControl(flowControl) {
364
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
365
+ throw new WorkflowNonRetryableError(
366
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
367
+ );
368
+ }
369
+ }
345
370
  function getRandomInt() {
346
371
  return Math.floor(Math.random() * NANOID_CHARS.length);
347
372
  }
@@ -863,8 +888,8 @@ var triggerFirstInvocation = async (params) => {
863
888
  if (unknownSdk) {
864
889
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
865
890
  }
866
- if (workflowContext.label) {
867
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
891
+ if (workflowContext.labels.length > 0) {
892
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
868
893
  }
869
894
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
870
895
  return {
@@ -1666,8 +1691,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1666
1691
  });
1667
1692
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1668
1693
  if (label) {
1669
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1670
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1694
+ const labelHeader = serializeLabel(label);
1695
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1696
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1671
1697
  }
1672
1698
  return { headers: triggerHeaders, contentType };
1673
1699
  }
@@ -2733,9 +2759,10 @@ var WorkflowContext = class {
2733
2759
  */
2734
2760
  env;
2735
2761
  /**
2736
- * Label to apply to the workflow run.
2762
+ * Labels attached to the workflow run.
2737
2763
  *
2738
- * Can be used to filter the workflow run logs.
2764
+ * Can be used to filter the workflow run logs. A run can have multiple
2765
+ * labels when triggered with `label: string[]`.
2739
2766
  *
2740
2767
  * Can be set by passing a `label` parameter when triggering the workflow
2741
2768
  * with `client.trigger`:
@@ -2743,11 +2770,20 @@ var WorkflowContext = class {
2743
2770
  * ```ts
2744
2771
  * await client.trigger({
2745
2772
  * url: "https://workflow-endpoint.com",
2746
- * label: "my-label"
2773
+ * label: ["label-1", "label-2"]
2747
2774
  * });
2748
2775
  * ```
2749
2776
  */
2750
- label;
2777
+ labels;
2778
+ /**
2779
+ * Label of the workflow run.
2780
+ *
2781
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2782
+ * only returns the first one.
2783
+ */
2784
+ get label() {
2785
+ return this.labels[0];
2786
+ }
2751
2787
  /**
2752
2788
  * Number of times QStash has retried delivering the current request.
2753
2789
  *
@@ -2778,7 +2814,7 @@ var WorkflowContext = class {
2778
2814
  this.headers = headers;
2779
2815
  this.requestPayload = initialPayload;
2780
2816
  this.env = env ?? {};
2781
- this.label = label;
2817
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2782
2818
  this.retried = retried ?? 0;
2783
2819
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2784
2820
  middlewareManagerInstance.assignContext(this);
@@ -2859,8 +2895,10 @@ var WorkflowContext = class {
2859
2895
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2860
2896
  }
2861
2897
  async call(stepName, settings) {
2898
+ validateFlowControl(settings.flowControl);
2862
2899
  let callStep;
2863
2900
  if ("workflow" in settings) {
2901
+ validateLabel(settings.label);
2864
2902
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2865
2903
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2866
2904
  callStep = new LazyCallStep({
@@ -2968,6 +3006,8 @@ var WorkflowContext = class {
2968
3006
  );
2969
3007
  }
2970
3008
  async invoke(stepName, settings) {
3009
+ validateLabel(settings.label);
3010
+ validateFlowControl(settings.flowControl);
2971
3011
  return await this.addStep(
2972
3012
  new LazyInvokeStep(this, stepName, settings)
2973
3013
  );
@@ -3127,7 +3167,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3127
3167
  url: context.url,
3128
3168
  initialPayload: context.requestPayload,
3129
3169
  env: context.env,
3130
- label: context.label,
3170
+ label: context.labels,
3131
3171
  retried: context.retried
3132
3172
  });
3133
3173
  try {
@@ -3923,6 +3963,9 @@ export {
3923
3963
  buildBulkActionQueryParameters,
3924
3964
  WORKFLOW_LABEL_HEADER,
3925
3965
  SDK_TELEMETRY,
3966
+ validateLabel,
3967
+ serializeLabel,
3968
+ validateFlowControl,
3926
3969
  getWorkflowRunId,
3927
3970
  StepTypes,
3928
3971
  triggerFirstInvocation,
package/cloudflare.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
2
- import { s as serveManyBase } from './serve-many-D3D9uE4u.mjs';
1
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
2
+ import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
 
package/cloudflare.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.js';
2
- import { s as serveManyBase } from './serve-many-kPOasiyb.js';
1
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
2
+ import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
 
package/cloudflare.js CHANGED
@@ -216,6 +216,31 @@ var import_qstash4 = require("@upstash/qstash");
216
216
  // src/utils.ts
217
217
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
218
218
  var NANOID_LENGTH = 21;
219
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
220
+ function validateLabel(label) {
221
+ if (label === void 0) return;
222
+ const labels = Array.isArray(label) ? label : [label];
223
+ if (labels.length === 0) {
224
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
225
+ }
226
+ for (const value of labels) {
227
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
228
+ throw new WorkflowNonRetryableError(
229
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
230
+ );
231
+ }
232
+ }
233
+ }
234
+ function serializeLabel(label) {
235
+ return Array.isArray(label) ? label.join(",") : label;
236
+ }
237
+ function validateFlowControl(flowControl) {
238
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
239
+ throw new WorkflowNonRetryableError(
240
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
241
+ );
242
+ }
243
+ }
219
244
  function getRandomInt() {
220
245
  return Math.floor(Math.random() * NANOID_CHARS.length);
221
246
  }
@@ -751,8 +776,8 @@ var triggerFirstInvocation = async (params) => {
751
776
  if (unknownSdk) {
752
777
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
753
778
  }
754
- if (workflowContext.label) {
755
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
779
+ if (workflowContext.labels.length > 0) {
780
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
756
781
  }
757
782
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
758
783
  return {
@@ -1554,8 +1579,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1554
1579
  });
1555
1580
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1556
1581
  if (label) {
1557
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1558
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1582
+ const labelHeader = serializeLabel(label);
1583
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1584
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1559
1585
  }
1560
1586
  return { headers: triggerHeaders, contentType };
1561
1587
  }
@@ -2696,9 +2722,10 @@ var WorkflowContext = class {
2696
2722
  */
2697
2723
  env;
2698
2724
  /**
2699
- * Label to apply to the workflow run.
2725
+ * Labels attached to the workflow run.
2700
2726
  *
2701
- * Can be used to filter the workflow run logs.
2727
+ * Can be used to filter the workflow run logs. A run can have multiple
2728
+ * labels when triggered with `label: string[]`.
2702
2729
  *
2703
2730
  * Can be set by passing a `label` parameter when triggering the workflow
2704
2731
  * with `client.trigger`:
@@ -2706,11 +2733,20 @@ var WorkflowContext = class {
2706
2733
  * ```ts
2707
2734
  * await client.trigger({
2708
2735
  * url: "https://workflow-endpoint.com",
2709
- * label: "my-label"
2736
+ * label: ["label-1", "label-2"]
2710
2737
  * });
2711
2738
  * ```
2712
2739
  */
2713
- label;
2740
+ labels;
2741
+ /**
2742
+ * Label of the workflow run.
2743
+ *
2744
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2745
+ * only returns the first one.
2746
+ */
2747
+ get label() {
2748
+ return this.labels[0];
2749
+ }
2714
2750
  /**
2715
2751
  * Number of times QStash has retried delivering the current request.
2716
2752
  *
@@ -2741,7 +2777,7 @@ var WorkflowContext = class {
2741
2777
  this.headers = headers;
2742
2778
  this.requestPayload = initialPayload;
2743
2779
  this.env = env ?? {};
2744
- this.label = label;
2780
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2745
2781
  this.retried = retried ?? 0;
2746
2782
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2747
2783
  middlewareManagerInstance.assignContext(this);
@@ -2822,8 +2858,10 @@ var WorkflowContext = class {
2822
2858
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2823
2859
  }
2824
2860
  async call(stepName, settings) {
2861
+ validateFlowControl(settings.flowControl);
2825
2862
  let callStep;
2826
2863
  if ("workflow" in settings) {
2864
+ validateLabel(settings.label);
2827
2865
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2828
2866
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2829
2867
  callStep = new LazyCallStep({
@@ -2931,6 +2969,8 @@ var WorkflowContext = class {
2931
2969
  );
2932
2970
  }
2933
2971
  async invoke(stepName, settings) {
2972
+ validateLabel(settings.label);
2973
+ validateFlowControl(settings.flowControl);
2934
2974
  return await this.addStep(
2935
2975
  new LazyInvokeStep(this, stepName, settings)
2936
2976
  );
@@ -3016,7 +3056,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3016
3056
  url: context.url,
3017
3057
  initialPayload: context.requestPayload,
3018
3058
  env: context.env,
3019
- label: context.label,
3059
+ label: context.labels,
3020
3060
  retried: context.retried
3021
3061
  });
3022
3062
  try {
package/cloudflare.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-CWCCIOXR.mjs";
6
6
 
7
7
  // platforms/cloudflare.ts
8
8
  var getArgs = (args) => {
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
@@ -216,6 +216,31 @@ var import_qstash4 = require("@upstash/qstash");
216
216
  // src/utils.ts
217
217
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
218
218
  var NANOID_LENGTH = 21;
219
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
220
+ function validateLabel(label) {
221
+ if (label === void 0) return;
222
+ const labels = Array.isArray(label) ? label : [label];
223
+ if (labels.length === 0) {
224
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
225
+ }
226
+ for (const value of labels) {
227
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
228
+ throw new WorkflowNonRetryableError(
229
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
230
+ );
231
+ }
232
+ }
233
+ }
234
+ function serializeLabel(label) {
235
+ return Array.isArray(label) ? label.join(",") : label;
236
+ }
237
+ function validateFlowControl(flowControl) {
238
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
239
+ throw new WorkflowNonRetryableError(
240
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
241
+ );
242
+ }
243
+ }
219
244
  function getRandomInt() {
220
245
  return Math.floor(Math.random() * NANOID_CHARS.length);
221
246
  }
@@ -751,8 +776,8 @@ var triggerFirstInvocation = async (params) => {
751
776
  if (unknownSdk) {
752
777
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
753
778
  }
754
- if (workflowContext.label) {
755
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
779
+ if (workflowContext.labels.length > 0) {
780
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
756
781
  }
757
782
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
758
783
  return {
@@ -1554,8 +1579,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1554
1579
  });
1555
1580
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1556
1581
  if (label) {
1557
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1558
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1582
+ const labelHeader = serializeLabel(label);
1583
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1584
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1559
1585
  }
1560
1586
  return { headers: triggerHeaders, contentType };
1561
1587
  }
@@ -2696,9 +2722,10 @@ var WorkflowContext = class {
2696
2722
  */
2697
2723
  env;
2698
2724
  /**
2699
- * Label to apply to the workflow run.
2725
+ * Labels attached to the workflow run.
2700
2726
  *
2701
- * Can be used to filter the workflow run logs.
2727
+ * Can be used to filter the workflow run logs. A run can have multiple
2728
+ * labels when triggered with `label: string[]`.
2702
2729
  *
2703
2730
  * Can be set by passing a `label` parameter when triggering the workflow
2704
2731
  * with `client.trigger`:
@@ -2706,11 +2733,20 @@ var WorkflowContext = class {
2706
2733
  * ```ts
2707
2734
  * await client.trigger({
2708
2735
  * url: "https://workflow-endpoint.com",
2709
- * label: "my-label"
2736
+ * label: ["label-1", "label-2"]
2710
2737
  * });
2711
2738
  * ```
2712
2739
  */
2713
- label;
2740
+ labels;
2741
+ /**
2742
+ * Label of the workflow run.
2743
+ *
2744
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2745
+ * only returns the first one.
2746
+ */
2747
+ get label() {
2748
+ return this.labels[0];
2749
+ }
2714
2750
  /**
2715
2751
  * Number of times QStash has retried delivering the current request.
2716
2752
  *
@@ -2741,7 +2777,7 @@ var WorkflowContext = class {
2741
2777
  this.headers = headers;
2742
2778
  this.requestPayload = initialPayload;
2743
2779
  this.env = env ?? {};
2744
- this.label = label;
2780
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2745
2781
  this.retried = retried ?? 0;
2746
2782
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2747
2783
  middlewareManagerInstance.assignContext(this);
@@ -2822,8 +2858,10 @@ var WorkflowContext = class {
2822
2858
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2823
2859
  }
2824
2860
  async call(stepName, settings) {
2861
+ validateFlowControl(settings.flowControl);
2825
2862
  let callStep;
2826
2863
  if ("workflow" in settings) {
2864
+ validateLabel(settings.label);
2827
2865
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2828
2866
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2829
2867
  callStep = new LazyCallStep({
@@ -2931,6 +2969,8 @@ var WorkflowContext = class {
2931
2969
  );
2932
2970
  }
2933
2971
  async invoke(stepName, settings) {
2972
+ validateLabel(settings.label);
2973
+ validateFlowControl(settings.flowControl);
2934
2974
  return await this.addStep(
2935
2975
  new LazyInvokeStep(this, stepName, settings)
2936
2976
  );
@@ -3016,7 +3056,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3016
3056
  url: context.url,
3017
3057
  initialPayload: context.requestPayload,
3018
3058
  env: context.env,
3019
- label: context.label,
3059
+ label: context.labels,
3020
3060
  retried: context.retried
3021
3061
  });
3022
3062
  try {
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-CWCCIOXR.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