@upstash/qstash 2.9.1-rc.1 → 2.9.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.
@@ -372,43 +372,6 @@ function decodeBase64(base64) {
372
372
  }
373
373
  }
374
374
  }
375
- function buildBulkActionFilterPayload(request, options) {
376
- const hasDlqIds = "dlqIds" in request && request.dlqIds !== void 0;
377
- const hasAll = "all" in request && Boolean(request.all);
378
- const filterKeys = Object.keys(request).filter((k) => k !== "dlqIds" && k !== "all");
379
- const hasFilters = filterKeys.length > 0;
380
- if (hasDlqIds && hasAll) {
381
- throw new QstashError("dlqIds and all: true are mutually exclusive.");
382
- }
383
- if (hasDlqIds && hasFilters) {
384
- throw new QstashError(
385
- `dlqIds cannot be combined with filter fields: ${filterKeys.join(", ")}.`
386
- );
387
- }
388
- if (hasAll && hasFilters) {
389
- throw new QstashError(
390
- `all: true cannot be combined with filter fields: ${filterKeys.join(", ")}.`
391
- );
392
- }
393
- if (hasAll)
394
- return {};
395
- const { urlGroup, callerIp, ...rest } = request;
396
- const payload = {
397
- ...rest,
398
- ...urlGroup === void 0 || typeof urlGroup !== "string" ? {} : { topicName: urlGroup },
399
- ...callerIp === void 0 || typeof callerIp !== "string" ? {} : options?.callerIpCasing ? { callerIP: callerIp } : { callerIp }
400
- };
401
- if (Object.keys(payload).length === 0) {
402
- throw new QstashError(
403
- "No filters provided. Pass { all: true } to explicitly target all messages."
404
- );
405
- }
406
- return payload;
407
- }
408
- function normalizeCursor(response) {
409
- const cursor = response.cursor;
410
- return { ...response, cursor: cursor || void 0 };
411
- }
412
375
  function getRuntime() {
413
376
  if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
414
377
  return `bun@${process.versions.bun}`;
@@ -638,20 +601,17 @@ var DLQ = class {
638
601
  /**
639
602
  * List messages in the dlq
640
603
  */
641
- async listMessages(options = {}) {
642
- const { urlGroup, ...restFilter } = options.filter ?? {};
604
+ async listMessages(options) {
643
605
  const filterPayload = {
644
- ...restFilter,
645
- ...urlGroup === void 0 ? {} : { topicName: urlGroup }
606
+ ...options?.filter,
607
+ topicName: options?.filter?.urlGroup
646
608
  };
647
609
  const messagesPayload = await this.http.request({
648
610
  method: "GET",
649
611
  path: ["v2", "dlq"],
650
612
  query: {
651
- cursor: options.cursor,
652
- count: options.count,
653
- order: options.order,
654
- trimBody: options.trimBody,
613
+ cursor: options?.cursor,
614
+ count: options?.count,
655
615
  ...filterPayload
656
616
  }
657
617
  });
@@ -667,70 +627,127 @@ var DLQ = class {
667
627
  };
668
628
  }
669
629
  /**
670
- * Remove messages from the dlq.
671
- *
672
- * Can be called with:
673
- * - A single dlqId: `delete("id")`
674
- * - An array of dlqIds: `delete(["id1", "id2"])`
675
- * - An object with dlqIds: `delete({ dlqIds: ["id1", "id2"] })`
676
- * - A filter object: `delete({ url: "https://example.com", label: "label" })`
677
- * - All messages: `delete({ all: true })`
678
- *
679
- * Note: passing an empty array returns `{ deleted: 0 }` without making a request.
630
+ * Remove a message from the dlq using it's `dlqId`
680
631
  */
681
- async delete(request) {
682
- if (typeof request === "string") {
683
- await this.http.request({
684
- method: "DELETE",
685
- path: ["v2", "dlq", request],
686
- parseResponseAsJson: false
687
- });
688
- return { deleted: 1 };
689
- }
690
- if (Array.isArray(request) && request.length === 0)
691
- return { deleted: 0 };
692
- const filters = Array.isArray(request) ? { dlqIds: request } : request;
693
- return normalizeCursor(
694
- await this.http.request({
695
- method: "DELETE",
696
- path: ["v2", "dlq"],
697
- query: buildBulkActionFilterPayload(filters)
698
- })
699
- );
632
+ async delete(dlqMessageId) {
633
+ return await this.http.request({
634
+ method: "DELETE",
635
+ path: ["v2", "dlq", dlqMessageId],
636
+ parseResponseAsJson: false
637
+ // there is no response
638
+ });
700
639
  }
701
640
  /**
702
641
  * Remove multiple messages from the dlq using their `dlqId`s
703
- *
704
- * @deprecated Use `delete` instead
705
642
  */
706
643
  async deleteMany(request) {
707
- return await this.delete(request);
644
+ return await this.http.request({
645
+ method: "DELETE",
646
+ path: ["v2", "dlq"],
647
+ headers: { "Content-Type": "application/json" },
648
+ body: JSON.stringify({ dlqIds: request.dlqIds })
649
+ });
650
+ }
651
+ };
652
+
653
+ // src/client/flow-control.ts
654
+ var FlowControlApi = class {
655
+ http;
656
+ constructor(http) {
657
+ this.http = http;
708
658
  }
709
659
  /**
710
- * Retry messages from the dlq.
660
+ * Get a single flow control by key.
661
+ */
662
+ async get(flowControlKey) {
663
+ return await this.http.request({
664
+ method: "GET",
665
+ path: ["v2", "flowControl", flowControlKey]
666
+ });
667
+ }
668
+ /**
669
+ * Get the global parallelism info.
670
+ */
671
+ async getGlobalParallelism() {
672
+ const response = await this.http.request({
673
+ method: "GET",
674
+ path: ["v2", "globalParallelism"]
675
+ });
676
+ return {
677
+ parallelismMax: response.parallelismMax ?? 0,
678
+ parallelismCount: response.parallelismCount ?? 0
679
+ };
680
+ }
681
+ /**
682
+ * Pause message delivery for a flow-control key.
711
683
  *
712
- * Can be called with:
713
- * - A single dlqId: `retry("id")`
714
- * - An array of dlqIds: `retry(["id1", "id2"])`
715
- * - An object with dlqIds: `retry({ dlqIds: ["id1", "id2"] })`
716
- * - A filter object: `retry({ url: "https://example.com", label: "label" })`
717
- * - All messages: `retry({ all: true })`
684
+ * Messages already in the waitlist will remain there.
685
+ * New incoming messages will be added directly to the waitlist.
686
+ */
687
+ async pause(flowControlKey) {
688
+ await this.http.request({
689
+ method: "POST",
690
+ path: ["v2", "flowControl", flowControlKey, "pause"],
691
+ parseResponseAsJson: false
692
+ });
693
+ }
694
+ /**
695
+ * Resume message delivery for a flow-control key.
696
+ */
697
+ async resume(flowControlKey) {
698
+ await this.http.request({
699
+ method: "POST",
700
+ path: ["v2", "flowControl", flowControlKey, "resume"],
701
+ parseResponseAsJson: false
702
+ });
703
+ }
704
+ /**
705
+ * Pin a processing configuration for a flow-control key.
718
706
  *
719
- * Note: passing an empty array returns `{ responses: [] }` without making a request.
707
+ * While pinned, the system ignores configurations provided by incoming
708
+ * messages and uses the pinned configuration instead.
720
709
  */
721
- async retry(request) {
722
- if (typeof request === "string")
723
- request = [request];
724
- if (Array.isArray(request) && request.length === 0)
725
- return { responses: [] };
726
- const filters = Array.isArray(request) ? { dlqIds: request } : request;
727
- return normalizeCursor(
728
- await this.http.request({
729
- method: "POST",
730
- path: ["v2", "dlq", "retry"],
731
- query: buildBulkActionFilterPayload(filters)
732
- })
733
- );
710
+ async pin(flowControlKey, options) {
711
+ await this.http.request({
712
+ method: "POST",
713
+ path: ["v2", "flowControl", flowControlKey, "pin"],
714
+ query: {
715
+ parallelism: options.parallelism,
716
+ rate: options.rate,
717
+ period: options.period
718
+ },
719
+ parseResponseAsJson: false
720
+ });
721
+ }
722
+ /**
723
+ * Remove the pinned configuration for a flow-control key.
724
+ *
725
+ * After unpinning, the system resumes updating the configuration
726
+ * based on incoming messages.
727
+ */
728
+ async unpin(flowControlKey, options) {
729
+ await this.http.request({
730
+ method: "POST",
731
+ path: ["v2", "flowControl", flowControlKey, "unpin"],
732
+ query: {
733
+ parallelism: options.parallelism,
734
+ rate: options.rate
735
+ },
736
+ parseResponseAsJson: false
737
+ });
738
+ }
739
+ /**
740
+ * Reset the rate configuration state for a flow-control key.
741
+ *
742
+ * Clears the current rate count and immediately ends the current period.
743
+ * The current timestamp becomes the start of the new rate period.
744
+ */
745
+ async resetRate(flowControlKey) {
746
+ await this.http.request({
747
+ method: "POST",
748
+ path: ["v2", "flowControl", flowControlKey, "resetRate"],
749
+ parseResponseAsJson: false
750
+ });
734
751
  }
735
752
  };
736
753
 
@@ -831,15 +848,7 @@ var HttpClient = class {
831
848
  const url = new URL([request.baseUrl ?? this.baseUrl, ...request.path].join("/"));
832
849
  if (request.query) {
833
850
  for (const [key, value] of Object.entries(request.query)) {
834
- if (value === void 0)
835
- continue;
836
- if (Array.isArray(value)) {
837
- for (const item of value) {
838
- url.searchParams.append(key, item);
839
- }
840
- } else if (value instanceof Date) {
841
- url.searchParams.set(key, value.getTime().toString());
842
- } else {
851
+ if (value !== void 0) {
843
852
  url.searchParams.set(key, value.toString());
844
853
  }
845
854
  }
@@ -1070,57 +1079,29 @@ var Messages = class {
1070
1079
  return message;
1071
1080
  }
1072
1081
  /**
1073
- * Cancel messages.
1074
- *
1075
- * Can be called with:
1076
- * - A single messageId: `cancel("id")`
1077
- * - An array of messageIds: `cancel(["id1", "id2"])`
1078
- * - A filter object: `cancel({ flowControlKey: "key", label: "label" })`
1079
- * - All messages: `cancel({ all: true })`
1080
- */
1081
- async cancel(request) {
1082
- if (typeof request === "string") {
1083
- return await this.http.request({
1084
- method: "DELETE",
1085
- path: ["v2", "messages", request]
1086
- });
1087
- }
1088
- if (Array.isArray(request) && request.length === 0)
1089
- return { cancelled: 0 };
1090
- const filters = Array.isArray(request) ? { messageIds: request } : request;
1091
- return await this.http.request({
1092
- method: "DELETE",
1093
- path: ["v2", "messages"],
1094
- query: buildBulkActionFilterPayload(filters, { callerIpCasing: true })
1095
- });
1096
- }
1097
- /**
1098
- * Delete a message.
1099
- *
1100
- * @deprecated Use `cancel(messageId: string)` instead
1082
+ * Cancel a message
1101
1083
  */
1102
1084
  async delete(messageId) {
1103
- await this.http.request({
1085
+ return await this.http.request({
1104
1086
  method: "DELETE",
1105
1087
  path: ["v2", "messages", messageId],
1106
1088
  parseResponseAsJson: false
1107
1089
  });
1108
1090
  }
1109
- /**
1110
- * Cancel multiple messages by their messageIds.
1111
- *
1112
- * @deprecated Use `cancel(messageIds: string[])` instead
1113
- */
1114
1091
  async deleteMany(messageIds) {
1115
- const result = await this.cancel(messageIds);
1092
+ const result = await this.http.request({
1093
+ method: "DELETE",
1094
+ path: ["v2", "messages"],
1095
+ headers: { "Content-Type": "application/json" },
1096
+ body: JSON.stringify({ messageIds })
1097
+ });
1116
1098
  return result.cancelled;
1117
1099
  }
1118
- /**
1119
- * Cancel all messages
1120
- * @deprecated Use `cancel({all: true})` to cancel all
1121
- */
1122
1100
  async deleteAll() {
1123
- const result = await this.cancel({ all: true });
1101
+ const result = await this.http.request({
1102
+ method: "DELETE",
1103
+ path: ["v2", "messages"]
1104
+ });
1124
1105
  return result.cancelled;
1125
1106
  }
1126
1107
  };
@@ -1454,7 +1435,7 @@ var UrlGroups = class {
1454
1435
  };
1455
1436
 
1456
1437
  // version.ts
1457
- var VERSION = "v2.9.1-rc.1";
1438
+ var VERSION = "v2.9.1";
1458
1439
 
1459
1440
  // src/client/client.ts
1460
1441
  var Client = class {
@@ -1525,6 +1506,14 @@ var Client = class {
1525
1506
  get schedules() {
1526
1507
  return new Schedules(this.http);
1527
1508
  }
1509
+ /**
1510
+ * Access the flow control API.
1511
+ *
1512
+ * List, get, or reset flow controls.
1513
+ */
1514
+ get flowControl() {
1515
+ return new FlowControlApi(this.http);
1516
+ }
1528
1517
  /**
1529
1518
  * Access the workflow API.
1530
1519
  *
@@ -1649,47 +1638,39 @@ var Client = class {
1649
1638
  * }
1650
1639
  * ```
1651
1640
  */
1652
- async logs(request = {}) {
1653
- const {
1654
- urlGroup,
1655
- // eslint-disable-next-line @typescript-eslint/no-deprecated
1656
- topicName,
1657
- fromDate,
1658
- toDate,
1659
- callerIp,
1660
- messageIds,
1661
- // eslint-disable-next-line @typescript-eslint/no-deprecated
1662
- count: filterCount,
1663
- ...restFilter
1664
- } = request.filter ?? {};
1665
- const filterPayload = {
1666
- ...restFilter,
1667
- topicName: urlGroup ?? topicName,
1668
- fromDate,
1669
- toDate,
1670
- callerIp
1671
- };
1672
- let cursorString;
1673
- if (typeof request.cursor === "number" && request.cursor > 0) {
1674
- cursorString = request.cursor.toString();
1675
- } else if (typeof request.cursor === "string" && request.cursor !== "") {
1676
- cursorString = request.cursor;
1677
- }
1678
- const query = {
1679
- cursor: cursorString,
1680
- count: request.count ?? filterCount,
1681
- order: request.order,
1682
- trimBody: request.trimBody,
1683
- messageIds,
1684
- ...filterPayload
1685
- };
1641
+ async logs(request) {
1642
+ const query = {};
1643
+ if (typeof request?.cursor === "number" && request.cursor > 0) {
1644
+ query.cursor = request.cursor.toString();
1645
+ } else if (typeof request?.cursor === "string" && request.cursor !== "") {
1646
+ query.cursor = request.cursor;
1647
+ }
1648
+ for (const [key, value] of Object.entries(request?.filter ?? {})) {
1649
+ if (typeof value === "number" && value < 0) {
1650
+ continue;
1651
+ }
1652
+ if (key === "urlGroup") {
1653
+ query.topicName = value.toString();
1654
+ } else if (typeof value !== "undefined") {
1655
+ query[key] = value.toString();
1656
+ }
1657
+ }
1686
1658
  const responsePayload = await this.http.request({
1687
1659
  path: ["v2", "events"],
1688
1660
  method: "GET",
1689
1661
  query
1690
1662
  });
1691
- const logs = responsePayload.events.map((event) => ({ ...event, urlGroup: event.topicName }));
1692
- return { cursor: responsePayload.cursor, logs, events: logs };
1663
+ const logs = responsePayload.events.map((event) => {
1664
+ return {
1665
+ ...event,
1666
+ urlGroup: event.topicName
1667
+ };
1668
+ });
1669
+ return {
1670
+ cursor: responsePayload.cursor,
1671
+ logs,
1672
+ events: logs
1673
+ };
1693
1674
  }
1694
1675
  /**
1695
1676
  * @deprecated Will be removed in the next major release. Use the `logs` method instead.
@@ -3119,6 +3100,7 @@ export {
3119
3100
  decodeBase64,
3120
3101
  SignatureError,
3121
3102
  Receiver,
3103
+ FlowControlApi,
3122
3104
  setupAnalytics,
3123
3105
  Chat,
3124
3106
  Messages,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Receiver,
3
3
  serve
4
- } from "./chunk-RUCOF5QZ.mjs";
4
+ } from "./chunk-DT2X63FB.mjs";
5
5
 
6
6
  // node_modules/defu/dist/defu.mjs
7
7
  function isPlainObject(value) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BaseProvider
3
- } from "./chunk-RUCOF5QZ.mjs";
3
+ } from "./chunk-DT2X63FB.mjs";
4
4
 
5
5
  // src/client/api/email.ts
6
6
  var EmailProvider = class extends BaseProvider {