@upstash/workflow 1.2.1 → 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 (51) hide show
  1. package/README.md +10 -0
  2. package/astro.d.mts +2 -2
  3. package/astro.d.ts +2 -2
  4. package/astro.js +80 -14
  5. package/astro.mjs +1 -1
  6. package/{chunk-THS5AX2D.mjs → chunk-CWCCIOXR.mjs} +83 -14
  7. package/cloudflare.d.mts +2 -2
  8. package/cloudflare.d.ts +2 -2
  9. package/cloudflare.js +80 -14
  10. package/cloudflare.mjs +1 -1
  11. package/express.d.mts +2 -2
  12. package/express.d.ts +2 -2
  13. package/express.js +80 -14
  14. package/express.mjs +1 -1
  15. package/h3.d.mts +2 -2
  16. package/h3.d.ts +2 -2
  17. package/h3.js +80 -14
  18. package/h3.mjs +1 -1
  19. package/hono.d.mts +2 -2
  20. package/hono.d.ts +2 -2
  21. package/hono.js +80 -14
  22. package/hono.mjs +1 -1
  23. package/index.d.mts +24 -5
  24. package/index.d.ts +24 -5
  25. package/index.js +83 -15
  26. package/index.mjs +8 -3
  27. package/nextjs.d.mts +2 -2
  28. package/nextjs.d.ts +2 -2
  29. package/nextjs.js +80 -14
  30. package/nextjs.mjs +1 -1
  31. package/package.json +1 -1
  32. package/react-router.d.mts +2 -2
  33. package/react-router.d.ts +2 -2
  34. package/react-router.js +80 -14
  35. package/react-router.mjs +1 -1
  36. package/{serve-many-C6sa_DxN.d.mts → serve-many-CG3BFvO3.d.mts} +1 -1
  37. package/{serve-many-B-fe7bh7.d.ts → serve-many-iJF1IUXk.d.ts} +1 -1
  38. package/solidjs.d.mts +1 -1
  39. package/solidjs.d.ts +1 -1
  40. package/solidjs.js +80 -14
  41. package/solidjs.mjs +1 -1
  42. package/svelte.d.mts +2 -2
  43. package/svelte.d.ts +2 -2
  44. package/svelte.js +80 -14
  45. package/svelte.mjs +1 -1
  46. package/tanstack.d.mts +2 -2
  47. package/tanstack.d.ts +2 -2
  48. package/tanstack.js +80 -14
  49. package/tanstack.mjs +1 -1
  50. package/{types-B2S08hRU.d.ts → types-CekOpKvz.d.mts} +23 -7
  51. package/{types-B2S08hRU.d.mts → types-CekOpKvz.d.ts} +23 -7
package/react-router.js CHANGED
@@ -35,6 +35,7 @@ var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
35
35
  var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
36
36
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
37
37
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
38
+ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
38
39
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
39
40
  var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
40
41
  var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
@@ -43,7 +44,7 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
43
44
  var DEFAULT_CONTENT_TYPE = "application/json";
44
45
  var NO_CONCURRENCY = 1;
45
46
  var DEFAULT_RETRIES = 3;
46
- var VERSION = "v1.0.0";
47
+ var VERSION = "v1.2.1";
47
48
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
48
49
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
49
50
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -215,6 +216,31 @@ var import_qstash4 = require("@upstash/qstash");
215
216
  // src/utils.ts
216
217
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
217
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
+ }
218
244
  function getRandomInt() {
219
245
  return Math.floor(Math.random() * NANOID_CHARS.length);
220
246
  }
@@ -750,8 +776,8 @@ var triggerFirstInvocation = async (params) => {
750
776
  if (unknownSdk) {
751
777
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
752
778
  }
753
- if (workflowContext.label) {
754
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
779
+ if (workflowContext.labels.length > 0) {
780
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
755
781
  }
756
782
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
757
783
  return {
@@ -855,6 +881,9 @@ var recreateUserHeaders = (headers) => {
855
881
  }
856
882
  return filteredHeaders;
857
883
  };
884
+ var isThirdPartyCallResult = (request) => {
885
+ return request.headers.get("Upstash-Workflow-Callback") !== null;
886
+ };
858
887
  var handleThirdPartyCallResult = async ({
859
888
  request,
860
889
  requestPayload,
@@ -864,7 +893,7 @@ var handleThirdPartyCallResult = async ({
864
893
  middlewareManager
865
894
  }) => {
866
895
  try {
867
- if (request.headers.get("Upstash-Workflow-Callback")) {
896
+ if (isThirdPartyCallResult(request)) {
868
897
  let callbackPayload;
869
898
  if (requestPayload) {
870
899
  callbackPayload = requestPayload;
@@ -1550,8 +1579,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1550
1579
  });
1551
1580
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1552
1581
  if (label) {
1553
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1554
- 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;
1555
1585
  }
1556
1586
  return { headers: triggerHeaders, contentType };
1557
1587
  }
@@ -2692,9 +2722,10 @@ var WorkflowContext = class {
2692
2722
  */
2693
2723
  env;
2694
2724
  /**
2695
- * Label to apply to the workflow run.
2725
+ * Labels attached to the workflow run.
2696
2726
  *
2697
- * 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[]`.
2698
2729
  *
2699
2730
  * Can be set by passing a `label` parameter when triggering the workflow
2700
2731
  * with `client.trigger`:
@@ -2702,11 +2733,27 @@ var WorkflowContext = class {
2702
2733
  * ```ts
2703
2734
  * await client.trigger({
2704
2735
  * url: "https://workflow-endpoint.com",
2705
- * label: "my-label"
2736
+ * label: ["label-1", "label-2"]
2706
2737
  * });
2707
2738
  * ```
2708
2739
  */
2709
- 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
+ }
2750
+ /**
2751
+ * Number of times QStash has retried delivering the current request.
2752
+ *
2753
+ * Sourced from the `Upstash-Retried` header. `0` on the first delivery,
2754
+ * `1` on the first retry, `2` on the second, and so on.
2755
+ */
2756
+ retried;
2710
2757
  constructor({
2711
2758
  qstashClient,
2712
2759
  workflowRunId,
@@ -2719,6 +2766,7 @@ var WorkflowContext = class {
2719
2766
  telemetry: telemetry2,
2720
2767
  invokeCount,
2721
2768
  label,
2769
+ retried,
2722
2770
  middlewareManager
2723
2771
  }) {
2724
2772
  this.qstashClient = qstashClient;
@@ -2729,7 +2777,8 @@ var WorkflowContext = class {
2729
2777
  this.headers = headers;
2730
2778
  this.requestPayload = initialPayload;
2731
2779
  this.env = env ?? {};
2732
- this.label = label;
2780
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2781
+ this.retried = retried ?? 0;
2733
2782
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2734
2783
  middlewareManagerInstance.assignContext(this);
2735
2784
  this.executor = new AutoExecutor(
@@ -2809,8 +2858,10 @@ var WorkflowContext = class {
2809
2858
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2810
2859
  }
2811
2860
  async call(stepName, settings) {
2861
+ validateFlowControl(settings.flowControl);
2812
2862
  let callStep;
2813
2863
  if ("workflow" in settings) {
2864
+ validateLabel(settings.label);
2814
2865
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2815
2866
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2816
2867
  callStep = new LazyCallStep({
@@ -2918,6 +2969,8 @@ var WorkflowContext = class {
2918
2969
  );
2919
2970
  }
2920
2971
  async invoke(stepName, settings) {
2972
+ validateLabel(settings.label);
2973
+ validateFlowControl(settings.flowControl);
2921
2974
  return await this.addStep(
2922
2975
  new LazyInvokeStep(this, stepName, settings)
2923
2976
  );
@@ -2993,7 +3046,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2993
3046
  const disabledContext = new _DisabledWorkflowContext({
2994
3047
  qstashClient: new import_qstash10.Client({
2995
3048
  baseUrl: "disabled-client",
2996
- token: "disabled-client"
3049
+ token: "disabled-client",
3050
+ devMode: false
2997
3051
  }),
2998
3052
  workflowRunId: context.workflowRunId,
2999
3053
  workflowRunCreatedAt: context.workflowRunCreatedAt,
@@ -3002,7 +3056,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
3002
3056
  url: context.url,
3003
3057
  initialPayload: context.requestPayload,
3004
3058
  env: context.env,
3005
- label: context.label
3059
+ label: context.labels,
3060
+ retried: context.retried
3006
3061
  });
3007
3062
  try {
3008
3063
  await routeFunction(disabledContext);
@@ -3218,6 +3273,7 @@ var handleFailure = async ({
3218
3273
  errorMessage = `Couldn't parse 'failResponse' in 'failureFunction', received: '${decodedBody}'`;
3219
3274
  }
3220
3275
  const userHeaders = recreateUserHeaders(request.headers);
3276
+ const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3221
3277
  const workflowContext = new WorkflowContext({
3222
3278
  qstashClient,
3223
3279
  workflowRunId,
@@ -3229,6 +3285,7 @@ var handleFailure = async ({
3229
3285
  telemetry: void 0,
3230
3286
  // not going to make requests in authentication check
3231
3287
  label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
3288
+ retried,
3232
3289
  workflowRunCreatedAt: workflowCreatedAt,
3233
3290
  middlewareManager: void 0
3234
3291
  });
@@ -3388,6 +3445,9 @@ var getReceiver = (environment, receiverConfig, region) => {
3388
3445
  if (receiverConfig === "set-to-undefined") {
3389
3446
  return void 0;
3390
3447
  }
3448
+ if (isQStashDevModeEnabled(environment)) {
3449
+ return new import_qstash11.Receiver({ devMode: true });
3450
+ }
3391
3451
  const receiverEnv = readReceiverEnvironmentVariables(environment, region);
3392
3452
  return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash11.Receiver({
3393
3453
  currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
@@ -3397,6 +3457,10 @@ var getReceiver = (environment, receiverConfig, region) => {
3397
3457
  return receiverConfig;
3398
3458
  }
3399
3459
  };
3460
+ var isQStashDevModeEnabled = (env) => {
3461
+ const value = env.QSTASH_DEV;
3462
+ return value === "true" || value === "1";
3463
+ };
3400
3464
  var getQStashHandlerOptions = (...params) => {
3401
3465
  const handlers = getQStashHandlers(...params);
3402
3466
  return {
@@ -3706,12 +3770,13 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
3706
3770
  );
3707
3771
  }
3708
3772
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
3773
+ const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3709
3774
  const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
3710
3775
  const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
3711
3776
  const workflowContext = new WorkflowContext({
3712
3777
  qstashClient: regionalClient,
3713
3778
  workflowRunId,
3714
- initialPayload: initialPayloadParser(rawInitialPayload),
3779
+ initialPayload: isThirdPartyCallResult(request) ? JSON.parse(rawInitialPayload) : initialPayloadParser(rawInitialPayload),
3715
3780
  headers: recreateUserHeaders(request.headers),
3716
3781
  steps,
3717
3782
  url: workflowUrl,
@@ -3719,6 +3784,7 @@ var serveBase = (routeFunction, telemetry2, options, internalOptions) => {
3719
3784
  telemetry: telemetry2,
3720
3785
  invokeCount,
3721
3786
  label,
3787
+ retried,
3722
3788
  workflowRunCreatedAt: Number(workflowRunCreatedAt),
3723
3789
  middlewareManager
3724
3790
  });
package/react-router.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-THS5AX2D.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-B2S08hRU.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-B2S08hRU.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-B2S08hRU.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-B2S08hRU.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
@@ -190,6 +190,7 @@ var WORKFLOW_FAILURE_HEADER = "Upstash-Workflow-Is-Failure";
190
190
  var WORKFLOW_FAILURE_CALLBACK_HEADER = "Upstash-Workflow-Failure-Callback";
191
191
  var WORKFLOW_FEATURE_HEADER = "Upstash-Feature-Set";
192
192
  var WORKFLOW_INVOKE_COUNT_HEADER = "Upstash-Workflow-Invoke-Count";
193
+ var WORKFLOW_RETRIED_HEADER = "Upstash-Retried";
193
194
  var WORKFLOW_LABEL_HEADER = "Upstash-Label";
194
195
  var WORKFLOW_UNKOWN_SDK_VERSION_HEADER = "Upstash-Workflow-Unknown-Sdk";
195
196
  var WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER = "upstash-workflow-trigger-by-sdk";
@@ -198,7 +199,7 @@ var WORKFLOW_PROTOCOL_VERSION_HEADER = "Upstash-Workflow-Sdk-Version";
198
199
  var DEFAULT_CONTENT_TYPE = "application/json";
199
200
  var NO_CONCURRENCY = 1;
200
201
  var DEFAULT_RETRIES = 3;
201
- var VERSION = "v1.0.0";
202
+ var VERSION = "v1.2.1";
202
203
  var SDK_TELEMETRY = `@upstash/workflow@${VERSION}`;
203
204
  var TELEMETRY_HEADER_SDK = "Upstash-Telemetry-Sdk";
204
205
  var TELEMETRY_HEADER_FRAMEWORK = "Upstash-Telemetry-Framework";
@@ -213,6 +214,31 @@ var import_qstash4 = require("@upstash/qstash");
213
214
  // src/utils.ts
214
215
  var NANOID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
215
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
+ }
216
242
  function getRandomInt() {
217
243
  return Math.floor(Math.random() * NANOID_CHARS.length);
218
244
  }
@@ -748,8 +774,8 @@ var triggerFirstInvocation = async (params) => {
748
774
  if (unknownSdk) {
749
775
  headers[WORKFLOW_UNKOWN_SDK_TRIGGER_HEADER] = "true";
750
776
  }
751
- if (workflowContext.label) {
752
- headers[WORKFLOW_LABEL_HEADER] = workflowContext.label;
777
+ if (workflowContext.labels.length > 0) {
778
+ headers[WORKFLOW_LABEL_HEADER] = serializeLabel(workflowContext.labels);
753
779
  }
754
780
  const body = typeof workflowContext.requestPayload === "string" ? workflowContext.requestPayload : JSON.stringify(workflowContext.requestPayload);
755
781
  return {
@@ -853,6 +879,9 @@ var recreateUserHeaders = (headers) => {
853
879
  }
854
880
  return filteredHeaders;
855
881
  };
882
+ var isThirdPartyCallResult = (request) => {
883
+ return request.headers.get("Upstash-Workflow-Callback") !== null;
884
+ };
856
885
  var handleThirdPartyCallResult = async ({
857
886
  request,
858
887
  requestPayload,
@@ -862,7 +891,7 @@ var handleThirdPartyCallResult = async ({
862
891
  middlewareManager
863
892
  }) => {
864
893
  try {
865
- if (request.headers.get("Upstash-Workflow-Callback")) {
894
+ if (isThirdPartyCallResult(request)) {
866
895
  let callbackPayload;
867
896
  if (requestPayload) {
868
897
  callbackPayload = requestPayload;
@@ -1548,8 +1577,9 @@ var LazyInvokeStep = class extends BaseLazyStep {
1548
1577
  });
1549
1578
  triggerHeaders["Upstash-Workflow-Invoke"] = "true";
1550
1579
  if (label) {
1551
- triggerHeaders[WORKFLOW_LABEL_HEADER] = label;
1552
- 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;
1553
1583
  }
1554
1584
  return { headers: triggerHeaders, contentType };
1555
1585
  }
@@ -2623,9 +2653,10 @@ var WorkflowContext = class {
2623
2653
  */
2624
2654
  env;
2625
2655
  /**
2626
- * Label to apply to the workflow run.
2656
+ * Labels attached to the workflow run.
2627
2657
  *
2628
- * 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[]`.
2629
2660
  *
2630
2661
  * Can be set by passing a `label` parameter when triggering the workflow
2631
2662
  * with `client.trigger`:
@@ -2633,11 +2664,27 @@ var WorkflowContext = class {
2633
2664
  * ```ts
2634
2665
  * await client.trigger({
2635
2666
  * url: "https://workflow-endpoint.com",
2636
- * label: "my-label"
2667
+ * label: ["label-1", "label-2"]
2637
2668
  * });
2638
2669
  * ```
2639
2670
  */
2640
- 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
+ }
2681
+ /**
2682
+ * Number of times QStash has retried delivering the current request.
2683
+ *
2684
+ * Sourced from the `Upstash-Retried` header. `0` on the first delivery,
2685
+ * `1` on the first retry, `2` on the second, and so on.
2686
+ */
2687
+ retried;
2641
2688
  constructor({
2642
2689
  qstashClient,
2643
2690
  workflowRunId,
@@ -2650,6 +2697,7 @@ var WorkflowContext = class {
2650
2697
  telemetry,
2651
2698
  invokeCount,
2652
2699
  label,
2700
+ retried,
2653
2701
  middlewareManager
2654
2702
  }) {
2655
2703
  this.qstashClient = qstashClient;
@@ -2660,7 +2708,8 @@ var WorkflowContext = class {
2660
2708
  this.headers = headers;
2661
2709
  this.requestPayload = initialPayload;
2662
2710
  this.env = env ?? {};
2663
- this.label = label;
2711
+ this.labels = label === void 0 ? [] : Array.isArray(label) ? label : label ? label.split(",") : [];
2712
+ this.retried = retried ?? 0;
2664
2713
  const middlewareManagerInstance = middlewareManager ?? new MiddlewareManager([]);
2665
2714
  middlewareManagerInstance.assignContext(this);
2666
2715
  this.executor = new AutoExecutor(
@@ -2740,8 +2789,10 @@ var WorkflowContext = class {
2740
2789
  await this.addStep(new LazySleepUntilStep(this, stepName, time));
2741
2790
  }
2742
2791
  async call(stepName, settings) {
2792
+ validateFlowControl(settings.flowControl);
2743
2793
  let callStep;
2744
2794
  if ("workflow" in settings) {
2795
+ validateLabel(settings.label);
2745
2796
  const url = getNewUrlFromWorkflowId(this.url, settings.workflow.workflowId);
2746
2797
  const stringBody = typeof settings.body === "string" ? settings.body : settings.body === void 0 ? void 0 : JSON.stringify(settings.body);
2747
2798
  callStep = new LazyCallStep({
@@ -2849,6 +2900,8 @@ var WorkflowContext = class {
2849
2900
  );
2850
2901
  }
2851
2902
  async invoke(stepName, settings) {
2903
+ validateLabel(settings.label);
2904
+ validateFlowControl(settings.flowControl);
2852
2905
  return await this.addStep(
2853
2906
  new LazyInvokeStep(this, stepName, settings)
2854
2907
  );
@@ -2924,7 +2977,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2924
2977
  const disabledContext = new _DisabledWorkflowContext({
2925
2978
  qstashClient: new import_qstash10.Client({
2926
2979
  baseUrl: "disabled-client",
2927
- token: "disabled-client"
2980
+ token: "disabled-client",
2981
+ devMode: false
2928
2982
  }),
2929
2983
  workflowRunId: context.workflowRunId,
2930
2984
  workflowRunCreatedAt: context.workflowRunCreatedAt,
@@ -2933,7 +2987,8 @@ var DisabledWorkflowContext = class _DisabledWorkflowContext extends WorkflowCon
2933
2987
  url: context.url,
2934
2988
  initialPayload: context.requestPayload,
2935
2989
  env: context.env,
2936
- label: context.label
2990
+ label: context.labels,
2991
+ retried: context.retried
2937
2992
  });
2938
2993
  try {
2939
2994
  await routeFunction(disabledContext);
@@ -3149,6 +3204,7 @@ var handleFailure = async ({
3149
3204
  errorMessage = `Couldn't parse 'failResponse' in 'failureFunction', received: '${decodedBody}'`;
3150
3205
  }
3151
3206
  const userHeaders = recreateUserHeaders(request.headers);
3207
+ const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3152
3208
  const workflowContext = new WorkflowContext({
3153
3209
  qstashClient,
3154
3210
  workflowRunId,
@@ -3160,6 +3216,7 @@ var handleFailure = async ({
3160
3216
  telemetry: void 0,
3161
3217
  // not going to make requests in authentication check
3162
3218
  label: userHeaders.get(WORKFLOW_LABEL_HEADER) ?? void 0,
3219
+ retried,
3163
3220
  workflowRunCreatedAt: workflowCreatedAt,
3164
3221
  middlewareManager: void 0
3165
3222
  });
@@ -3319,6 +3376,9 @@ var getReceiver = (environment, receiverConfig, region) => {
3319
3376
  if (receiverConfig === "set-to-undefined") {
3320
3377
  return void 0;
3321
3378
  }
3379
+ if (isQStashDevModeEnabled(environment)) {
3380
+ return new import_qstash11.Receiver({ devMode: true });
3381
+ }
3322
3382
  const receiverEnv = readReceiverEnvironmentVariables(environment, region);
3323
3383
  return receiverEnv.QSTASH_CURRENT_SIGNING_KEY && receiverEnv.QSTASH_NEXT_SIGNING_KEY ? new import_qstash11.Receiver({
3324
3384
  currentSigningKey: receiverEnv.QSTASH_CURRENT_SIGNING_KEY,
@@ -3328,6 +3388,10 @@ var getReceiver = (environment, receiverConfig, region) => {
3328
3388
  return receiverConfig;
3329
3389
  }
3330
3390
  };
3391
+ var isQStashDevModeEnabled = (env) => {
3392
+ const value = env.QSTASH_DEV;
3393
+ return value === "true" || value === "1";
3394
+ };
3331
3395
  var getQStashHandlerOptions = (...params) => {
3332
3396
  const handlers = getQStashHandlers(...params);
3333
3397
  return {
@@ -3637,12 +3701,13 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
3637
3701
  );
3638
3702
  }
3639
3703
  const invokeCount = Number(request.headers.get(WORKFLOW_INVOKE_COUNT_HEADER) ?? "0");
3704
+ const retried = Number(request.headers.get(WORKFLOW_RETRIED_HEADER) ?? "0");
3640
3705
  const label = request.headers.get(WORKFLOW_LABEL_HEADER) ?? void 0;
3641
3706
  const workflowRunCreatedAt = request.headers.get(WORKFLOW_CREATED_AT_HEADER);
3642
3707
  const workflowContext = new WorkflowContext({
3643
3708
  qstashClient: regionalClient,
3644
3709
  workflowRunId,
3645
- initialPayload: initialPayloadParser(rawInitialPayload),
3710
+ initialPayload: isThirdPartyCallResult(request) ? JSON.parse(rawInitialPayload) : initialPayloadParser(rawInitialPayload),
3646
3711
  headers: recreateUserHeaders(request.headers),
3647
3712
  steps,
3648
3713
  url: workflowUrl,
@@ -3650,6 +3715,7 @@ var serveBase = (routeFunction, telemetry, options, internalOptions) => {
3650
3715
  telemetry,
3651
3716
  invokeCount,
3652
3717
  label,
3718
+ retried,
3653
3719
  workflowRunCreatedAt: Number(workflowRunCreatedAt),
3654
3720
  middlewareManager
3655
3721
  });
package/solidjs.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase
4
- } from "./chunk-THS5AX2D.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-B2S08hRU.mjs';
4
- import { s as serveManyBase } from './serve-many-C6sa_DxN.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-B2S08hRU.js';
4
- import { s as serveManyBase } from './serve-many-B-fe7bh7.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