@upstash/qstash 2.9.0 → 2.9.1-rc.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.
package/workflow.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export { am as AsyncStepFunction, af as DisabledWorkflowContext, F as FailureFunctionPayload, ap as FinishCondition, ar as LogLevel, ao as ParallelCallState, ak as RawStep, aq as RequiredExceptFields, a9 as RouteFunction, S as Step, an as StepFunction, aj as StepType, ai as StepTypes, al as SyncStepFunction, ab as Workflow, ag as WorkflowClient, ae as WorkflowContext, at as WorkflowLogger, as as WorkflowLoggerOptions, ah as WorkflowReceiver, aa as WorkflowServeOptions, ac as processOptions, ad as serve } from './client-BVG9vt90.mjs';
1
+ export { an as AsyncStepFunction, ag as DisabledWorkflowContext, F as FailureFunctionPayload, aq as FinishCondition, as as LogLevel, ap as ParallelCallState, al as RawStep, ar as RequiredExceptFields, aa as RouteFunction, S as Step, ao as StepFunction, ak as StepType, aj as StepTypes, am as SyncStepFunction, ac as Workflow, ah as WorkflowClient, af as WorkflowContext, au as WorkflowLogger, at as WorkflowLoggerOptions, ai as WorkflowReceiver, ab as WorkflowServeOptions, ad as processOptions, ae as serve } from './client-Gv4WRTxB.mjs';
2
2
  import 'neverthrow';
package/workflow.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { am as AsyncStepFunction, af as DisabledWorkflowContext, F as FailureFunctionPayload, ap as FinishCondition, ar as LogLevel, ao as ParallelCallState, ak as RawStep, aq as RequiredExceptFields, a9 as RouteFunction, S as Step, an as StepFunction, aj as StepType, ai as StepTypes, al as SyncStepFunction, ab as Workflow, ag as WorkflowClient, ae as WorkflowContext, at as WorkflowLogger, as as WorkflowLoggerOptions, ah as WorkflowReceiver, aa as WorkflowServeOptions, ac as processOptions, ad as serve } from './client-BVG9vt90.js';
1
+ export { an as AsyncStepFunction, ag as DisabledWorkflowContext, F as FailureFunctionPayload, aq as FinishCondition, as as LogLevel, ap as ParallelCallState, al as RawStep, ar as RequiredExceptFields, aa as RouteFunction, S as Step, ao as StepFunction, ak as StepType, aj as StepTypes, am as SyncStepFunction, ac as Workflow, ah as WorkflowClient, af as WorkflowContext, au as WorkflowLogger, at as WorkflowLoggerOptions, ai as WorkflowReceiver, ab as WorkflowServeOptions, ad as processOptions, ae as serve } from './client-Gv4WRTxB.js';
2
2
  import 'neverthrow';
package/workflow.js CHANGED
@@ -398,6 +398,43 @@ function decodeBase64(base64) {
398
398
  }
399
399
  }
400
400
  }
401
+ function buildBulkActionFilterPayload(request, options) {
402
+ const hasDlqIds = "dlqIds" in request && request.dlqIds !== void 0;
403
+ const hasAll = "all" in request && Boolean(request.all);
404
+ const filterKeys = Object.keys(request).filter((k) => k !== "dlqIds" && k !== "all");
405
+ const hasFilters = filterKeys.length > 0;
406
+ if (hasDlqIds && hasAll) {
407
+ throw new QstashError("dlqIds and all: true are mutually exclusive.");
408
+ }
409
+ if (hasDlqIds && hasFilters) {
410
+ throw new QstashError(
411
+ `dlqIds cannot be combined with filter fields: ${filterKeys.join(", ")}.`
412
+ );
413
+ }
414
+ if (hasAll && hasFilters) {
415
+ throw new QstashError(
416
+ `all: true cannot be combined with filter fields: ${filterKeys.join(", ")}.`
417
+ );
418
+ }
419
+ if (hasAll)
420
+ return {};
421
+ const { urlGroup, callerIp, ...rest } = request;
422
+ const payload = {
423
+ ...rest,
424
+ ...urlGroup === void 0 || typeof urlGroup !== "string" ? {} : { topicName: urlGroup },
425
+ ...callerIp === void 0 || typeof callerIp !== "string" ? {} : options?.callerIpCasing ? { callerIP: callerIp } : { callerIp }
426
+ };
427
+ if (Object.keys(payload).length === 0) {
428
+ throw new QstashError(
429
+ "No filters provided. Pass { all: true } to explicitly target all messages."
430
+ );
431
+ }
432
+ return payload;
433
+ }
434
+ function normalizeCursor(response) {
435
+ const cursor = response.cursor;
436
+ return { ...response, cursor: cursor || void 0 };
437
+ }
401
438
  function getRuntime() {
402
439
  if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
403
440
  return `bun@${process.versions.bun}`;
@@ -627,17 +664,20 @@ var DLQ = class {
627
664
  /**
628
665
  * List messages in the dlq
629
666
  */
630
- async listMessages(options) {
667
+ async listMessages(options = {}) {
668
+ const { urlGroup, ...restFilter } = options.filter ?? {};
631
669
  const filterPayload = {
632
- ...options?.filter,
633
- topicName: options?.filter?.urlGroup
670
+ ...restFilter,
671
+ ...urlGroup === void 0 ? {} : { topicName: urlGroup }
634
672
  };
635
673
  const messagesPayload = await this.http.request({
636
674
  method: "GET",
637
675
  path: ["v2", "dlq"],
638
676
  query: {
639
- cursor: options?.cursor,
640
- count: options?.count,
677
+ cursor: options.cursor,
678
+ count: options.count,
679
+ order: options.order,
680
+ trimBody: options.trimBody,
641
681
  ...filterPayload
642
682
  }
643
683
  });
@@ -653,26 +693,70 @@ var DLQ = class {
653
693
  };
654
694
  }
655
695
  /**
656
- * Remove a message from the dlq using it's `dlqId`
696
+ * Remove messages from the dlq.
697
+ *
698
+ * Can be called with:
699
+ * - A single dlqId: `delete("id")`
700
+ * - An array of dlqIds: `delete(["id1", "id2"])`
701
+ * - An object with dlqIds: `delete({ dlqIds: ["id1", "id2"] })`
702
+ * - A filter object: `delete({ url: "https://example.com", label: "label" })`
703
+ * - All messages: `delete({ all: true })`
704
+ *
705
+ * Note: passing an empty array returns `{ deleted: 0 }` without making a request.
657
706
  */
658
- async delete(dlqMessageId) {
659
- return await this.http.request({
660
- method: "DELETE",
661
- path: ["v2", "dlq", dlqMessageId],
662
- parseResponseAsJson: false
663
- // there is no response
664
- });
707
+ async delete(request) {
708
+ if (typeof request === "string") {
709
+ await this.http.request({
710
+ method: "DELETE",
711
+ path: ["v2", "dlq", request],
712
+ parseResponseAsJson: false
713
+ });
714
+ return { deleted: 1 };
715
+ }
716
+ if (Array.isArray(request) && request.length === 0)
717
+ return { deleted: 0 };
718
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
719
+ return normalizeCursor(
720
+ await this.http.request({
721
+ method: "DELETE",
722
+ path: ["v2", "dlq"],
723
+ query: buildBulkActionFilterPayload(filters)
724
+ })
725
+ );
665
726
  }
666
727
  /**
667
728
  * Remove multiple messages from the dlq using their `dlqId`s
729
+ *
730
+ * @deprecated Use `delete` instead
668
731
  */
669
732
  async deleteMany(request) {
670
- return await this.http.request({
671
- method: "DELETE",
672
- path: ["v2", "dlq"],
673
- headers: { "Content-Type": "application/json" },
674
- body: JSON.stringify({ dlqIds: request.dlqIds })
675
- });
733
+ return await this.delete(request);
734
+ }
735
+ /**
736
+ * Retry messages from the dlq.
737
+ *
738
+ * Can be called with:
739
+ * - A single dlqId: `retry("id")`
740
+ * - An array of dlqIds: `retry(["id1", "id2"])`
741
+ * - An object with dlqIds: `retry({ dlqIds: ["id1", "id2"] })`
742
+ * - A filter object: `retry({ url: "https://example.com", label: "label" })`
743
+ * - All messages: `retry({ all: true })`
744
+ *
745
+ * Note: passing an empty array returns `{ responses: [] }` without making a request.
746
+ */
747
+ async retry(request) {
748
+ if (typeof request === "string")
749
+ request = [request];
750
+ if (Array.isArray(request) && request.length === 0)
751
+ return { responses: [] };
752
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
753
+ return normalizeCursor(
754
+ await this.http.request({
755
+ method: "POST",
756
+ path: ["v2", "dlq", "retry"],
757
+ query: buildBulkActionFilterPayload(filters)
758
+ })
759
+ );
676
760
  }
677
761
  };
678
762
 
@@ -773,7 +857,15 @@ var HttpClient = class {
773
857
  const url = new URL([request.baseUrl ?? this.baseUrl, ...request.path].join("/"));
774
858
  if (request.query) {
775
859
  for (const [key, value] of Object.entries(request.query)) {
776
- if (value !== void 0) {
860
+ if (value === void 0)
861
+ continue;
862
+ if (Array.isArray(value)) {
863
+ for (const item of value) {
864
+ url.searchParams.append(key, item);
865
+ }
866
+ } else if (value instanceof Date) {
867
+ url.searchParams.set(key, value.getTime().toString());
868
+ } else {
777
869
  url.searchParams.set(key, value.toString());
778
870
  }
779
871
  }
@@ -1004,29 +1096,57 @@ var Messages = class {
1004
1096
  return message;
1005
1097
  }
1006
1098
  /**
1007
- * Cancel a message
1099
+ * Cancel messages.
1100
+ *
1101
+ * Can be called with:
1102
+ * - A single messageId: `cancel("id")`
1103
+ * - An array of messageIds: `cancel(["id1", "id2"])`
1104
+ * - A filter object: `cancel({ flowControlKey: "key", label: "label" })`
1105
+ * - All messages: `cancel({ all: true })`
1008
1106
  */
1009
- async delete(messageId) {
1107
+ async cancel(request) {
1108
+ if (typeof request === "string") {
1109
+ return await this.http.request({
1110
+ method: "DELETE",
1111
+ path: ["v2", "messages", request]
1112
+ });
1113
+ }
1114
+ if (Array.isArray(request) && request.length === 0)
1115
+ return { cancelled: 0 };
1116
+ const filters = Array.isArray(request) ? { messageIds: request } : request;
1010
1117
  return await this.http.request({
1118
+ method: "DELETE",
1119
+ path: ["v2", "messages"],
1120
+ query: buildBulkActionFilterPayload(filters, { callerIpCasing: true })
1121
+ });
1122
+ }
1123
+ /**
1124
+ * Delete a message.
1125
+ *
1126
+ * @deprecated Use `cancel(messageId: string)` instead
1127
+ */
1128
+ async delete(messageId) {
1129
+ await this.http.request({
1011
1130
  method: "DELETE",
1012
1131
  path: ["v2", "messages", messageId],
1013
1132
  parseResponseAsJson: false
1014
1133
  });
1015
1134
  }
1135
+ /**
1136
+ * Cancel multiple messages by their messageIds.
1137
+ *
1138
+ * @deprecated Use `cancel(messageIds: string[])` instead
1139
+ */
1016
1140
  async deleteMany(messageIds) {
1017
- const result = await this.http.request({
1018
- method: "DELETE",
1019
- path: ["v2", "messages"],
1020
- headers: { "Content-Type": "application/json" },
1021
- body: JSON.stringify({ messageIds })
1022
- });
1141
+ const result = await this.cancel(messageIds);
1023
1142
  return result.cancelled;
1024
1143
  }
1144
+ /**
1145
+ * Cancel all messages
1146
+ * @deprecated Use `cancel({all: true})` to cancel all
1147
+ */
1025
1148
  async deleteAll() {
1026
- const result = await this.http.request({
1027
- method: "DELETE",
1028
- path: ["v2", "messages"]
1029
- });
1149
+ const result = await this.cancel({ all: true });
1030
1150
  return result.cancelled;
1031
1151
  }
1032
1152
  };
@@ -1360,7 +1480,7 @@ var UrlGroups = class {
1360
1480
  };
1361
1481
 
1362
1482
  // version.ts
1363
- var VERSION = "v2.9.0";
1483
+ var VERSION = "v2.9.1-rc.1";
1364
1484
 
1365
1485
  // src/client/client.ts
1366
1486
  var Client = class {
@@ -1555,39 +1675,47 @@ var Client = class {
1555
1675
  * }
1556
1676
  * ```
1557
1677
  */
1558
- async logs(request) {
1559
- const query = {};
1560
- if (typeof request?.cursor === "number" && request.cursor > 0) {
1561
- query.cursor = request.cursor.toString();
1562
- } else if (typeof request?.cursor === "string" && request.cursor !== "") {
1563
- query.cursor = request.cursor;
1564
- }
1565
- for (const [key, value] of Object.entries(request?.filter ?? {})) {
1566
- if (typeof value === "number" && value < 0) {
1567
- continue;
1568
- }
1569
- if (key === "urlGroup") {
1570
- query.topicName = value.toString();
1571
- } else if (typeof value !== "undefined") {
1572
- query[key] = value.toString();
1573
- }
1574
- }
1678
+ async logs(request = {}) {
1679
+ const {
1680
+ urlGroup,
1681
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
1682
+ topicName,
1683
+ fromDate,
1684
+ toDate,
1685
+ callerIp,
1686
+ messageIds,
1687
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
1688
+ count: filterCount,
1689
+ ...restFilter
1690
+ } = request.filter ?? {};
1691
+ const filterPayload = {
1692
+ ...restFilter,
1693
+ topicName: urlGroup ?? topicName,
1694
+ fromDate,
1695
+ toDate,
1696
+ callerIp
1697
+ };
1698
+ let cursorString;
1699
+ if (typeof request.cursor === "number" && request.cursor > 0) {
1700
+ cursorString = request.cursor.toString();
1701
+ } else if (typeof request.cursor === "string" && request.cursor !== "") {
1702
+ cursorString = request.cursor;
1703
+ }
1704
+ const query = {
1705
+ cursor: cursorString,
1706
+ count: request.count ?? filterCount,
1707
+ order: request.order,
1708
+ trimBody: request.trimBody,
1709
+ messageIds,
1710
+ ...filterPayload
1711
+ };
1575
1712
  const responsePayload = await this.http.request({
1576
1713
  path: ["v2", "events"],
1577
1714
  method: "GET",
1578
1715
  query
1579
1716
  });
1580
- const logs = responsePayload.events.map((event) => {
1581
- return {
1582
- ...event,
1583
- urlGroup: event.topicName
1584
- };
1585
- });
1586
- return {
1587
- cursor: responsePayload.cursor,
1588
- logs,
1589
- events: logs
1590
- };
1717
+ const logs = responsePayload.events.map((event) => ({ ...event, urlGroup: event.topicName }));
1718
+ return { cursor: responsePayload.cursor, logs, events: logs };
1591
1719
  }
1592
1720
  /**
1593
1721
  * @deprecated Will be removed in the next major release. Use the `logs` method instead.
package/workflow.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  WorkflowLogger,
7
7
  processOptions,
8
8
  serve
9
- } from "./chunk-QYBCXZKB.mjs";
9
+ } from "./chunk-RUCOF5QZ.mjs";
10
10
  export {
11
11
  DisabledWorkflowContext,
12
12
  StepTypes,