@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.
package/nextjs.js CHANGED
@@ -396,43 +396,6 @@ function decodeBase64(base64) {
396
396
  }
397
397
  }
398
398
  }
399
- function buildBulkActionFilterPayload(request, options) {
400
- const hasDlqIds = "dlqIds" in request && request.dlqIds !== void 0;
401
- const hasAll = "all" in request && Boolean(request.all);
402
- const filterKeys = Object.keys(request).filter((k) => k !== "dlqIds" && k !== "all");
403
- const hasFilters = filterKeys.length > 0;
404
- if (hasDlqIds && hasAll) {
405
- throw new QstashError("dlqIds and all: true are mutually exclusive.");
406
- }
407
- if (hasDlqIds && hasFilters) {
408
- throw new QstashError(
409
- `dlqIds cannot be combined with filter fields: ${filterKeys.join(", ")}.`
410
- );
411
- }
412
- if (hasAll && hasFilters) {
413
- throw new QstashError(
414
- `all: true cannot be combined with filter fields: ${filterKeys.join(", ")}.`
415
- );
416
- }
417
- if (hasAll)
418
- return {};
419
- const { urlGroup, callerIp, ...rest } = request;
420
- const payload = {
421
- ...rest,
422
- ...urlGroup === void 0 || typeof urlGroup !== "string" ? {} : { topicName: urlGroup },
423
- ...callerIp === void 0 || typeof callerIp !== "string" ? {} : options?.callerIpCasing ? { callerIP: callerIp } : { callerIp }
424
- };
425
- if (Object.keys(payload).length === 0) {
426
- throw new QstashError(
427
- "No filters provided. Pass { all: true } to explicitly target all messages."
428
- );
429
- }
430
- return payload;
431
- }
432
- function normalizeCursor(response) {
433
- const cursor = response.cursor;
434
- return { ...response, cursor: cursor || void 0 };
435
- }
436
399
  function getRuntime() {
437
400
  if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
438
401
  return `bun@${process.versions.bun}`;
@@ -662,20 +625,17 @@ var DLQ = class {
662
625
  /**
663
626
  * List messages in the dlq
664
627
  */
665
- async listMessages(options = {}) {
666
- const { urlGroup, ...restFilter } = options.filter ?? {};
628
+ async listMessages(options) {
667
629
  const filterPayload = {
668
- ...restFilter,
669
- ...urlGroup === void 0 ? {} : { topicName: urlGroup }
630
+ ...options?.filter,
631
+ topicName: options?.filter?.urlGroup
670
632
  };
671
633
  const messagesPayload = await this.http.request({
672
634
  method: "GET",
673
635
  path: ["v2", "dlq"],
674
636
  query: {
675
- cursor: options.cursor,
676
- count: options.count,
677
- order: options.order,
678
- trimBody: options.trimBody,
637
+ cursor: options?.cursor,
638
+ count: options?.count,
679
639
  ...filterPayload
680
640
  }
681
641
  });
@@ -691,70 +651,127 @@ var DLQ = class {
691
651
  };
692
652
  }
693
653
  /**
694
- * Remove messages from the dlq.
695
- *
696
- * Can be called with:
697
- * - A single dlqId: `delete("id")`
698
- * - An array of dlqIds: `delete(["id1", "id2"])`
699
- * - An object with dlqIds: `delete({ dlqIds: ["id1", "id2"] })`
700
- * - A filter object: `delete({ url: "https://example.com", label: "label" })`
701
- * - All messages: `delete({ all: true })`
702
- *
703
- * Note: passing an empty array returns `{ deleted: 0 }` without making a request.
654
+ * Remove a message from the dlq using it's `dlqId`
704
655
  */
705
- async delete(request) {
706
- if (typeof request === "string") {
707
- await this.http.request({
708
- method: "DELETE",
709
- path: ["v2", "dlq", request],
710
- parseResponseAsJson: false
711
- });
712
- return { deleted: 1 };
713
- }
714
- if (Array.isArray(request) && request.length === 0)
715
- return { deleted: 0 };
716
- const filters = Array.isArray(request) ? { dlqIds: request } : request;
717
- return normalizeCursor(
718
- await this.http.request({
719
- method: "DELETE",
720
- path: ["v2", "dlq"],
721
- query: buildBulkActionFilterPayload(filters)
722
- })
723
- );
656
+ async delete(dlqMessageId) {
657
+ return await this.http.request({
658
+ method: "DELETE",
659
+ path: ["v2", "dlq", dlqMessageId],
660
+ parseResponseAsJson: false
661
+ // there is no response
662
+ });
724
663
  }
725
664
  /**
726
665
  * Remove multiple messages from the dlq using their `dlqId`s
727
- *
728
- * @deprecated Use `delete` instead
729
666
  */
730
667
  async deleteMany(request) {
731
- return await this.delete(request);
668
+ return await this.http.request({
669
+ method: "DELETE",
670
+ path: ["v2", "dlq"],
671
+ headers: { "Content-Type": "application/json" },
672
+ body: JSON.stringify({ dlqIds: request.dlqIds })
673
+ });
674
+ }
675
+ };
676
+
677
+ // src/client/flow-control.ts
678
+ var FlowControlApi = class {
679
+ http;
680
+ constructor(http) {
681
+ this.http = http;
732
682
  }
733
683
  /**
734
- * Retry messages from the dlq.
684
+ * Get a single flow control by key.
685
+ */
686
+ async get(flowControlKey) {
687
+ return await this.http.request({
688
+ method: "GET",
689
+ path: ["v2", "flowControl", flowControlKey]
690
+ });
691
+ }
692
+ /**
693
+ * Get the global parallelism info.
694
+ */
695
+ async getGlobalParallelism() {
696
+ const response = await this.http.request({
697
+ method: "GET",
698
+ path: ["v2", "globalParallelism"]
699
+ });
700
+ return {
701
+ parallelismMax: response.parallelismMax ?? 0,
702
+ parallelismCount: response.parallelismCount ?? 0
703
+ };
704
+ }
705
+ /**
706
+ * Pause message delivery for a flow-control key.
735
707
  *
736
- * Can be called with:
737
- * - A single dlqId: `retry("id")`
738
- * - An array of dlqIds: `retry(["id1", "id2"])`
739
- * - An object with dlqIds: `retry({ dlqIds: ["id1", "id2"] })`
740
- * - A filter object: `retry({ url: "https://example.com", label: "label" })`
741
- * - All messages: `retry({ all: true })`
708
+ * Messages already in the waitlist will remain there.
709
+ * New incoming messages will be added directly to the waitlist.
710
+ */
711
+ async pause(flowControlKey) {
712
+ await this.http.request({
713
+ method: "POST",
714
+ path: ["v2", "flowControl", flowControlKey, "pause"],
715
+ parseResponseAsJson: false
716
+ });
717
+ }
718
+ /**
719
+ * Resume message delivery for a flow-control key.
720
+ */
721
+ async resume(flowControlKey) {
722
+ await this.http.request({
723
+ method: "POST",
724
+ path: ["v2", "flowControl", flowControlKey, "resume"],
725
+ parseResponseAsJson: false
726
+ });
727
+ }
728
+ /**
729
+ * Pin a processing configuration for a flow-control key.
742
730
  *
743
- * Note: passing an empty array returns `{ responses: [] }` without making a request.
731
+ * While pinned, the system ignores configurations provided by incoming
732
+ * messages and uses the pinned configuration instead.
744
733
  */
745
- async retry(request) {
746
- if (typeof request === "string")
747
- request = [request];
748
- if (Array.isArray(request) && request.length === 0)
749
- return { responses: [] };
750
- const filters = Array.isArray(request) ? { dlqIds: request } : request;
751
- return normalizeCursor(
752
- await this.http.request({
753
- method: "POST",
754
- path: ["v2", "dlq", "retry"],
755
- query: buildBulkActionFilterPayload(filters)
756
- })
757
- );
734
+ async pin(flowControlKey, options) {
735
+ await this.http.request({
736
+ method: "POST",
737
+ path: ["v2", "flowControl", flowControlKey, "pin"],
738
+ query: {
739
+ parallelism: options.parallelism,
740
+ rate: options.rate,
741
+ period: options.period
742
+ },
743
+ parseResponseAsJson: false
744
+ });
745
+ }
746
+ /**
747
+ * Remove the pinned configuration for a flow-control key.
748
+ *
749
+ * After unpinning, the system resumes updating the configuration
750
+ * based on incoming messages.
751
+ */
752
+ async unpin(flowControlKey, options) {
753
+ await this.http.request({
754
+ method: "POST",
755
+ path: ["v2", "flowControl", flowControlKey, "unpin"],
756
+ query: {
757
+ parallelism: options.parallelism,
758
+ rate: options.rate
759
+ },
760
+ parseResponseAsJson: false
761
+ });
762
+ }
763
+ /**
764
+ * Reset the rate configuration state for a flow-control key.
765
+ *
766
+ * Clears the current rate count and immediately ends the current period.
767
+ * The current timestamp becomes the start of the new rate period.
768
+ */
769
+ async resetRate(flowControlKey) {
770
+ await this.http.request({
771
+ method: "POST",
772
+ path: ["v2", "flowControl", flowControlKey, "resetRate"],
773
+ parseResponseAsJson: false
774
+ });
758
775
  }
759
776
  };
760
777
 
@@ -855,15 +872,7 @@ var HttpClient = class {
855
872
  const url = new URL([request.baseUrl ?? this.baseUrl, ...request.path].join("/"));
856
873
  if (request.query) {
857
874
  for (const [key, value] of Object.entries(request.query)) {
858
- if (value === void 0)
859
- continue;
860
- if (Array.isArray(value)) {
861
- for (const item of value) {
862
- url.searchParams.append(key, item);
863
- }
864
- } else if (value instanceof Date) {
865
- url.searchParams.set(key, value.getTime().toString());
866
- } else {
875
+ if (value !== void 0) {
867
876
  url.searchParams.set(key, value.toString());
868
877
  }
869
878
  }
@@ -1094,57 +1103,29 @@ var Messages = class {
1094
1103
  return message;
1095
1104
  }
1096
1105
  /**
1097
- * Cancel messages.
1098
- *
1099
- * Can be called with:
1100
- * - A single messageId: `cancel("id")`
1101
- * - An array of messageIds: `cancel(["id1", "id2"])`
1102
- * - A filter object: `cancel({ flowControlKey: "key", label: "label" })`
1103
- * - All messages: `cancel({ all: true })`
1104
- */
1105
- async cancel(request) {
1106
- if (typeof request === "string") {
1107
- return await this.http.request({
1108
- method: "DELETE",
1109
- path: ["v2", "messages", request]
1110
- });
1111
- }
1112
- if (Array.isArray(request) && request.length === 0)
1113
- return { cancelled: 0 };
1114
- const filters = Array.isArray(request) ? { messageIds: request } : request;
1115
- return await this.http.request({
1116
- method: "DELETE",
1117
- path: ["v2", "messages"],
1118
- query: buildBulkActionFilterPayload(filters, { callerIpCasing: true })
1119
- });
1120
- }
1121
- /**
1122
- * Delete a message.
1123
- *
1124
- * @deprecated Use `cancel(messageId: string)` instead
1106
+ * Cancel a message
1125
1107
  */
1126
1108
  async delete(messageId) {
1127
- await this.http.request({
1109
+ return await this.http.request({
1128
1110
  method: "DELETE",
1129
1111
  path: ["v2", "messages", messageId],
1130
1112
  parseResponseAsJson: false
1131
1113
  });
1132
1114
  }
1133
- /**
1134
- * Cancel multiple messages by their messageIds.
1135
- *
1136
- * @deprecated Use `cancel(messageIds: string[])` instead
1137
- */
1138
1115
  async deleteMany(messageIds) {
1139
- const result = await this.cancel(messageIds);
1116
+ const result = await this.http.request({
1117
+ method: "DELETE",
1118
+ path: ["v2", "messages"],
1119
+ headers: { "Content-Type": "application/json" },
1120
+ body: JSON.stringify({ messageIds })
1121
+ });
1140
1122
  return result.cancelled;
1141
1123
  }
1142
- /**
1143
- * Cancel all messages
1144
- * @deprecated Use `cancel({all: true})` to cancel all
1145
- */
1146
1124
  async deleteAll() {
1147
- const result = await this.cancel({ all: true });
1125
+ const result = await this.http.request({
1126
+ method: "DELETE",
1127
+ path: ["v2", "messages"]
1128
+ });
1148
1129
  return result.cancelled;
1149
1130
  }
1150
1131
  };
@@ -1478,7 +1459,7 @@ var UrlGroups = class {
1478
1459
  };
1479
1460
 
1480
1461
  // version.ts
1481
- var VERSION = "v2.9.1-rc.1";
1462
+ var VERSION = "v2.9.1";
1482
1463
 
1483
1464
  // src/client/client.ts
1484
1465
  var Client = class {
@@ -1549,6 +1530,14 @@ var Client = class {
1549
1530
  get schedules() {
1550
1531
  return new Schedules(this.http);
1551
1532
  }
1533
+ /**
1534
+ * Access the flow control API.
1535
+ *
1536
+ * List, get, or reset flow controls.
1537
+ */
1538
+ get flowControl() {
1539
+ return new FlowControlApi(this.http);
1540
+ }
1552
1541
  /**
1553
1542
  * Access the workflow API.
1554
1543
  *
@@ -1673,47 +1662,39 @@ var Client = class {
1673
1662
  * }
1674
1663
  * ```
1675
1664
  */
1676
- async logs(request = {}) {
1677
- const {
1678
- urlGroup,
1679
- // eslint-disable-next-line @typescript-eslint/no-deprecated
1680
- topicName,
1681
- fromDate,
1682
- toDate,
1683
- callerIp,
1684
- messageIds,
1685
- // eslint-disable-next-line @typescript-eslint/no-deprecated
1686
- count: filterCount,
1687
- ...restFilter
1688
- } = request.filter ?? {};
1689
- const filterPayload = {
1690
- ...restFilter,
1691
- topicName: urlGroup ?? topicName,
1692
- fromDate,
1693
- toDate,
1694
- callerIp
1695
- };
1696
- let cursorString;
1697
- if (typeof request.cursor === "number" && request.cursor > 0) {
1698
- cursorString = request.cursor.toString();
1699
- } else if (typeof request.cursor === "string" && request.cursor !== "") {
1700
- cursorString = request.cursor;
1701
- }
1702
- const query = {
1703
- cursor: cursorString,
1704
- count: request.count ?? filterCount,
1705
- order: request.order,
1706
- trimBody: request.trimBody,
1707
- messageIds,
1708
- ...filterPayload
1709
- };
1665
+ async logs(request) {
1666
+ const query = {};
1667
+ if (typeof request?.cursor === "number" && request.cursor > 0) {
1668
+ query.cursor = request.cursor.toString();
1669
+ } else if (typeof request?.cursor === "string" && request.cursor !== "") {
1670
+ query.cursor = request.cursor;
1671
+ }
1672
+ for (const [key, value] of Object.entries(request?.filter ?? {})) {
1673
+ if (typeof value === "number" && value < 0) {
1674
+ continue;
1675
+ }
1676
+ if (key === "urlGroup") {
1677
+ query.topicName = value.toString();
1678
+ } else if (typeof value !== "undefined") {
1679
+ query[key] = value.toString();
1680
+ }
1681
+ }
1710
1682
  const responsePayload = await this.http.request({
1711
1683
  path: ["v2", "events"],
1712
1684
  method: "GET",
1713
1685
  query
1714
1686
  });
1715
- const logs = responsePayload.events.map((event) => ({ ...event, urlGroup: event.topicName }));
1716
- return { cursor: responsePayload.cursor, logs, events: logs };
1687
+ const logs = responsePayload.events.map((event) => {
1688
+ return {
1689
+ ...event,
1690
+ urlGroup: event.topicName
1691
+ };
1692
+ });
1693
+ return {
1694
+ cursor: responsePayload.cursor,
1695
+ logs,
1696
+ events: logs
1697
+ };
1717
1698
  }
1718
1699
  /**
1719
1700
  * @deprecated Will be removed in the next major release. Use the `logs` method instead.
package/nextjs.mjs CHANGED
@@ -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
  // platforms/nextjs.ts
7
7
  var BAD_REQUEST = 400;
package/nuxt.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  verifySignatureH3
3
- } from "./chunk-STWPT5EV.mjs";
4
- import "./chunk-SN6OPGRS.mjs";
5
- import "./chunk-RUCOF5QZ.mjs";
3
+ } from "./chunk-JO26IBSH.mjs";
4
+ import "./chunk-KDHOB7B5.mjs";
5
+ import "./chunk-DT2X63FB.mjs";
6
6
 
7
7
  // platforms/nuxt.ts
8
8
  var verifySignatureNuxt = verifySignatureH3;
package/package.json CHANGED
@@ -1 +1 @@
1
- {"version":"v2.9.1-rc.1","name":"@upstash/qstash","description":"Official Typescript client for QStash","author":"Andreas Thomas <dev@chronark.com>","license":"MIT","homepage":"https://github.com/upstash/qstash-js#readme","repository":{"type":"git","url":"git+https://github.com/upstash/qstash-js.git"},"bugs":{"url":"https://github.com/upstash/qstash-js/issues"},"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"},"./nuxt":{"import":"./nuxt.mjs","require":"./nuxt.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"}},"keywords":["qstash","queue","events","serverless","upstash"],"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"},"devDependencies":{"@commitlint/cli":"^19.2.2","@commitlint/config-conventional":"^19.2.2","@eslint/eslintrc":"^3.1.0","@eslint/js":"^9.10.0","@solidjs/start":"^1.0.6","@sveltejs/kit":"^2.5.18","@types/bun":"^1.1.1","@types/crypto-js":"^4.2.0","@typescript-eslint/eslint-plugin":"^8.4.0","@typescript-eslint/parser":"^8.4.0","bun-types":"^1.1.7","eslint":"^9.10.0","eslint-plugin-unicorn":"^51.0.1","h3":"^1.12.0","hono":"^4.5.8","husky":"^9.0.10","next":"^14.0.2","prettier":"^3.2.5","tsup":"latest","typescript":"^5.4.5","undici-types":"^6.16.0","vitest":"latest"},"dependencies":{"crypto-js":">=4.2.0","jose":"^5.2.3","neverthrow":"^7.0.1"}}
1
+ {"version":"v2.9.1","name":"@upstash/qstash","description":"Official Typescript client for QStash","author":"Andreas Thomas <dev@chronark.com>","license":"MIT","homepage":"https://github.com/upstash/qstash-js#readme","repository":{"type":"git","url":"git+https://github.com/upstash/qstash-js.git"},"bugs":{"url":"https://github.com/upstash/qstash-js/issues"},"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"},"./nuxt":{"import":"./nuxt.mjs","require":"./nuxt.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"}},"keywords":["qstash","queue","events","serverless","upstash"],"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"},"devDependencies":{"@commitlint/cli":"^19.2.2","@commitlint/config-conventional":"^19.2.2","@eslint/eslintrc":"^3.1.0","@eslint/js":"^9.10.0","@solidjs/start":"^1.0.6","@sveltejs/kit":"^2.5.18","@types/bun":"^1.1.1","@types/crypto-js":"^4.2.0","@typescript-eslint/eslint-plugin":"^8.4.0","@typescript-eslint/parser":"^8.4.0","bun-types":"^1.1.7","eslint":"^9.10.0","eslint-plugin-unicorn":"^51.0.1","h3":"^1.12.0","hono":"^4.5.8","husky":"^9.0.10","next":"^14.0.2","prettier":"^3.2.5","tsup":"latest","typescript":"^5.4.5","undici-types":"^6.16.0","vitest":"latest"},"dependencies":{"crypto-js":">=4.2.0","jose":"^5.2.3","neverthrow":"^7.0.1"}}
package/solidjs.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIHandler, APIEvent } from '@solidjs/start/server';
2
- import { aa as RouteFunction, ab as WorkflowServeOptions } from './client-Gv4WRTxB.mjs';
2
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-jh_SomWB.mjs';
3
3
  import 'neverthrow';
4
4
 
5
5
  type VerifySignatureConfig = {
package/solidjs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIHandler, APIEvent } from '@solidjs/start/server';
2
- import { aa as RouteFunction, ab as WorkflowServeOptions } from './client-Gv4WRTxB.js';
2
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-jh_SomWB.js';
3
3
  import 'neverthrow';
4
4
 
5
5
  type VerifySignatureConfig = {