@upstash/workflow 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/astro.js CHANGED
@@ -142,8 +142,15 @@ function isInstanceOf(v, ctor) {
142
142
  }
143
143
 
144
144
  // src/client/utils.ts
145
+ var assertNonEmptyId = (id, label = "id") => {
146
+ if (!id) {
147
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
148
+ }
149
+ };
145
150
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
146
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
151
+ assertNonEmptyId(eventId, "Event id");
152
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
153
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
147
154
  const result = await requester.request({
148
155
  path,
149
156
  method: "POST",
package/astro.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/astro.ts
8
8
  var telemetry = {
@@ -232,8 +232,20 @@ import { QstashError as QstashError4 } from "@upstash/qstash";
232
232
 
233
233
  // src/client/utils.ts
234
234
  import { QstashError as QstashError2 } from "@upstash/qstash";
235
+ var assertNonEmptyId = (id, label = "id") => {
236
+ if (!id) {
237
+ throw new QstashError2(`${label} cannot be empty`);
238
+ }
239
+ };
240
+ var toNonEmptyIdArray = (request, label = "id") => {
241
+ const ids = typeof request === "string" ? [request] : request;
242
+ for (const id of ids) assertNonEmptyId(id, label);
243
+ return ids;
244
+ };
235
245
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
236
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
246
+ assertNonEmptyId(eventId, "Event id");
247
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
248
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
237
249
  const result = await requester.request({
238
250
  path,
239
251
  method: "POST",
@@ -242,6 +254,7 @@ var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) =>
242
254
  return result;
243
255
  };
244
256
  var makeGetWaitersRequest = async (requester, eventId) => {
257
+ assertNonEmptyId(eventId, "Event id");
245
258
  const result = await requester.request({
246
259
  path: ["v2", "waiters", eventId],
247
260
  method: "GET"
@@ -328,6 +341,13 @@ function buildBulkActionQueryParameters(request, options) {
328
341
  "No filter provided. Use { filter: { ... } } with at least one filter field, or { all: true }."
329
342
  );
330
343
  }
344
+ for (const [field, value] of Object.entries(filter)) {
345
+ if (Array.isArray(value) && value.length === 0) {
346
+ throw new QstashError2(
347
+ `Empty array provided for filter field '${field}'. If you intend to target all records, use { all: true } explicitly.`
348
+ );
349
+ }
350
+ }
331
351
  if (options?.translateWorkflowUrl) {
332
352
  const { workflowUrlStartingWith, workflowUrl, ...rest } = filter;
333
353
  if (workflowUrlStartingWith && workflowUrl) {
@@ -3984,6 +4004,8 @@ export {
3984
4004
  WorkflowAbort,
3985
4005
  WorkflowNonRetryableError,
3986
4006
  WorkflowRetryAfterError,
4007
+ assertNonEmptyId,
4008
+ toNonEmptyIdArray,
3987
4009
  makeNotifyRequest,
3988
4010
  makeGetWaitersRequest,
3989
4011
  normalizeCursor,
package/cloudflare.js CHANGED
@@ -167,8 +167,15 @@ function isInstanceOf(v, ctor) {
167
167
  }
168
168
 
169
169
  // src/client/utils.ts
170
+ var assertNonEmptyId = (id, label = "id") => {
171
+ if (!id) {
172
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
173
+ }
174
+ };
170
175
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
171
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
176
+ assertNonEmptyId(eventId, "Event id");
177
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
178
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
172
179
  const result = await requester.request({
173
180
  path,
174
181
  method: "POST",
package/cloudflare.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/cloudflare.ts
8
8
  var getArgs = (args) => {
package/express.js CHANGED
@@ -167,8 +167,15 @@ function isInstanceOf(v, ctor) {
167
167
  }
168
168
 
169
169
  // src/client/utils.ts
170
+ var assertNonEmptyId = (id, label = "id") => {
171
+ if (!id) {
172
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
173
+ }
174
+ };
170
175
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
171
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
176
+ assertNonEmptyId(eventId, "Event id");
177
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
178
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
172
179
  const result = await requester.request({
173
180
  path,
174
181
  method: "POST",
package/express.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/express.ts
8
8
  import {
package/h3.js CHANGED
@@ -451,8 +451,15 @@ function isInstanceOf(v, ctor) {
451
451
  }
452
452
 
453
453
  // src/client/utils.ts
454
+ var assertNonEmptyId = (id, label = "id") => {
455
+ if (!id) {
456
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
457
+ }
458
+ };
454
459
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
455
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
460
+ assertNonEmptyId(eventId, "Event id");
461
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
462
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
456
463
  const result = await requester.request({
457
464
  path,
458
465
  method: "POST",
package/h3.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // node_modules/defu/dist/defu.mjs
8
8
  function isPlainObject(value) {
package/hono.js CHANGED
@@ -142,8 +142,15 @@ function isInstanceOf(v, ctor) {
142
142
  }
143
143
 
144
144
  // src/client/utils.ts
145
+ var assertNonEmptyId = (id, label = "id") => {
146
+ if (!id) {
147
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
148
+ }
149
+ };
145
150
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
146
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
151
+ assertNonEmptyId(eventId, "Event id");
152
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
153
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
147
154
  const result = await requester.request({
148
155
  path,
149
156
  method: "POST",
package/hono.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/hono.ts
8
8
  var telemetry = {
package/index.d.mts CHANGED
@@ -221,7 +221,7 @@ type FailureFunctionLog = {
221
221
  /**
222
222
  * State of the message published for failure
223
223
  */
224
- state: "CALLBACK_INPROGRESS" | "CALLBACK_SUCCESS" | "CALLBACK_FAIL";
224
+ state: "CALLBACK_INPROGRESS" | "CALLBACK_SUCCESS" | "CALLBACK_FAIL" | "CALLBACK_CANCELED";
225
225
  /**
226
226
  * Headers received from the step which caused the workflow to fail
227
227
  */
@@ -538,14 +538,21 @@ declare const serveBase: <TInitialPayload = unknown, TRequest extends Request =
538
538
  */
539
539
  declare const serve: <TInitialPayload = unknown, TRequest extends Request = Request, TResponse extends Response = Response, TResult = unknown>(routeFunction: RouteFunction<TInitialPayload, TResult>, options?: WorkflowServeOptions<TInitialPayload, TResult>) => ReturnType<typeof serveBase<TInitialPayload, TRequest, TResponse, TResult>>;
540
540
 
541
- type RequireAtLeastOne<T> = {
541
+ type RequireAtLeastOne<T> = T & {
542
542
  [K in keyof T]-?: Required<Pick<T, K>>;
543
543
  }[keyof T];
544
- /** Shared filter fields accepted by every qstash & workflow endpoint. */
544
+ /**
545
+ * Shared filter fields accepted by every qstash & workflow endpoint.
546
+ *
547
+ * Most fields support multi-value filtering: pass an array to match a record
548
+ * whose value equals any of the given values (OR semantics). Separate filters
549
+ * are combined with AND semantics.
550
+ */
545
551
  type UniversalFilterFields = {
546
552
  fromDate?: Date | number;
547
553
  toDate?: Date | number;
548
- callerIp?: string;
554
+ /** Filter by the IP address of the publisher. Supports multiple values. */
555
+ callerIp?: string | string[];
549
556
  /**
550
557
  * Filter by label.
551
558
  *
@@ -554,11 +561,13 @@ type UniversalFilterFields = {
554
561
  * filtering by `[label_1, label_2]` returns both.
555
562
  */
556
563
  label?: string | string[];
557
- flowControlKey?: string;
564
+ /** Filter by Flow Control Key. Supports multiple values. */
565
+ flowControlKey?: string | string[];
558
566
  };
559
567
  /** Workflow-specific filter fields for DLQ and bulk endpoints. */
560
568
  type WorkflowFilterFields = {
561
- workflowUrl?: string;
569
+ /** Filter by workflow URL. Supports multiple values. */
570
+ workflowUrl?: string | string[];
562
571
  workflowRunId?: string;
563
572
  workflowCreatedAt?: number;
564
573
  failureFunctionState?: string;
@@ -567,19 +576,33 @@ type WorkflowLogsFilterFields = {
567
576
  state?: WorkflowRunLog["workflowState"];
568
577
  messageId?: string;
569
578
  };
579
+ /**
580
+ * Filter by the host/path of the workflow URL.
581
+ *
582
+ * Supported by the cancel and logs endpoints (the DLQ endpoint rejects these).
583
+ * Each supports multiple values: pass an array to match any value.
584
+ */
585
+ type HostPathFilterFields = {
586
+ /** Filter by the host of the workflow URL. Supports multiple values. */
587
+ host?: string | string[];
588
+ /** Filter by the path of the workflow URL. Supports multiple values. */
589
+ path?: string | string[];
590
+ };
570
591
  type DLQActionFilterFields = UniversalFilterFields & WorkflowFilterFields;
571
592
  /** Cancel filter: exact URL match. Cannot combine with `workflowUrlStartingWith`. */
572
- type CancelFilterWithExactUrl = UniversalFilterFields & {
573
- workflowUrl: string;
593
+ type CancelFilterWithExactUrl = UniversalFilterFields & HostPathFilterFields & {
594
+ /** Filter by exact workflow URL. Supports multiple values. */
595
+ workflowUrl: string | string[];
574
596
  workflowUrlStartingWith?: never;
575
597
  };
576
598
  /** Cancel filter: URL prefix match. Cannot combine with `workflowUrl`. */
577
- type CancelFilterWithPrefixUrl = UniversalFilterFields & {
578
- workflowUrlStartingWith: string;
599
+ type CancelFilterWithPrefixUrl = UniversalFilterFields & HostPathFilterFields & {
600
+ /** Filter by workflow URL prefix. Supports multiple values. */
601
+ workflowUrlStartingWith: string | string[];
579
602
  workflowUrl?: never;
580
603
  };
581
604
  /** Cancel filter: no URL. Requires at least one other filter field. */
582
- type CancelFilterWithoutUrl = RequireAtLeastOne<UniversalFilterFields> & {
605
+ type CancelFilterWithoutUrl = RequireAtLeastOne<UniversalFilterFields & HostPathFilterFields> & {
583
606
  workflowUrl?: never;
584
607
  workflowUrlStartingWith?: never;
585
608
  };
@@ -650,14 +673,14 @@ type WorkflowRunCancelFilters = {
650
673
  workflowRunIds?: never;
651
674
  filter?: never;
652
675
  } & WorkflowCancelCount);
653
- type WorkflowLogsListFilters = UniversalFilterFields & Pick<WorkflowFilterFields, "workflowUrl" | "workflowRunId" | "workflowCreatedAt"> & WorkflowLogsFilterFields;
676
+ type WorkflowLogsListFilters = UniversalFilterFields & Pick<WorkflowFilterFields, "workflowUrl" | "workflowRunId" | "workflowCreatedAt"> & HostPathFilterFields & WorkflowLogsFilterFields;
654
677
 
655
678
  type ResumeRestartOptions = {
656
679
  flowControl?: FlowControl;
657
680
  retries?: number;
658
681
  };
659
682
  type FailureCallbackInfo = {
660
- state?: "CALLBACK_FAIL" | "CALLBACK_SUCCESS" | "CALLBACK_INPROGRESS";
683
+ state?: "CALLBACK_FAIL" | "CALLBACK_SUCCESS" | "CALLBACK_INPROGRESS" | "CALLBACK_CANCELED";
661
684
  responseStatus?: number;
662
685
  responseBody?: string;
663
686
  responseHeaders?: Record<string, string[]>;
@@ -863,6 +886,11 @@ declare class Client {
863
886
  * - With other filters: `cancel({ filter: { label: "my-label" } })`
864
887
  * - To target all: `cancel({ all: true })`
865
888
  *
889
+ * Filters support multiple values: pass an array to match a run whose value
890
+ * equals any of the given values (OR logic). Separate filters are combined with
891
+ * AND logic. For example:
892
+ * `cancel({ filter: { workflowUrl: ["https://a.com", "https://b.com"] } })`
893
+ *
866
894
  * Cancels up to `count` workflow runs per call (defaults to 100).
867
895
  *
868
896
  * ```ts
package/index.d.ts CHANGED
@@ -221,7 +221,7 @@ type FailureFunctionLog = {
221
221
  /**
222
222
  * State of the message published for failure
223
223
  */
224
- state: "CALLBACK_INPROGRESS" | "CALLBACK_SUCCESS" | "CALLBACK_FAIL";
224
+ state: "CALLBACK_INPROGRESS" | "CALLBACK_SUCCESS" | "CALLBACK_FAIL" | "CALLBACK_CANCELED";
225
225
  /**
226
226
  * Headers received from the step which caused the workflow to fail
227
227
  */
@@ -538,14 +538,21 @@ declare const serveBase: <TInitialPayload = unknown, TRequest extends Request =
538
538
  */
539
539
  declare const serve: <TInitialPayload = unknown, TRequest extends Request = Request, TResponse extends Response = Response, TResult = unknown>(routeFunction: RouteFunction<TInitialPayload, TResult>, options?: WorkflowServeOptions<TInitialPayload, TResult>) => ReturnType<typeof serveBase<TInitialPayload, TRequest, TResponse, TResult>>;
540
540
 
541
- type RequireAtLeastOne<T> = {
541
+ type RequireAtLeastOne<T> = T & {
542
542
  [K in keyof T]-?: Required<Pick<T, K>>;
543
543
  }[keyof T];
544
- /** Shared filter fields accepted by every qstash & workflow endpoint. */
544
+ /**
545
+ * Shared filter fields accepted by every qstash & workflow endpoint.
546
+ *
547
+ * Most fields support multi-value filtering: pass an array to match a record
548
+ * whose value equals any of the given values (OR semantics). Separate filters
549
+ * are combined with AND semantics.
550
+ */
545
551
  type UniversalFilterFields = {
546
552
  fromDate?: Date | number;
547
553
  toDate?: Date | number;
548
- callerIp?: string;
554
+ /** Filter by the IP address of the publisher. Supports multiple values. */
555
+ callerIp?: string | string[];
549
556
  /**
550
557
  * Filter by label.
551
558
  *
@@ -554,11 +561,13 @@ type UniversalFilterFields = {
554
561
  * filtering by `[label_1, label_2]` returns both.
555
562
  */
556
563
  label?: string | string[];
557
- flowControlKey?: string;
564
+ /** Filter by Flow Control Key. Supports multiple values. */
565
+ flowControlKey?: string | string[];
558
566
  };
559
567
  /** Workflow-specific filter fields for DLQ and bulk endpoints. */
560
568
  type WorkflowFilterFields = {
561
- workflowUrl?: string;
569
+ /** Filter by workflow URL. Supports multiple values. */
570
+ workflowUrl?: string | string[];
562
571
  workflowRunId?: string;
563
572
  workflowCreatedAt?: number;
564
573
  failureFunctionState?: string;
@@ -567,19 +576,33 @@ type WorkflowLogsFilterFields = {
567
576
  state?: WorkflowRunLog["workflowState"];
568
577
  messageId?: string;
569
578
  };
579
+ /**
580
+ * Filter by the host/path of the workflow URL.
581
+ *
582
+ * Supported by the cancel and logs endpoints (the DLQ endpoint rejects these).
583
+ * Each supports multiple values: pass an array to match any value.
584
+ */
585
+ type HostPathFilterFields = {
586
+ /** Filter by the host of the workflow URL. Supports multiple values. */
587
+ host?: string | string[];
588
+ /** Filter by the path of the workflow URL. Supports multiple values. */
589
+ path?: string | string[];
590
+ };
570
591
  type DLQActionFilterFields = UniversalFilterFields & WorkflowFilterFields;
571
592
  /** Cancel filter: exact URL match. Cannot combine with `workflowUrlStartingWith`. */
572
- type CancelFilterWithExactUrl = UniversalFilterFields & {
573
- workflowUrl: string;
593
+ type CancelFilterWithExactUrl = UniversalFilterFields & HostPathFilterFields & {
594
+ /** Filter by exact workflow URL. Supports multiple values. */
595
+ workflowUrl: string | string[];
574
596
  workflowUrlStartingWith?: never;
575
597
  };
576
598
  /** Cancel filter: URL prefix match. Cannot combine with `workflowUrl`. */
577
- type CancelFilterWithPrefixUrl = UniversalFilterFields & {
578
- workflowUrlStartingWith: string;
599
+ type CancelFilterWithPrefixUrl = UniversalFilterFields & HostPathFilterFields & {
600
+ /** Filter by workflow URL prefix. Supports multiple values. */
601
+ workflowUrlStartingWith: string | string[];
579
602
  workflowUrl?: never;
580
603
  };
581
604
  /** Cancel filter: no URL. Requires at least one other filter field. */
582
- type CancelFilterWithoutUrl = RequireAtLeastOne<UniversalFilterFields> & {
605
+ type CancelFilterWithoutUrl = RequireAtLeastOne<UniversalFilterFields & HostPathFilterFields> & {
583
606
  workflowUrl?: never;
584
607
  workflowUrlStartingWith?: never;
585
608
  };
@@ -650,14 +673,14 @@ type WorkflowRunCancelFilters = {
650
673
  workflowRunIds?: never;
651
674
  filter?: never;
652
675
  } & WorkflowCancelCount);
653
- type WorkflowLogsListFilters = UniversalFilterFields & Pick<WorkflowFilterFields, "workflowUrl" | "workflowRunId" | "workflowCreatedAt"> & WorkflowLogsFilterFields;
676
+ type WorkflowLogsListFilters = UniversalFilterFields & Pick<WorkflowFilterFields, "workflowUrl" | "workflowRunId" | "workflowCreatedAt"> & HostPathFilterFields & WorkflowLogsFilterFields;
654
677
 
655
678
  type ResumeRestartOptions = {
656
679
  flowControl?: FlowControl;
657
680
  retries?: number;
658
681
  };
659
682
  type FailureCallbackInfo = {
660
- state?: "CALLBACK_FAIL" | "CALLBACK_SUCCESS" | "CALLBACK_INPROGRESS";
683
+ state?: "CALLBACK_FAIL" | "CALLBACK_SUCCESS" | "CALLBACK_INPROGRESS" | "CALLBACK_CANCELED";
661
684
  responseStatus?: number;
662
685
  responseBody?: string;
663
686
  responseHeaders?: Record<string, string[]>;
@@ -863,6 +886,11 @@ declare class Client {
863
886
  * - With other filters: `cancel({ filter: { label: "my-label" } })`
864
887
  * - To target all: `cancel({ all: true })`
865
888
  *
889
+ * Filters support multiple values: pass an array to match a run whose value
890
+ * equals any of the given values (OR logic). Separate filters are combined with
891
+ * AND logic. For example:
892
+ * `cancel({ filter: { workflowUrl: ["https://a.com", "https://b.com"] } })`
893
+ *
866
894
  * Cancels up to `count` workflow runs per call (defaults to 100).
867
895
  *
868
896
  * ```ts
package/index.js CHANGED
@@ -149,8 +149,20 @@ function isInstanceOf(v, ctor) {
149
149
  }
150
150
 
151
151
  // src/client/utils.ts
152
+ var assertNonEmptyId = (id, label = "id") => {
153
+ if (!id) {
154
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
155
+ }
156
+ };
157
+ var toNonEmptyIdArray = (request, label = "id") => {
158
+ const ids = typeof request === "string" ? [request] : request;
159
+ for (const id of ids) assertNonEmptyId(id, label);
160
+ return ids;
161
+ };
152
162
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
153
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
163
+ assertNonEmptyId(eventId, "Event id");
164
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
165
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
154
166
  const result = await requester.request({
155
167
  path,
156
168
  method: "POST",
@@ -159,6 +171,7 @@ var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) =>
159
171
  return result;
160
172
  };
161
173
  var makeGetWaitersRequest = async (requester, eventId) => {
174
+ assertNonEmptyId(eventId, "Event id");
162
175
  const result = await requester.request({
163
176
  path: ["v2", "waiters", eventId],
164
177
  method: "GET"
@@ -245,6 +258,13 @@ function buildBulkActionQueryParameters(request, options) {
245
258
  "No filter provided. Use { filter: { ... } } with at least one filter field, or { all: true }."
246
259
  );
247
260
  }
261
+ for (const [field, value] of Object.entries(filter)) {
262
+ if (Array.isArray(value) && value.length === 0) {
263
+ throw new import_qstash2.QstashError(
264
+ `Empty array provided for filter field '${field}'. If you intend to target all records, use { all: true } explicitly.`
265
+ );
266
+ }
267
+ }
248
268
  if (options?.translateWorkflowUrl) {
249
269
  const { workflowUrlStartingWith, workflowUrl, ...rest } = filter;
250
270
  if (workflowUrlStartingWith && workflowUrl) {
@@ -4013,8 +4033,11 @@ var DLQ = class {
4013
4033
  });
4014
4034
  return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
4015
4035
  }
4016
- if (typeof request === "string") request = [request];
4017
- if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
4036
+ if (typeof request === "string" || Array.isArray(request)) {
4037
+ const ids = toNonEmptyIdArray(request, "DLQ id");
4038
+ if (ids.length === 0) return { workflowRuns: [] };
4039
+ request = ids;
4040
+ }
4018
4041
  const filters = Array.isArray(request) ? { dlqIds: request } : request;
4019
4042
  return normalizeCursor(
4020
4043
  await this.client.http.request({
@@ -4037,8 +4060,11 @@ var DLQ = class {
4037
4060
  });
4038
4061
  return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
4039
4062
  }
4040
- if (typeof request === "string") request = [request];
4041
- if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
4063
+ if (typeof request === "string" || Array.isArray(request)) {
4064
+ const ids = toNonEmptyIdArray(request, "DLQ id");
4065
+ if (ids.length === 0) return { workflowRuns: [] };
4066
+ request = ids;
4067
+ }
4042
4068
  const filters = Array.isArray(request) ? { dlqIds: request } : request;
4043
4069
  return normalizeCursor(
4044
4070
  await this.client.http.request({
@@ -4057,6 +4083,7 @@ var DLQ = class {
4057
4083
  * @returns response with workflow run information
4058
4084
  */
4059
4085
  async retryFailureFunction({ dlqId }) {
4086
+ assertNonEmptyId(dlqId, "DLQ id");
4060
4087
  const response = await this.client.http.request({
4061
4088
  path: ["v2", "workflows", "dlq", "callback", dlqId],
4062
4089
  method: "POST"
@@ -4084,8 +4111,11 @@ var DLQ = class {
4084
4111
  * ```
4085
4112
  */
4086
4113
  async delete(request) {
4087
- if (typeof request === "string") request = [request];
4088
- if (Array.isArray(request) && request.length === 0) return { deleted: 0 };
4114
+ if (typeof request === "string" || Array.isArray(request)) {
4115
+ const ids = toNonEmptyIdArray(request, "DLQ id");
4116
+ if (ids.length === 0) return { deleted: 0 };
4117
+ request = ids;
4118
+ }
4089
4119
  const filters = Array.isArray(request) ? { dlqIds: request } : request;
4090
4120
  return normalizeCursor(
4091
4121
  await this.client.http.request({
@@ -4114,8 +4144,11 @@ var Client4 = class {
4114
4144
  return this.cancel({ filter: { workflowUrlStartingWith: legacy.urlStartingWith } });
4115
4145
  }
4116
4146
  }
4117
- if (typeof request === "string") request = [request];
4118
- if (Array.isArray(request) && request.length === 0) return { cancelled: 0 };
4147
+ if (typeof request === "string" || Array.isArray(request)) {
4148
+ const ids = toNonEmptyIdArray(request, "Workflow run id");
4149
+ if (ids.length === 0) return { cancelled: 0 };
4150
+ request = ids;
4151
+ }
4119
4152
  const filters = Array.isArray(request) ? { workflowRunIds: request } : request;
4120
4153
  return await this.client.http.request({
4121
4154
  path: ["v2", "workflows", "runs"],
package/index.mjs CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  WorkflowMiddleware,
9
9
  WorkflowNonRetryableError,
10
10
  WorkflowRetryAfterError,
11
+ assertNonEmptyId,
11
12
  buildBulkActionQueryParameters,
12
13
  getWorkflowRunId,
13
14
  loggingMiddleware,
@@ -17,10 +18,11 @@ import {
17
18
  prepareFlowControl,
18
19
  serializeLabel,
19
20
  serve,
21
+ toNonEmptyIdArray,
20
22
  triggerFirstInvocation,
21
23
  validateFlowControl,
22
24
  validateLabel
23
- } from "./chunk-ICDNN4UW.mjs";
25
+ } from "./chunk-WEQGCISK.mjs";
24
26
 
25
27
  // src/client/index.ts
26
28
  import { Client as QStashClient } from "@upstash/qstash";
@@ -86,8 +88,11 @@ var DLQ = class {
86
88
  });
87
89
  return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
88
90
  }
89
- if (typeof request === "string") request = [request];
90
- if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
91
+ if (typeof request === "string" || Array.isArray(request)) {
92
+ const ids = toNonEmptyIdArray(request, "DLQ id");
93
+ if (ids.length === 0) return { workflowRuns: [] };
94
+ request = ids;
95
+ }
91
96
  const filters = Array.isArray(request) ? { dlqIds: request } : request;
92
97
  return normalizeCursor(
93
98
  await this.client.http.request({
@@ -110,8 +115,11 @@ var DLQ = class {
110
115
  });
111
116
  return Array.isArray(dlqId) ? workflowRuns : workflowRuns[0];
112
117
  }
113
- if (typeof request === "string") request = [request];
114
- if (Array.isArray(request) && request.length === 0) return { workflowRuns: [] };
118
+ if (typeof request === "string" || Array.isArray(request)) {
119
+ const ids = toNonEmptyIdArray(request, "DLQ id");
120
+ if (ids.length === 0) return { workflowRuns: [] };
121
+ request = ids;
122
+ }
115
123
  const filters = Array.isArray(request) ? { dlqIds: request } : request;
116
124
  return normalizeCursor(
117
125
  await this.client.http.request({
@@ -130,6 +138,7 @@ var DLQ = class {
130
138
  * @returns response with workflow run information
131
139
  */
132
140
  async retryFailureFunction({ dlqId }) {
141
+ assertNonEmptyId(dlqId, "DLQ id");
133
142
  const response = await this.client.http.request({
134
143
  path: ["v2", "workflows", "dlq", "callback", dlqId],
135
144
  method: "POST"
@@ -157,8 +166,11 @@ var DLQ = class {
157
166
  * ```
158
167
  */
159
168
  async delete(request) {
160
- if (typeof request === "string") request = [request];
161
- if (Array.isArray(request) && request.length === 0) return { deleted: 0 };
169
+ if (typeof request === "string" || Array.isArray(request)) {
170
+ const ids = toNonEmptyIdArray(request, "DLQ id");
171
+ if (ids.length === 0) return { deleted: 0 };
172
+ request = ids;
173
+ }
162
174
  const filters = Array.isArray(request) ? { dlqIds: request } : request;
163
175
  return normalizeCursor(
164
176
  await this.client.http.request({
@@ -187,8 +199,11 @@ var Client = class {
187
199
  return this.cancel({ filter: { workflowUrlStartingWith: legacy.urlStartingWith } });
188
200
  }
189
201
  }
190
- if (typeof request === "string") request = [request];
191
- if (Array.isArray(request) && request.length === 0) return { cancelled: 0 };
202
+ if (typeof request === "string" || Array.isArray(request)) {
203
+ const ids = toNonEmptyIdArray(request, "Workflow run id");
204
+ if (ids.length === 0) return { cancelled: 0 };
205
+ request = ids;
206
+ }
192
207
  const filters = Array.isArray(request) ? { workflowRunIds: request } : request;
193
208
  return await this.client.http.request({
194
209
  path: ["v2", "workflows", "runs"],
package/nextjs.js CHANGED
@@ -145,8 +145,15 @@ function isInstanceOf(v, ctor) {
145
145
  }
146
146
 
147
147
  // src/client/utils.ts
148
+ var assertNonEmptyId = (id, label = "id") => {
149
+ if (!id) {
150
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
151
+ }
152
+ };
148
153
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
149
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
154
+ assertNonEmptyId(eventId, "Event id");
155
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
156
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
150
157
  const result = await requester.request({
151
158
  path,
152
159
  method: "POST",
package/nextjs.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.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.2","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.3","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"}}
package/react-router.js CHANGED
@@ -167,8 +167,15 @@ function isInstanceOf(v, ctor) {
167
167
  }
168
168
 
169
169
  // src/client/utils.ts
170
+ var assertNonEmptyId = (id, label = "id") => {
171
+ if (!id) {
172
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
173
+ }
174
+ };
170
175
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
171
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
176
+ assertNonEmptyId(eventId, "Event id");
177
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
178
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
172
179
  const result = await requester.request({
173
180
  path,
174
181
  method: "POST",
package/react-router.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/react-router.ts
8
8
  var telemetry = {
package/solidjs.js CHANGED
@@ -140,8 +140,15 @@ function isInstanceOf(v, ctor) {
140
140
  }
141
141
 
142
142
  // src/client/utils.ts
143
+ var assertNonEmptyId = (id, label = "id") => {
144
+ if (!id) {
145
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
146
+ }
147
+ };
143
148
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
144
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
149
+ assertNonEmptyId(eventId, "Event id");
150
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
151
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
145
152
  const result = await requester.request({
146
153
  path,
147
154
  method: "POST",
package/solidjs.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase
4
- } from "./chunk-ICDNN4UW.mjs";
4
+ } from "./chunk-WEQGCISK.mjs";
5
5
 
6
6
  // platforms/solidjs.ts
7
7
  var serve = (routeFunction, options) => {
package/svelte.js CHANGED
@@ -142,8 +142,15 @@ function isInstanceOf(v, ctor) {
142
142
  }
143
143
 
144
144
  // src/client/utils.ts
145
+ var assertNonEmptyId = (id, label = "id") => {
146
+ if (!id) {
147
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
148
+ }
149
+ };
145
150
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
146
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
151
+ assertNonEmptyId(eventId, "Event id");
152
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
153
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
147
154
  const result = await requester.request({
148
155
  path,
149
156
  method: "POST",
package/svelte.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/svelte.ts
8
8
  var telemetry = {
package/tanstack.js CHANGED
@@ -142,8 +142,15 @@ function isInstanceOf(v, ctor) {
142
142
  }
143
143
 
144
144
  // src/client/utils.ts
145
+ var assertNonEmptyId = (id, label = "id") => {
146
+ if (!id) {
147
+ throw new import_qstash2.QstashError(`${label} cannot be empty`);
148
+ }
149
+ };
145
150
  var makeNotifyRequest = async (requester, eventId, eventData, workflowRunId) => {
146
- const path = workflowRunId ? ["v2", "notify", workflowRunId, eventId] : ["v2", "notify", eventId];
151
+ assertNonEmptyId(eventId, "Event id");
152
+ if (workflowRunId !== void 0) assertNonEmptyId(workflowRunId, "Workflow run id");
153
+ const path = workflowRunId === void 0 ? ["v2", "notify", eventId] : ["v2", "notify", workflowRunId, eventId];
147
154
  const result = await requester.request({
148
155
  path,
149
156
  method: "POST",
package/tanstack.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  SDK_TELEMETRY,
3
3
  serveBase,
4
4
  serveManyBase
5
- } from "./chunk-ICDNN4UW.mjs";
5
+ } from "./chunk-WEQGCISK.mjs";
6
6
 
7
7
  // platforms/tanstack.ts
8
8
  var telemetry = {