@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/nextjs.js CHANGED
@@ -396,6 +396,43 @@ 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
+ }
399
436
  function getRuntime() {
400
437
  if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
401
438
  return `bun@${process.versions.bun}`;
@@ -625,17 +662,20 @@ var DLQ = class {
625
662
  /**
626
663
  * List messages in the dlq
627
664
  */
628
- async listMessages(options) {
665
+ async listMessages(options = {}) {
666
+ const { urlGroup, ...restFilter } = options.filter ?? {};
629
667
  const filterPayload = {
630
- ...options?.filter,
631
- topicName: options?.filter?.urlGroup
668
+ ...restFilter,
669
+ ...urlGroup === void 0 ? {} : { topicName: urlGroup }
632
670
  };
633
671
  const messagesPayload = await this.http.request({
634
672
  method: "GET",
635
673
  path: ["v2", "dlq"],
636
674
  query: {
637
- cursor: options?.cursor,
638
- count: options?.count,
675
+ cursor: options.cursor,
676
+ count: options.count,
677
+ order: options.order,
678
+ trimBody: options.trimBody,
639
679
  ...filterPayload
640
680
  }
641
681
  });
@@ -651,26 +691,70 @@ var DLQ = class {
651
691
  };
652
692
  }
653
693
  /**
654
- * Remove a message from the dlq using it's `dlqId`
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.
655
704
  */
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
- });
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
+ );
663
724
  }
664
725
  /**
665
726
  * Remove multiple messages from the dlq using their `dlqId`s
727
+ *
728
+ * @deprecated Use `delete` instead
666
729
  */
667
730
  async deleteMany(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
- });
731
+ return await this.delete(request);
732
+ }
733
+ /**
734
+ * Retry messages from the dlq.
735
+ *
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 })`
742
+ *
743
+ * Note: passing an empty array returns `{ responses: [] }` without making a request.
744
+ */
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
+ );
674
758
  }
675
759
  };
676
760
 
@@ -771,7 +855,15 @@ var HttpClient = class {
771
855
  const url = new URL([request.baseUrl ?? this.baseUrl, ...request.path].join("/"));
772
856
  if (request.query) {
773
857
  for (const [key, value] of Object.entries(request.query)) {
774
- if (value !== void 0) {
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 {
775
867
  url.searchParams.set(key, value.toString());
776
868
  }
777
869
  }
@@ -1002,29 +1094,57 @@ var Messages = class {
1002
1094
  return message;
1003
1095
  }
1004
1096
  /**
1005
- * Cancel a message
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 })`
1006
1104
  */
1007
- async delete(messageId) {
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;
1008
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
1125
+ */
1126
+ async delete(messageId) {
1127
+ await this.http.request({
1009
1128
  method: "DELETE",
1010
1129
  path: ["v2", "messages", messageId],
1011
1130
  parseResponseAsJson: false
1012
1131
  });
1013
1132
  }
1133
+ /**
1134
+ * Cancel multiple messages by their messageIds.
1135
+ *
1136
+ * @deprecated Use `cancel(messageIds: string[])` instead
1137
+ */
1014
1138
  async deleteMany(messageIds) {
1015
- const result = await this.http.request({
1016
- method: "DELETE",
1017
- path: ["v2", "messages"],
1018
- headers: { "Content-Type": "application/json" },
1019
- body: JSON.stringify({ messageIds })
1020
- });
1139
+ const result = await this.cancel(messageIds);
1021
1140
  return result.cancelled;
1022
1141
  }
1142
+ /**
1143
+ * Cancel all messages
1144
+ * @deprecated Use `cancel({all: true})` to cancel all
1145
+ */
1023
1146
  async deleteAll() {
1024
- const result = await this.http.request({
1025
- method: "DELETE",
1026
- path: ["v2", "messages"]
1027
- });
1147
+ const result = await this.cancel({ all: true });
1028
1148
  return result.cancelled;
1029
1149
  }
1030
1150
  };
@@ -1358,7 +1478,7 @@ var UrlGroups = class {
1358
1478
  };
1359
1479
 
1360
1480
  // version.ts
1361
- var VERSION = "v2.9.0";
1481
+ var VERSION = "v2.9.1-rc.1";
1362
1482
 
1363
1483
  // src/client/client.ts
1364
1484
  var Client = class {
@@ -1553,39 +1673,47 @@ var Client = class {
1553
1673
  * }
1554
1674
  * ```
1555
1675
  */
1556
- async logs(request) {
1557
- const query = {};
1558
- if (typeof request?.cursor === "number" && request.cursor > 0) {
1559
- query.cursor = request.cursor.toString();
1560
- } else if (typeof request?.cursor === "string" && request.cursor !== "") {
1561
- query.cursor = request.cursor;
1562
- }
1563
- for (const [key, value] of Object.entries(request?.filter ?? {})) {
1564
- if (typeof value === "number" && value < 0) {
1565
- continue;
1566
- }
1567
- if (key === "urlGroup") {
1568
- query.topicName = value.toString();
1569
- } else if (typeof value !== "undefined") {
1570
- query[key] = value.toString();
1571
- }
1572
- }
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
+ };
1573
1710
  const responsePayload = await this.http.request({
1574
1711
  path: ["v2", "events"],
1575
1712
  method: "GET",
1576
1713
  query
1577
1714
  });
1578
- const logs = responsePayload.events.map((event) => {
1579
- return {
1580
- ...event,
1581
- urlGroup: event.topicName
1582
- };
1583
- });
1584
- return {
1585
- cursor: responsePayload.cursor,
1586
- logs,
1587
- events: logs
1588
- };
1715
+ const logs = responsePayload.events.map((event) => ({ ...event, urlGroup: event.topicName }));
1716
+ return { cursor: responsePayload.cursor, logs, events: logs };
1589
1717
  }
1590
1718
  /**
1591
1719
  * @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-QYBCXZKB.mjs";
4
+ } from "./chunk-RUCOF5QZ.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-H5OAU75L.mjs";
4
- import "./chunk-M7SEEFAC.mjs";
5
- import "./chunk-QYBCXZKB.mjs";
3
+ } from "./chunk-STWPT5EV.mjs";
4
+ import "./chunk-SN6OPGRS.mjs";
5
+ import "./chunk-RUCOF5QZ.mjs";
6
6
 
7
7
  // platforms/nuxt.ts
8
8
  var verifySignatureNuxt = verifySignatureH3;
package/package.json CHANGED
@@ -1 +1 @@
1
- {"version":"v2.9.0","name":"@upstash/qstash","description":"Official Typescript client for QStash","author":"Andreas Thomas <dev@chronark.com>","license":"MIT","homepage":"https://github.com/upstash/sdk-qstash-ts#readme","repository":{"type":"git","url":"git+https://github.com/upstash/sdk-qstash-ts.git"},"bugs":{"url":"https://github.com/upstash/sdk-qstash-ts/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-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"}}
package/solidjs.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { APIHandler, APIEvent } from '@solidjs/start/server';
2
- import { a9 as RouteFunction, aa as WorkflowServeOptions } from './client-BVG9vt90.mjs';
2
+ import { aa as RouteFunction, ab as WorkflowServeOptions } from './client-Gv4WRTxB.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 { a9 as RouteFunction, aa as WorkflowServeOptions } from './client-BVG9vt90.js';
2
+ import { aa as RouteFunction, ab as WorkflowServeOptions } from './client-Gv4WRTxB.js';
3
3
  import 'neverthrow';
4
4
 
5
5
  type VerifySignatureConfig = {