@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.
@@ -103,7 +103,7 @@ type LogPayload = Omit<Log, "urlGroup"> & {
103
103
  topicName: string;
104
104
  };
105
105
  /**
106
- * Deprecated. Use the `EventPayload` type instead.
106
+ * Deprecated. Use the `LogPayload` type instead.
107
107
  *
108
108
  * @deprecated
109
109
  */
@@ -464,7 +464,7 @@ type UpstashRequest = {
464
464
  * A string to set request's method.
465
465
  */
466
466
  method?: HTTPMethods;
467
- query?: Record<string, string | number | boolean | undefined>;
467
+ query?: Record<string, string | number | boolean | Date | string[] | undefined>;
468
468
  /**
469
469
  * if enabled, call `res.json()`
470
470
  *
@@ -505,6 +505,146 @@ type RetryConfig = false | {
505
505
  backoff?: (retryCount: number) => number;
506
506
  };
507
507
 
508
+ type RequireAtLeastOne<T> = {
509
+ [K in keyof T]-?: Required<Pick<T, K>>;
510
+ }[keyof T];
511
+ type NeverKeys<T> = {
512
+ [K in keyof T]?: never;
513
+ };
514
+ /** Two-branch exclusive union: A or B, never both. */
515
+ type Exclusive<A, B> = (A & NeverKeys<B>) | (B & NeverKeys<A>);
516
+ /** Shared filter fields accepted by every qstash & workflow endpoint. */
517
+ type UniversalFilterFields = {
518
+ fromDate?: Date | number;
519
+ toDate?: Date | number;
520
+ callerIp?: string;
521
+ label?: string;
522
+ flowControlKey?: string;
523
+ };
524
+ /** QStash-specific identity filters (DLQ + message endpoints). */
525
+ type QStashIdentityFields = {
526
+ messageId?: string;
527
+ url?: string;
528
+ urlGroup?: string;
529
+ scheduleId?: string;
530
+ queueName?: string;
531
+ };
532
+ /** DLQ-specific response filter. */
533
+ type DLQResponseFields = {
534
+ responseStatus?: number;
535
+ };
536
+ /** Logs-specific filter fields exclusive to log endpoints. */
537
+ type LogsFilterFields = {
538
+ state?: State;
539
+ };
540
+ type DLQFilterFields = UniversalFilterFields & QStashIdentityFields & DLQResponseFields & {
541
+ /**
542
+ * @deprecated `api` filter has been removed from the API and will be ignored
543
+ */
544
+ api?: string;
545
+ };
546
+ type MessageCancelFilterFields = UniversalFilterFields & Omit<QStashIdentityFields, "messageId">;
547
+ /**
548
+ * Doesn't allow a single messageId because this is a bulk action.
549
+ * Cancel does not support cursor.
550
+ */
551
+ type MessageCancelFilters = {
552
+ messageIds: string[];
553
+ filter?: never;
554
+ all?: never;
555
+ count?: never;
556
+ } | ({
557
+ filter: RequireAtLeastOne<MessageCancelFilterFields>;
558
+ messageIds?: never;
559
+ all?: never;
560
+ } & MessageCancelCount) | ({
561
+ all: true;
562
+ messageIds?: never;
563
+ filter?: never;
564
+ } & MessageCancelCount);
565
+ type MessageCancelCount = {
566
+ /**
567
+ * Maximum number of messages to cancel per call.
568
+ *
569
+ * @default 100
570
+ */
571
+ count?: number;
572
+ };
573
+ /**
574
+ * DLQ bulk actions support three modes:
575
+ * - By dlqIds (no cursor)
576
+ * - By filter fields (with optional cursor)
577
+ * - All (with optional cursor)
578
+ */
579
+ type DLQBulkActionFilters = {
580
+ dlqIds: string | string[];
581
+ filter?: never;
582
+ all?: never;
583
+ count?: never;
584
+ cursor?: never;
585
+ } | ({
586
+ filter: RequireAtLeastOne<DLQFilterFields>;
587
+ dlqIds?: never;
588
+ all?: never;
589
+ } & DLQBulkActionCount) | ({
590
+ all: true;
591
+ dlqIds?: never;
592
+ filter?: never;
593
+ } & DLQBulkActionCount);
594
+ type DLQBulkActionCount = {
595
+ cursor?: string;
596
+ /**
597
+ * Maximum number of messages to process per call.
598
+ *
599
+ * @default 100
600
+ */
601
+ count?: number;
602
+ };
603
+ type DLQListRequest = Exclusive<{
604
+ dlqIds: string | string[];
605
+ }, {
606
+ filter?: DLQFilterFields;
607
+ cursor?: string;
608
+ }>;
609
+ type LogsListRequest = Exclusive<{
610
+ messageIds: string[];
611
+ }, {
612
+ filter?: LogsListFilters;
613
+ /**
614
+ * Passing `number` may silently break due to JavaScript integer precision
615
+ * limits — cursor values can exceed `Number.MAX_SAFE_INTEGER`. Use `string` instead.
616
+ */
617
+ cursor?: string | number;
618
+ }>;
619
+ type LogsListFilters = UniversalFilterFields & Omit<QStashIdentityFields, "messageId"> & LogsFilterFields & {
620
+ /**
621
+ * @deprecated `api` filter has been removed from the API and will be ignored
622
+ */
623
+ api?: string;
624
+ /**
625
+ * @deprecated use `messageIds` in the root instead of `messageId` in the `filter` object
626
+ *
627
+ * Example:
628
+ * ```ts
629
+ * await client.logs({ messageIds: ["id1", "id2"] })
630
+ * ```
631
+ */
632
+ messageId?: string;
633
+ /**
634
+ * @deprecated use `urlGroup` instead
635
+ */
636
+ topicName?: string;
637
+ /**
638
+ * @deprecated use `count` option in the root instead of the `filter` object
639
+ *
640
+ * Example:
641
+ * ```ts
642
+ * await client.logs({ count: 50 })
643
+ * ```
644
+ */
645
+ count?: number;
646
+ };
647
+
508
648
  type Message = {
509
649
  /**
510
650
  * A unique identifier for this message.
@@ -627,10 +767,44 @@ declare class Messages {
627
767
  */
628
768
  get(messageId: string): Promise<Message>;
629
769
  /**
630
- * Cancel a message
770
+ * Cancel messages.
771
+ *
772
+ * Can be called with:
773
+ * - A single messageId: `cancel("id")`
774
+ * - An array of messageIds: `cancel(["id1", "id2"])`
775
+ * - A filter object: `cancel({ filter: { flowControlKey: "key", label: "label" } })`
776
+ * - All messages: `cancel({ all: true })`
777
+ *
778
+ * Pass `count` to limit the number of messages processed per call (defaults to 100).
779
+ * Call in a loop until `cancelled` is 0:
780
+ *
781
+ * ```ts
782
+ * let cancelled: number;
783
+ * do {
784
+ * const result = await messages.cancel({ all: true, count: 100 });
785
+ * cancelled = result.cancelled;
786
+ * } while (cancelled > 0);
787
+ * ```
788
+ */
789
+ cancel(request: string | string[] | MessageCancelFilters): Promise<{
790
+ cancelled: number;
791
+ }>;
792
+ /**
793
+ * Delete a message.
794
+ *
795
+ * @deprecated Use `cancel(messageId: string)` instead
631
796
  */
632
797
  delete(messageId: string): Promise<void>;
798
+ /**
799
+ * Cancel multiple messages by their messageIds.
800
+ *
801
+ * @deprecated Use `cancel(messageIds: string[])` instead
802
+ */
633
803
  deleteMany(messageIds: string[]): Promise<number>;
804
+ /**
805
+ * Cancel all messages
806
+ * @deprecated Use `cancel({all: true})` to cancel all
807
+ */
634
808
  deleteAll(): Promise<number>;
635
809
  }
636
810
 
@@ -658,77 +832,85 @@ type DlqMessage = Message & {
658
832
  */
659
833
  responseBodyBase64?: string;
660
834
  };
661
- type DLQFilter = {
662
- /**
663
- * Filter DLQ entries by message id
664
- */
665
- messageId?: string;
666
- /**
667
- * Filter DLQ entries by url
668
- */
669
- url?: string;
670
- /**
671
- * Filter DLQ entries by url group name
672
- */
673
- urlGroup?: string;
674
- /**
675
- * Filter DLQ entries by api name
676
- */
677
- api?: string;
678
- /**
679
- * Filter DLQ entries by queue name
680
- */
681
- queueName?: string;
682
- /**
683
- * Filter DLQ entries by schedule id
684
- */
685
- scheduleId?: string;
686
- /**
687
- * Filter DLQ entries by starting time, in milliseconds
688
- */
689
- fromDate?: number;
690
- /**
691
- * Filter DLQ entries by ending time, in milliseconds
692
- */
693
- toDate?: number;
694
- /**
695
- * Filter DLQ entries by label
696
- */
697
- label?: string;
698
- /**
699
- * Filter DLQ entries by HTTP status of the response
700
- */
701
- responseStatus?: number;
702
- /**
703
- * Filter DLQ entries by IP address of the publisher of the message
704
- */
705
- callerIp?: string;
706
- };
707
835
  declare class DLQ {
708
836
  private readonly http;
709
837
  constructor(http: Requester);
710
838
  /**
711
839
  * List messages in the dlq
840
+ *
841
+ * Can be called with:
842
+ * - Filters: `listMessages({ filter: { url: "https://example.com" } })`
843
+ * - DLQ IDs: `listMessages({ dlqIds: ["id1", "id2"] })`
844
+ * - No filter (list all): `listMessages()`
712
845
  */
713
846
  listMessages(options?: {
714
- cursor?: string;
715
847
  count?: number;
716
- filter?: DLQFilter;
717
- }): Promise<{
848
+ } & DLQListRequest): Promise<{
718
849
  messages: DlqMessage[];
719
850
  cursor?: string;
720
851
  }>;
721
852
  /**
722
- * Remove a message from the dlq using it's `dlqId`
853
+ * Remove messages from the dlq.
854
+ *
855
+ * Can be called with:
856
+ * - A single dlqId: `delete("id")`
857
+ * - An array of dlqIds: `delete(["id1", "id2"])`
858
+ * - An object with dlqIds: `delete({ dlqIds: ["id1", "id2"] })`
859
+ * - A filter object: `delete({ filter: { url: "https://example.com", label: "label" } })`
860
+ * - All messages: `delete({ all: true })`
861
+ *
862
+ * Pass `count` to limit the number of messages processed per call (defaults to 100).
863
+ * Call in a loop until cursor is undefined:
864
+ *
865
+ * ```ts
866
+ * let cursor: string | undefined;
867
+ * do {
868
+ * const result = await dlq.delete({ all: true, count: 100, cursor });
869
+ * cursor = result.cursor;
870
+ * } while (cursor);
871
+ * ```
723
872
  */
724
- delete(dlqMessageId: string): Promise<void>;
873
+ delete(request: string | string[] | DLQBulkActionFilters): Promise<{
874
+ deleted: number;
875
+ cursor?: string;
876
+ }>;
725
877
  /**
726
878
  * Remove multiple messages from the dlq using their `dlqId`s
879
+ *
880
+ * @deprecated Use `delete` instead
727
881
  */
728
882
  deleteMany(request: {
729
883
  dlqIds: string[];
730
884
  }): Promise<{
731
885
  deleted: number;
886
+ cursor?: string;
887
+ }>;
888
+ /**
889
+ * Retry messages from the dlq.
890
+ *
891
+ * Can be called with:
892
+ * - A single dlqId: `retry("id")`
893
+ * - An array of dlqIds: `retry(["id1", "id2"])`
894
+ * - An object with dlqIds: `retry({ dlqIds: ["id1", "id2"] })`
895
+ * - A filter object: `retry({ filter: { url: "https://example.com", label: "label" } })`
896
+ * - All messages: `retry({ all: true })`
897
+ *
898
+ * Pass `count` to limit the number of messages processed per call (defaults to 100).
899
+ * Call in a loop until cursor is undefined:
900
+ *
901
+ * ```ts
902
+ * let cursor: string | undefined;
903
+ * do {
904
+ * const result = await dlq.retry({ all: true, count: 100, cursor });
905
+ * cursor = result.cursor;
906
+ * } while (cursor);
907
+ * ```
908
+ */
909
+ retry(request: string | string[] | DLQBulkActionFilters): Promise<{
910
+ cursor?: string;
911
+ responses: {
912
+ messageId: string;
913
+ }[];
732
914
  }>;
733
915
  }
734
916
 
@@ -1117,6 +1299,19 @@ type CreateScheduleRequest = {
1117
1299
  * @default undefined
1118
1300
  */
1119
1301
  label?: string;
1302
+ /**
1303
+ * Configure which fields should be redacted in logs.
1304
+ *
1305
+ * - `body: true` redacts the request body
1306
+ * - `header: true` redacts all headers
1307
+ * - `header: ["X"]` redacts specific headers (e.g., ["Authorization"])
1308
+ *
1309
+ * @default undefined
1310
+ */
1311
+ redact?: {
1312
+ body?: true;
1313
+ header?: true | string[];
1314
+ };
1120
1315
  } & Pick<PublishRequest, "retryDelay">;
1121
1316
  declare class Schedules {
1122
1317
  private readonly http;
@@ -2074,6 +2269,19 @@ type PublishRequest<TBody = BodyInit> = {
2074
2269
  * @default undefined
2075
2270
  */
2076
2271
  label?: string;
2272
+ /**
2273
+ * Configure which fields should be redacted in logs.
2274
+ *
2275
+ * - `body: true` redacts the request body
2276
+ * - `header: true` redacts all headers
2277
+ * - `header: ["X"]` redacts specific headers (e.g., ["Authorization"])
2278
+ *
2279
+ * @default undefined
2280
+ */
2281
+ redact?: {
2282
+ body?: true;
2283
+ header?: true | string[];
2284
+ };
2077
2285
  } & ({
2078
2286
  /**
2079
2287
  * The url where the message should be sent to.
@@ -2158,29 +2366,15 @@ type PublishJsonRequest = Omit<PublishRequest, "body"> & {
2158
2366
  body: unknown;
2159
2367
  };
2160
2368
  type LogsRequest = {
2161
- cursor?: string | number;
2162
- filter?: LogsRequestFilter;
2163
- };
2369
+ /** Max 1000. Defaults to 10 when `groupBy` is used. */
2370
+ count?: number;
2371
+ } & LogsListRequest;
2164
2372
  /**
2165
2373
  * Deprecated. Use `LogsRequest` instead.
2166
2374
  *
2167
2375
  * @deprecated
2168
2376
  */
2169
2377
  type EventsRequest = LogsRequest;
2170
- type LogsRequestFilter = {
2171
- messageId?: string;
2172
- state?: State;
2173
- url?: string;
2174
- urlGroup?: string;
2175
- topicName?: string;
2176
- api?: string;
2177
- scheduleId?: string;
2178
- queueName?: string;
2179
- fromDate?: number;
2180
- toDate?: number;
2181
- count?: number;
2182
- label?: string;
2183
- };
2184
2378
  type GetLogsResponse = {
2185
2379
  cursor?: string;
2186
2380
  logs: Log[];