@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/nextjs.js CHANGED
@@ -219,6 +219,31 @@ var import_qstash4 = require("@upstash/qstash");
219
219
  // src/utils.ts
220
220
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
221
221
  var NANOID_LENGTH = 21;
222
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
223
+ function validateLabel(label) {
224
+ if (label === void 0) return;
225
+ const labels = Array.isArray(label) ? label : [label];
226
+ if (labels.length === 0) {
227
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
228
+ }
229
+ for (const value of labels) {
230
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
231
+ throw new WorkflowNonRetryableError(
232
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
233
+ );
234
+ }
235
+ }
236
+ }
237
+ function serializeLabel(label) {
238
+ return Array.isArray(label) ? label.join(",") : label;
239
+ }
240
+ function validateFlowControl(flowControl) {
241
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
242
+ throw new WorkflowNonRetryableError(
243
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
244
+ );
245
+ }
246
+ }
222
247
  function getRandomInt() {
223
248
  return Math.floor(Math.random() * NANOID_CHARS.length);
224
249
  }
@@ -754,8 +779,8 @@ var triggerFirstInvocation = async (params) => {
754
779
  if (unknownSdk) {
755
780
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
756
781
  }
757
- if (workflowContext.label) {
758
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
782
+ if (workflowContext.labels.length > 0) {
783
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
759
784
  }
760
785
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
761
786
  return {
@@ -1557,8 +1582,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1557
1582
  });
1558
1583
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1559
1584
  if (label) {
1560
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1561
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1585
+ const labelHeader = serializeLabel(label);
1586
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1587
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1562
1588
  }
1563
1589
  return { headers: triggerHeaders, contentType };
1564
1590
  }
@@ -2699,9 +2725,10 @@ var WorkflowContext = class {
2699
2725
  */
2700
2726
  env;
2701
2727
  /**
2702
- * Label to apply to the workflow run.
2728
+ * Labels attached to the workflow run.
2703
2729
  *
2704
- * Can be used to filter the workflow run logs.
2730
+ * Can be used to filter the workflow run logs. A run can have multiple
2731
+ * labels when triggered with `label: string[]`.
2705
2732
  *
2706
2733
  * Can be set by passing a `label` parameter when triggering the workflow
2707
2734
  * with `client.trigger`:
@@ -2709,11 +2736,20 @@ var WorkflowContext = class {
2709
2736
  * ```ts
2710
2737
  * await client.trigger({
2711
2738
  * url: "https://workflow-endpoint.com",
2712
- * label: "my-label"
2739
+ * label: ["label-1", "label-2"]
2713
2740
  * });
2714
2741
  * ```
2715
2742
  */
2716
- label;
2743
+ labels;
2744
+ /**
2745
+ * Label of the workflow run.
2746
+ *
2747
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2748
+ * only returns the first one.
2749
+ */
2750
+ get label() {
2751
+ return this.labels[0];
2752
+ }
2717
2753
  /**
2718
2754
  * Number of times QStash has retried delivering the current request.
2719
2755
  *
@@ -2744,7 +2780,7 @@ var WorkflowContext = class {
2744
2780
  this.headers = headers;
2745
2781
  this.requestPayload = initialPayload;
2746
2782
  this.env = env ?? {};
2747
- this.label = label;
2783
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2748
2784
  this.retried = retried ?? 0;
2749
2785
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2750
2786
  middlewareManagerInstance.assignContext(this);
@@ -2825,8 +2861,10 @@ var WorkflowContext = class {
2825
2861
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2826
2862
  }
2827
2863
  async call(stepName, settings) {
2864
+ validateFlowControl(settings.flowControl);
2828
2865
  let callStep;
2829
2866
  if ("workflow" in settings) {
2867
+ validateLabel(settings.label);
2830
2868
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2831
2869
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2832
2870
  callStep = new LazyCallStep({
@@ -2934,6 +2972,8 @@ var WorkflowContext = class {
2934
2972
  );
2935
2973
  }
2936
2974
  async invoke(stepName, settings) {
2975
+ validateLabel(settings.label);
2976
+ validateFlowControl(settings.flowControl);
2937
2977
  return await this.addStep(
2938
2978
  new LazyInvokeStep(this, stepName, settings)
2939
2979
  );
@@ -3019,7 +3059,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3019
3059
  url: context.url,
3020
3060
  initialPayload: context.requestPayload,
3021
3061
  env: context.env,
3022
- label: context.label,
3062
+ label: context.labels,
3023
3063
  retried: context.retried
3024
3064
  });
3025
3065
  try {
package/nextjs.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/nextjs.ts
8
8
  var appTelemetry = {
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@upstash/workflow","version":"1.3.0","description":"Durable, Reliable and Performant Serverless Functions","main":"./index.js","module":"./index.mjs","types":"./index.d.ts","files":["./*"],"exports":{".":{"import":"./index.mjs","require":"./index.js"},"./dist/nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./h3":{"import":"./h3.mjs","require":"./h3.js"},"./svelte":{"import":"./svelte.mjs","require":"./svelte.js"},"./solidjs":{"import":"./solidjs.mjs","require":"./solidjs.js"},"./workflow":{"import":"./workflow.mjs","require":"./workflow.js"},"./hono":{"import":"./hono.mjs","require":"./hono.js"},"./cloudflare":{"import":"./cloudflare.mjs","require":"./cloudflare.js"},"./astro":{"import":"./astro.mjs","require":"./astro.js"},"./express":{"import":"./express.mjs","require":"./express.js"},"./tanstack":{"import":"./tanstack.mjs","require":"./tanstack.js"},"./react-router":{"import":"./react-router.mjs","require":"./react-router.js"}},"scripts":{"build":"tsup && cp README.md ./dist/ && cp package.json ./dist/ && cp LICENSE ./dist/","test":"bun test src","fmt":"prettier --write .","lint":"tsc && eslint \"{src,platforms}/**/*.{js,ts,tsx}\" --quiet --fix","check-exports":"bun run build && cd dist && attw -P"},"repository":{"type":"git","url":"git@github.com:upstash/workflow-js.git"},"keywords":["upstash","qstash","workflow","serverless"],"author":"Cahid Arda Oz","license":"MIT","bugs":{"url":"https://github.com/upstash/workflow-ts/issues"},"homepage":"https://github.com/upstash/workflow-ts#readme","devDependencies":{"@commitlint/cli":"^19.5.0","@commitlint/config-conventional":"^19.5.0","@eslint/js":"^9.11.1","@solidjs/start":"^1.0.8","@sveltejs/kit":"^2.6.1","@types/bun":"^1.1.10","@types/express":"^5.0.6","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^5.1.0","globals":"^15.10.0","h3":"^1.12.0","hono":"^4.6.20","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsup":"^8.3.0","typescript":"^5.7.2","typescript-eslint":"^8.18.0"},"dependencies":{"@upstash/qstash":"^2.11.0"},"directories":{"example":"examples"},"peerDependencies":{"zod":"^3.25.0 || ^4.0.0"}}
1
+ {"name":"@upstash/workflow","version":"1.3.1","description":"Durable, Reliable and Performant Serverless Functions","main":"./index.js","module":"./index.mjs","types":"./index.d.ts","files":["./*"],"exports":{".":{"import":"./index.mjs","require":"./index.js"},"./dist/nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./nextjs":{"import":"./nextjs.mjs","require":"./nextjs.js"},"./h3":{"import":"./h3.mjs","require":"./h3.js"},"./svelte":{"import":"./svelte.mjs","require":"./svelte.js"},"./solidjs":{"import":"./solidjs.mjs","require":"./solidjs.js"},"./workflow":{"import":"./workflow.mjs","require":"./workflow.js"},"./hono":{"import":"./hono.mjs","require":"./hono.js"},"./cloudflare":{"import":"./cloudflare.mjs","require":"./cloudflare.js"},"./astro":{"import":"./astro.mjs","require":"./astro.js"},"./express":{"import":"./express.mjs","require":"./express.js"},"./tanstack":{"import":"./tanstack.mjs","require":"./tanstack.js"},"./react-router":{"import":"./react-router.mjs","require":"./react-router.js"}},"scripts":{"build":"tsup && cp README.md ./dist/ && cp package.json ./dist/ && cp LICENSE ./dist/","test":"bun test src","fmt":"prettier --write .","lint":"tsc && eslint \"{src,platforms}/**/*.{js,ts,tsx}\" --quiet --fix","check-exports":"bun run build && cd dist && attw -P"},"repository":{"type":"git","url":"git@github.com:upstash/workflow-js.git"},"keywords":["upstash","qstash","workflow","serverless"],"author":"Cahid Arda Oz","license":"MIT","bugs":{"url":"https://github.com/upstash/workflow-ts/issues"},"homepage":"https://github.com/upstash/workflow-ts#readme","devDependencies":{"@commitlint/cli":"^19.5.0","@commitlint/config-conventional":"^19.5.0","@eslint/js":"^9.11.1","@solidjs/start":"^1.0.8","@sveltejs/kit":"^2.6.1","@types/bun":"^1.1.10","@types/express":"^5.0.6","astro":"^4.16.7","eslint":"^9.11.1","eslint-plugin-unicorn":"^55.0.0","express":"^5.1.0","globals":"^15.10.0","h3":"^1.12.0","hono":"^4.6.20","husky":"^9.1.6","next":"^14.2.14","prettier":"3.3.3","tsup":"^8.3.0","typescript":"^5.7.2","typescript-eslint":"^8.18.0"},"dependencies":{"@upstash/qstash":"^2.11.0"},"directories":{"example":"examples"},"peerDependencies":{"zod":"^3.25.0 || ^4.0.0"}}
@@ -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/react-router.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/react-router.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/react-router.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/react-router.ts
8
8
  var telemetry = {
@@ -1,4 +1,4 @@
1
- import { d as WorkflowServeOptions, c as RouteFunction, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
1
+ import { d as WorkflowServeOptions, c as RouteFunction, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
2
2
 
3
3
  type OmitOptionsInServeMany<TOptions> = Omit<TOptions, "env" | "url" | "schema" | "initialPayloadParser">;
4
4
  declare const serveManyBase: <THandler extends (...params: any[]) => any, TOptions extends OmitOptionsInServeMany<WorkflowServeOptions> = OmitOptionsInServeMany<WorkflowServeOptions>, TServeParams extends [routeFunction: RouteFunction<any, any>, options: TOptions] = [routeFunction: RouteFunction<any, any>, options: TOptions]>({ workflows, getUrl, serveMethod, options, }: {
@@ -1,4 +1,4 @@
1
- import { d as WorkflowServeOptions, c as RouteFunction, I as InvokableWorkflow } from './types-B_E1VAK6.js';
1
+ import { d as WorkflowServeOptions, c as RouteFunction, I as InvokableWorkflow } from './types-CekOpKvz.js';
2
2
 
3
3
  type OmitOptionsInServeMany<TOptions> = Omit<TOptions, "env" | "url" | "schema" | "initialPayloadParser">;
4
4
  declare const serveManyBase: <THandler extends (...params: any[]) => any, TOptions extends OmitOptionsInServeMany<WorkflowServeOptions> = OmitOptionsInServeMany<WorkflowServeOptions>, TServeParams extends [routeFunction: RouteFunction<any, any>, options: TOptions] = [routeFunction: RouteFunction<any, any>, options: TOptions]>({ workflows, getUrl, serveMethod, options, }: {
package/solidjs.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIEvent } from '@solidjs/start/server';
2
- import { c as RouteFunction, d as WorkflowServeOptions } from './types-B_E1VAK6.mjs';
2
+ import { c as RouteFunction, d as WorkflowServeOptions } from './types-CekOpKvz.mjs';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
 
package/solidjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIEvent } from '@solidjs/start/server';
2
- import { c as RouteFunction, d as WorkflowServeOptions } from './types-B_E1VAK6.js';
2
+ import { c as RouteFunction, d as WorkflowServeOptions } from './types-CekOpKvz.js';
3
3
  import '@upstash/qstash';
4
4
  import 'zod';
5
5
 
package/solidjs.js CHANGED
@@ -214,6 +214,31 @@ var import_qstash4 = require("@upstash/qstash");
214
214
  // src/utils.ts
215
215
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
216
216
  var NANOID_LENGTH = 21;
217
+ var RESOURCE_NAME_PATTERN = /^[a-zA-Z0-9\-_.]+$/;
218
+ function validateLabel(label) {
219
+ if (label === void 0) return;
220
+ const labels = Array.isArray(label) ? label : [label];
221
+ if (labels.length === 0) {
222
+ throw new WorkflowNonRetryableError("Invalid label: label array must not be empty.");
223
+ }
224
+ for (const value of labels) {
225
+ if (!RESOURCE_NAME_PATTERN.test(value)) {
226
+ throw new WorkflowNonRetryableError(
227
+ `Invalid label "${value}": must be alphanumeric, hyphen, underscore, or period.`
228
+ );
229
+ }
230
+ }
231
+ }
232
+ function serializeLabel(label) {
233
+ return Array.isArray(label) ? label.join(",") : label;
234
+ }
235
+ function validateFlowControl(flowControl) {
236
+ if (flowControl?.key !== void 0 && !RESOURCE_NAME_PATTERN.test(flowControl.key)) {
237
+ throw new WorkflowNonRetryableError(
238
+ `Invalid flow control key "${flowControl.key}": must be alphanumeric, hyphen, underscore, or period.`
239
+ );
240
+ }
241
+ }
217
242
  function getRandomInt() {
218
243
  return Math.floor(Math.random() * NANOID_CHARS.length);
219
244
  }
@@ -749,8 +774,8 @@ var triggerFirstInvocation = async (params) => {
749
774
  if (unknownSdk) {
750
775
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
751
776
  }
752
- if (workflowContext.label) {
753
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
777
+ if (workflowContext.labels.length > 0) {
778
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
754
779
  }
755
780
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
756
781
  return {
@@ -1552,8 +1577,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1552
1577
  });
1553
1578
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1554
1579
  if (label) {
1555
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1556
- triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = label;
1580
+ const labelHeader = serializeLabel(label);
1581
+ triggerHeaders[WORKFLOW_LABEL_HEADER] = labelHeader;
1582
+ triggerHeaders[`upstash-forward-${WORKFLOW_LABEL_HEADER}`] = labelHeader;
1557
1583
  }
1558
1584
  return { headers: triggerHeaders, contentType };
1559
1585
  }
@@ -2627,9 +2653,10 @@ var WorkflowContext = class {
2627
2653
  */
2628
2654
  env;
2629
2655
  /**
2630
- * Label to apply to the workflow run.
2656
+ * Labels attached to the workflow run.
2631
2657
  *
2632
- * Can be used to filter the workflow run logs.
2658
+ * Can be used to filter the workflow run logs. A run can have multiple
2659
+ * labels when triggered with `label: string[]`.
2633
2660
  *
2634
2661
  * Can be set by passing a `label` parameter when triggering the workflow
2635
2662
  * with `client.trigger`:
@@ -2637,11 +2664,20 @@ var WorkflowContext = class {
2637
2664
  * ```ts
2638
2665
  * await client.trigger({
2639
2666
  * url: "https://workflow-endpoint.com",
2640
- * label: "my-label"
2667
+ * label: ["label-1", "label-2"]
2641
2668
  * });
2642
2669
  * ```
2643
2670
  */
2644
- label;
2671
+ labels;
2672
+ /**
2673
+ * Label of the workflow run.
2674
+ *
2675
+ * @deprecated Use `labels` instead. When a run has multiple labels, this
2676
+ * only returns the first one.
2677
+ */
2678
+ get label() {
2679
+ return this.labels[0];
2680
+ }
2645
2681
  /**
2646
2682
  * Number of times QStash has retried delivering the current request.
2647
2683
  *
@@ -2672,7 +2708,7 @@ var WorkflowContext = class {
2672
2708
  this.headers = headers;
2673
2709
  this.requestPayload = initialPayload;
2674
2710
  this.env = env ?? {};
2675
- this.label = label;
2711
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2676
2712
  this.retried = retried ?? 0;
2677
2713
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2678
2714
  middlewareManagerInstance.assignContext(this);
@@ -2753,8 +2789,10 @@ var WorkflowContext = class {
2753
2789
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2754
2790
  }
2755
2791
  async call(stepName, settings) {
2792
+ validateFlowControl(settings.flowControl);
2756
2793
  let callStep;
2757
2794
  if ("workflow" in settings) {
2795
+ validateLabel(settings.label);
2758
2796
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2759
2797
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2760
2798
  callStep = new LazyCallStep({
@@ -2862,6 +2900,8 @@ var WorkflowContext = class {
2862
2900
  );
2863
2901
  }
2864
2902
  async invoke(stepName, settings) {
2903
+ validateLabel(settings.label);
2904
+ validateFlowControl(settings.flowControl);
2865
2905
  return await this.addStep(
2866
2906
  new LazyInvokeStep(this, stepName, settings)
2867
2907
  );
@@ -2947,7 +2987,7 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2947
2987
  url: context.url,
2948
2988
  initialPayload: context.requestPayload,
2949
2989
  env: context.env,
2950
- label: context.label,
2990
+ label: context.labels,
2951
2991
  retried: context.retried
2952
2992
  });
2953
2993
  try {
package/solidjs.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase
4
- } from "./chunk-G24J5PCC.mjs";
4
+ } from "./chunk-CWCCIOXR.mjs";
5
5
 
6
6
  // platforms/solidjs.ts
7
7
  var serve = (routeFunction, options) => {
package/svelte.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _sveltejs_kit from '@sveltejs/kit';
2
2
  import { RequestHandler } from '@sveltejs/kit';
3
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.mjs';
4
- import { s as serveManyBase } from './serve-many-D3D9uE4u.mjs';
3
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.mjs';
4
+ import { s as serveManyBase } from './serve-many-CG3BFvO3.mjs';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
 
package/svelte.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _sveltejs_kit from '@sveltejs/kit';
2
2
  import { RequestHandler } from '@sveltejs/kit';
3
- import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-B_E1VAK6.js';
4
- import { s as serveManyBase } from './serve-many-kPOasiyb.js';
3
+ import { c as RouteFunction, d as WorkflowServeOptions, I as InvokableWorkflow } from './types-CekOpKvz.js';
4
+ import { s as serveManyBase } from './serve-many-iJF1IUXk.js';
5
5
  import '@upstash/qstash';
6
6
  import 'zod';
7
7
 
package/svelte.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/svelte.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/svelte.ts
8
8
  var telemetry = {
package/tanstack.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, 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, E as ExclusiveValidationOptions, 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/tanstack.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { c as RouteFunction, d as WorkflowServeOptions, E as ExclusiveValidationOptions, 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, E as ExclusiveValidationOptions, 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