@upstash/qstash 2.9.1 → 2.10.0

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/solidjs.js CHANGED
@@ -239,6 +239,14 @@ var QstashDailyRatelimitError = class extends QstashError {
239
239
  this.reset = args.reset;
240
240
  }
241
241
  };
242
+ var QstashEmptyArrayError = class extends QstashError {
243
+ constructor(parameterName) {
244
+ super(
245
+ `Empty array provided for query parameter "${parameterName}". This would result in no filter being applied, which could affect all resources.`
246
+ );
247
+ this.name = "QstashEmptyArrayError";
248
+ }
249
+ };
242
250
  var QStashWorkflowError = class extends QstashError {
243
251
  constructor(message) {
244
252
  super(message);
@@ -268,6 +276,7 @@ var formatWorkflowError = (error) => {
268
276
  };
269
277
 
270
278
  // src/client/utils.ts
279
+ var DEFAULT_BULK_COUNT = 100;
271
280
  var isIgnoredHeader = (header) => {
272
281
  const lowerCaseHeader = header.toLowerCase();
273
282
  return lowerCaseHeader.startsWith("content-type") || lowerCaseHeader.startsWith("upstash-");
@@ -354,6 +363,24 @@ function processHeaders(request) {
354
363
  if (request.label !== void 0) {
355
364
  headers.set("Upstash-Label", request.label);
356
365
  }
366
+ if (request.redact !== void 0) {
367
+ const redactParts = [];
368
+ if (request.redact.body) {
369
+ redactParts.push("body");
370
+ }
371
+ if (request.redact.header !== void 0) {
372
+ if (request.redact.header === true) {
373
+ redactParts.push("header");
374
+ } else if (Array.isArray(request.redact.header) && request.redact.header.length > 0) {
375
+ for (const headerName of request.redact.header) {
376
+ redactParts.push(`header[${headerName}]`);
377
+ }
378
+ }
379
+ }
380
+ if (redactParts.length > 0) {
381
+ headers.set("Upstash-Redact-Fields", redactParts.join(","));
382
+ }
383
+ }
357
384
  return headers;
358
385
  }
359
386
  function getRequestPath(request) {
@@ -393,6 +420,44 @@ function decodeBase64(base64) {
393
420
  }
394
421
  }
395
422
  }
423
+ function buildBulkActionFilterPayload(request) {
424
+ const cursor = "cursor" in request ? request.cursor : void 0;
425
+ if ("all" in request) {
426
+ const count2 = "count" in request ? request.count ?? DEFAULT_BULK_COUNT : DEFAULT_BULK_COUNT;
427
+ return { count: count2, cursor };
428
+ }
429
+ if ("dlqIds" in request) {
430
+ const ids = request.dlqIds;
431
+ if (Array.isArray(ids) && ids.length === 0) {
432
+ throw new QstashError(
433
+ "Empty dlqIds array provided. If you intend to target all DLQ messages, use { all: true } explicitly."
434
+ );
435
+ }
436
+ return { dlqIds: ids, cursor };
437
+ }
438
+ if ("messageIds" in request && request.messageIds) {
439
+ if (request.messageIds.length === 0) {
440
+ throw new QstashError(
441
+ "Empty messageIds array provided. If you intend to target all messages, use { all: true } explicitly."
442
+ );
443
+ }
444
+ return { messageIds: request.messageIds, cursor };
445
+ }
446
+ const count = "count" in request ? request.count ?? DEFAULT_BULK_COUNT : DEFAULT_BULK_COUNT;
447
+ return {
448
+ ...renameUrlGroup(request.filter),
449
+ count,
450
+ cursor
451
+ };
452
+ }
453
+ function renameUrlGroup(filter) {
454
+ const { urlGroup, api, ...rest } = filter;
455
+ return { ...rest, ...urlGroup === void 0 ? {} : { topicName: urlGroup } };
456
+ }
457
+ function normalizeCursor(response) {
458
+ const cursor = response.cursor;
459
+ return { ...response, cursor: cursor || void 0 };
460
+ }
396
461
  function getRuntime() {
397
462
  if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
398
463
  return `bun@${process.versions.bun}`;
@@ -621,20 +686,21 @@ var DLQ = class {
621
686
  }
622
687
  /**
623
688
  * List messages in the dlq
689
+ *
690
+ * Can be called with:
691
+ * - Filters: `listMessages({ filter: { url: "https://example.com" } })`
692
+ * - DLQ IDs: `listMessages({ dlqIds: ["id1", "id2"] })`
693
+ * - No filter (list all): `listMessages()`
624
694
  */
625
- async listMessages(options) {
626
- const filterPayload = {
627
- ...options?.filter,
628
- topicName: options?.filter?.urlGroup
695
+ async listMessages(options = {}) {
696
+ const query = {
697
+ count: options.count,
698
+ ..."dlqIds" in options ? { dlqIds: options.dlqIds } : { ...renameUrlGroup(options.filter ?? {}), cursor: options.cursor }
629
699
  };
630
700
  const messagesPayload = await this.http.request({
631
701
  method: "GET",
632
702
  path: ["v2", "dlq"],
633
- query: {
634
- cursor: options?.cursor,
635
- count: options?.count,
636
- ...filterPayload
637
- }
703
+ query
638
704
  });
639
705
  return {
640
706
  messages: messagesPayload.messages.map((message) => {
@@ -648,26 +714,86 @@ var DLQ = class {
648
714
  };
649
715
  }
650
716
  /**
651
- * Remove a message from the dlq using it's `dlqId`
717
+ * Remove messages from the dlq.
718
+ *
719
+ * Can be called with:
720
+ * - A single dlqId: `delete("id")`
721
+ * - An array of dlqIds: `delete(["id1", "id2"])`
722
+ * - An object with dlqIds: `delete({ dlqIds: ["id1", "id2"] })`
723
+ * - A filter object: `delete({ filter: { url: "https://example.com", label: "label" } })`
724
+ * - All messages: `delete({ all: true })`
725
+ *
726
+ * Pass `count` to limit the number of messages processed per call (defaults to 100).
727
+ * Call in a loop until cursor is undefined:
728
+ *
729
+ * ```ts
730
+ * let cursor: string | undefined;
731
+ * do {
732
+ * const result = await dlq.delete({ all: true, count: 100, cursor });
733
+ * cursor = result.cursor;
734
+ * } while (cursor);
735
+ * ```
652
736
  */
653
- async delete(dlqMessageId) {
737
+ async delete(request) {
738
+ if (typeof request === "string") {
739
+ await this.http.request({
740
+ method: "DELETE",
741
+ path: ["v2", "dlq", request],
742
+ parseResponseAsJson: false
743
+ });
744
+ return { deleted: 1 };
745
+ }
746
+ if (Array.isArray(request) && request.length === 0)
747
+ return { deleted: 0 };
748
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
654
749
  return await this.http.request({
655
750
  method: "DELETE",
656
- path: ["v2", "dlq", dlqMessageId],
657
- parseResponseAsJson: false
658
- // there is no response
751
+ path: ["v2", "dlq"],
752
+ query: buildBulkActionFilterPayload(filters)
659
753
  });
660
754
  }
661
755
  /**
662
756
  * Remove multiple messages from the dlq using their `dlqId`s
757
+ *
758
+ * @deprecated Use `delete` instead
663
759
  */
664
760
  async deleteMany(request) {
665
- return await this.http.request({
666
- method: "DELETE",
667
- path: ["v2", "dlq"],
668
- headers: { "Content-Type": "application/json" },
669
- body: JSON.stringify({ dlqIds: request.dlqIds })
670
- });
761
+ return await this.delete(request);
762
+ }
763
+ /**
764
+ * Retry messages from the dlq.
765
+ *
766
+ * Can be called with:
767
+ * - A single dlqId: `retry("id")`
768
+ * - An array of dlqIds: `retry(["id1", "id2"])`
769
+ * - An object with dlqIds: `retry({ dlqIds: ["id1", "id2"] })`
770
+ * - A filter object: `retry({ filter: { url: "https://example.com", label: "label" } })`
771
+ * - All messages: `retry({ all: true })`
772
+ *
773
+ * Pass `count` to limit the number of messages processed per call (defaults to 100).
774
+ * Call in a loop until cursor is undefined:
775
+ *
776
+ * ```ts
777
+ * let cursor: string | undefined;
778
+ * do {
779
+ * const result = await dlq.retry({ all: true, count: 100, cursor });
780
+ * cursor = result.cursor;
781
+ * } while (cursor);
782
+ * ```
783
+ */
784
+ async retry(request) {
785
+ if (typeof request === "string")
786
+ request = [request];
787
+ if (Array.isArray(request) && request.length === 0)
788
+ return { responses: [] };
789
+ const filters = Array.isArray(request) ? { dlqIds: request } : request;
790
+ return normalizeCursor(
791
+ await this.http.request({
792
+ method: "POST",
793
+ path: ["v2", "dlq", "retry"],
794
+ query: buildBulkActionFilterPayload(filters)
795
+ })
796
+ );
671
797
  }
672
798
  };
673
799
 
@@ -869,7 +995,18 @@ var HttpClient = class {
869
995
  const url = new URL([request.baseUrl ?? this.baseUrl, ...request.path].join("/"));
870
996
  if (request.query) {
871
997
  for (const [key, value] of Object.entries(request.query)) {
872
- if (value !== void 0) {
998
+ if (value === void 0)
999
+ continue;
1000
+ if (Array.isArray(value)) {
1001
+ if (value.length === 0) {
1002
+ throw new QstashEmptyArrayError(key);
1003
+ }
1004
+ for (const item of value) {
1005
+ url.searchParams.append(key, item);
1006
+ }
1007
+ } else if (value instanceof Date) {
1008
+ url.searchParams.set(key, value.getTime().toString());
1009
+ } else {
873
1010
  url.searchParams.set(key, value.toString());
874
1011
  }
875
1012
  }
@@ -1100,29 +1237,68 @@ var Messages = class {
1100
1237
  return message;
1101
1238
  }
1102
1239
  /**
1103
- * Cancel a message
1240
+ * Cancel messages.
1241
+ *
1242
+ * Can be called with:
1243
+ * - A single messageId: `cancel("id")`
1244
+ * - An array of messageIds: `cancel(["id1", "id2"])`
1245
+ * - A filter object: `cancel({ filter: { flowControlKey: "key", label: "label" } })`
1246
+ * - All messages: `cancel({ all: true })`
1247
+ *
1248
+ * Pass `count` to limit the number of messages processed per call (defaults to 100).
1249
+ * Call in a loop until `cancelled` is 0:
1250
+ *
1251
+ * ```ts
1252
+ * let cancelled: number;
1253
+ * do {
1254
+ * const result = await messages.cancel({ all: true, count: 100 });
1255
+ * cancelled = result.cancelled;
1256
+ * } while (cancelled > 0);
1257
+ * ```
1104
1258
  */
1105
- async delete(messageId) {
1259
+ async cancel(request) {
1260
+ if (typeof request === "string") {
1261
+ return await this.http.request({
1262
+ method: "DELETE",
1263
+ path: ["v2", "messages", request]
1264
+ });
1265
+ }
1266
+ if (Array.isArray(request) && request.length === 0)
1267
+ return { cancelled: 0 };
1268
+ const filters = Array.isArray(request) ? { messageIds: request } : request;
1106
1269
  return await this.http.request({
1270
+ method: "DELETE",
1271
+ path: ["v2", "messages"],
1272
+ query: buildBulkActionFilterPayload(filters)
1273
+ });
1274
+ }
1275
+ /**
1276
+ * Delete a message.
1277
+ *
1278
+ * @deprecated Use `cancel(messageId: string)` instead
1279
+ */
1280
+ async delete(messageId) {
1281
+ await this.http.request({
1107
1282
  method: "DELETE",
1108
1283
  path: ["v2", "messages", messageId],
1109
1284
  parseResponseAsJson: false
1110
1285
  });
1111
1286
  }
1287
+ /**
1288
+ * Cancel multiple messages by their messageIds.
1289
+ *
1290
+ * @deprecated Use `cancel(messageIds: string[])` instead
1291
+ */
1112
1292
  async deleteMany(messageIds) {
1113
- const result = await this.http.request({
1114
- method: "DELETE",
1115
- path: ["v2", "messages"],
1116
- headers: { "Content-Type": "application/json" },
1117
- body: JSON.stringify({ messageIds })
1118
- });
1293
+ const result = await this.cancel(messageIds);
1119
1294
  return result.cancelled;
1120
1295
  }
1296
+ /**
1297
+ * Cancel all messages
1298
+ * @deprecated Use `cancel({all: true})` to cancel all
1299
+ */
1121
1300
  async deleteAll() {
1122
- const result = await this.http.request({
1123
- method: "DELETE",
1124
- path: ["v2", "messages"]
1125
- });
1301
+ const result = await this.cancel({ all: true });
1126
1302
  return result.cancelled;
1127
1303
  }
1128
1304
  };
@@ -1327,6 +1503,24 @@ var Schedules = class {
1327
1503
  if (request.label !== void 0) {
1328
1504
  headers.set("Upstash-Label", request.label);
1329
1505
  }
1506
+ if (request.redact !== void 0) {
1507
+ const redactParts = [];
1508
+ if (request.redact.body) {
1509
+ redactParts.push("body");
1510
+ }
1511
+ if (request.redact.header !== void 0) {
1512
+ if (request.redact.header === true) {
1513
+ redactParts.push("header");
1514
+ } else if (Array.isArray(request.redact.header) && request.redact.header.length > 0) {
1515
+ for (const headerName of request.redact.header) {
1516
+ redactParts.push(`header[${headerName}]`);
1517
+ }
1518
+ }
1519
+ }
1520
+ if (redactParts.length > 0) {
1521
+ headers.set("Upstash-Redact-Fields", redactParts.join(","));
1522
+ }
1523
+ }
1330
1524
  return await this.http.request({
1331
1525
  method: "POST",
1332
1526
  headers: wrapWithGlobalHeaders(headers, this.http.headers, this.http.telemetryHeaders),
@@ -2842,7 +3036,7 @@ var Workflow = class {
2842
3036
  };
2843
3037
 
2844
3038
  // version.ts
2845
- var VERSION = "v2.9.1";
3039
+ var VERSION = "2.10.0";
2846
3040
 
2847
3041
  // src/client/client.ts
2848
3042
  var Client = class {
@@ -3045,39 +3239,18 @@ var Client = class {
3045
3239
  * }
3046
3240
  * ```
3047
3241
  */
3048
- async logs(request) {
3049
- const query = {};
3050
- if (typeof request?.cursor === "number" && request.cursor > 0) {
3051
- query.cursor = request.cursor.toString();
3052
- } else if (typeof request?.cursor === "string" && request.cursor !== "") {
3053
- query.cursor = request.cursor;
3054
- }
3055
- for (const [key, value] of Object.entries(request?.filter ?? {})) {
3056
- if (typeof value === "number" && value < 0) {
3057
- continue;
3058
- }
3059
- if (key === "urlGroup") {
3060
- query.topicName = value.toString();
3061
- } else if (typeof value !== "undefined") {
3062
- query[key] = value.toString();
3063
- }
3064
- }
3242
+ async logs(request = {}) {
3243
+ const query = {
3244
+ count: request.count,
3245
+ ..."messageIds" in request ? { messageIds: request.messageIds } : { ...renameUrlGroup(request.filter ?? {}), cursor: request.cursor }
3246
+ };
3065
3247
  const responsePayload = await this.http.request({
3066
3248
  path: ["v2", "events"],
3067
3249
  method: "GET",
3068
3250
  query
3069
3251
  });
3070
- const logs = responsePayload.events.map((event) => {
3071
- return {
3072
- ...event,
3073
- urlGroup: event.topicName
3074
- };
3075
- });
3076
- return {
3077
- cursor: responsePayload.cursor,
3078
- logs,
3079
- events: logs
3080
- };
3252
+ const logs = responsePayload.events.map((event) => ({ ...event, urlGroup: event.topicName }));
3253
+ return { cursor: responsePayload.cursor, logs, events: logs };
3081
3254
  }
3082
3255
  /**
3083
3256
  * @deprecated Will be removed in the next major release. Use the `logs` method instead.
package/solidjs.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import "./chunk-KDHOB7B5.mjs";
1
+ import "./chunk-FAMFGAMR.mjs";
2
2
  import {
3
3
  Receiver,
4
4
  serve
5
- } from "./chunk-DT2X63FB.mjs";
5
+ } from "./chunk-X3MMU3BQ.mjs";
6
6
 
7
7
  // platforms/solidjs.ts
8
8
  var verifySignatureSolidjs = (handler, config) => {
package/svelte.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from '@sveltejs/kit';
2
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-jh_SomWB.mjs';
2
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.mjs';
3
3
  import 'neverthrow';
4
4
 
5
5
  type VerifySignatureConfig = {
package/svelte.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from '@sveltejs/kit';
2
- import { ae as RouteFunction, af as WorkflowServeOptions } from './client-jh_SomWB.js';
2
+ import { ae as RouteFunction, af as WorkflowServeOptions } from './client-CsM1dTnz.js';
3
3
  import 'neverthrow';
4
4
 
5
5
  type VerifySignatureConfig = {