@upstash/qstash 2.5.0 → 2.5.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/README.md CHANGED
@@ -84,7 +84,7 @@ const isValid = await r.verify({
84
84
  * The signature from the `Upstash-Signature` header.
85
85
  *
86
86
  * Please note that on some platforms (e.g. Vercel or Netlify) you might
87
- * receive the header in lower case: `upstash-signature`
87
+ * receive the header in lower case: `upstash-signature`
88
88
  *
89
89
  */
90
90
  signature: "string";
@@ -0,0 +1,59 @@
1
+ // src/receiver.ts
2
+ import * as jose from "jose";
3
+ import crypto from "crypto-js";
4
+ var SignatureError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "SignatureError";
8
+ }
9
+ };
10
+ var Receiver = class {
11
+ currentSigningKey;
12
+ nextSigningKey;
13
+ constructor(config) {
14
+ this.currentSigningKey = config.currentSigningKey;
15
+ this.nextSigningKey = config.nextSigningKey;
16
+ }
17
+ /**
18
+ * Verify the signature of a request.
19
+ *
20
+ * Tries to verify the signature with the current signing key.
21
+ * If that fails, maybe because you have rotated the keys recently, it will
22
+ * try to verify the signature with the next signing key.
23
+ *
24
+ * If that fails, the signature is invalid and a `SignatureError` is thrown.
25
+ */
26
+ async verify(request) {
27
+ const isValid = await this.verifyWithKey(this.currentSigningKey, request);
28
+ if (isValid) {
29
+ return true;
30
+ }
31
+ return this.verifyWithKey(this.nextSigningKey, request);
32
+ }
33
+ /**
34
+ * Verify signature with a specific signing key
35
+ */
36
+ async verifyWithKey(key, request) {
37
+ const jwt = await jose.jwtVerify(request.signature, new TextEncoder().encode(key), {
38
+ issuer: "Upstash",
39
+ clockTolerance: request.clockTolerance
40
+ }).catch((error) => {
41
+ throw new SignatureError(error.message);
42
+ });
43
+ const p = jwt.payload;
44
+ if (request.url !== void 0 && p.sub !== request.url) {
45
+ throw new SignatureError(`invalid subject: ${p.sub}, want: ${request.url}`);
46
+ }
47
+ const bodyHash = crypto.SHA256(request.body).toString(crypto.enc.Base64url);
48
+ const padding = new RegExp(/=+$/);
49
+ if (p.body.replace(padding, "") !== bodyHash.replace(padding, "")) {
50
+ throw new SignatureError(`body hash does not match, want: ${p.body}, got: ${bodyHash}`);
51
+ }
52
+ return true;
53
+ }
54
+ };
55
+
56
+ export {
57
+ SignatureError,
58
+ Receiver
59
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/receiver.ts
2
+ var _jose = require('jose'); var jose = _interopRequireWildcard(_jose);
3
+ var _cryptojs = require('crypto-js'); var _cryptojs2 = _interopRequireDefault(_cryptojs);
4
+ var SignatureError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "SignatureError";
8
+ }
9
+ };
10
+ var Receiver = class {
11
+
12
+
13
+ constructor(config) {
14
+ this.currentSigningKey = config.currentSigningKey;
15
+ this.nextSigningKey = config.nextSigningKey;
16
+ }
17
+ /**
18
+ * Verify the signature of a request.
19
+ *
20
+ * Tries to verify the signature with the current signing key.
21
+ * If that fails, maybe because you have rotated the keys recently, it will
22
+ * try to verify the signature with the next signing key.
23
+ *
24
+ * If that fails, the signature is invalid and a `SignatureError` is thrown.
25
+ */
26
+ async verify(request) {
27
+ const isValid = await this.verifyWithKey(this.currentSigningKey, request);
28
+ if (isValid) {
29
+ return true;
30
+ }
31
+ return this.verifyWithKey(this.nextSigningKey, request);
32
+ }
33
+ /**
34
+ * Verify signature with a specific signing key
35
+ */
36
+ async verifyWithKey(key, request) {
37
+ const jwt = await jose.jwtVerify(request.signature, new TextEncoder().encode(key), {
38
+ issuer: "Upstash",
39
+ clockTolerance: request.clockTolerance
40
+ }).catch((error) => {
41
+ throw new SignatureError(error.message);
42
+ });
43
+ const p = jwt.payload;
44
+ if (request.url !== void 0 && p.sub !== request.url) {
45
+ throw new SignatureError(`invalid subject: ${p.sub}, want: ${request.url}`);
46
+ }
47
+ const bodyHash = _cryptojs2.default.SHA256(request.body).toString(_cryptojs2.default.enc.Base64url);
48
+ const padding = new RegExp(/=+$/);
49
+ if (p.body.replace(padding, "") !== bodyHash.replace(padding, "")) {
50
+ throw new SignatureError(`body hash does not match, want: ${p.body}, got: ${bodyHash}`);
51
+ }
52
+ return true;
53
+ }
54
+ };
55
+
56
+
57
+
58
+
59
+ exports.SignatureError = SignatureError; exports.Receiver = Receiver;
@@ -1,3 +1,5 @@
1
+ import { BodyInit, HeadersInit } from 'undici';
2
+
1
3
  /**
2
4
  * Necessary to verify the signature of a request.
3
5
  */
@@ -37,7 +39,7 @@ declare class SignatureError extends Error {
37
39
  constructor(message: string);
38
40
  }
39
41
  /**
40
- * Receiver offers a simlpe way to verify the signature of a request.
42
+ * Receiver offers a simple way to verify the signature of a request.
41
43
  */
42
44
  declare class Receiver {
43
45
  private readonly currentSigningKey;
@@ -52,7 +54,7 @@ declare class Receiver {
52
54
  *
53
55
  * If that fails, the signature is invalid and a `SignatureError` is thrown.
54
56
  */
55
- verify(req: VerifyRequest): Promise<boolean>;
57
+ verify(request: VerifyRequest): Promise<boolean>;
56
58
  /**
57
59
  * Verify signature with a specific signing key
58
60
  */
@@ -92,9 +94,9 @@ type UpstashRequest = {
92
94
  type UpstashResponse<TResult> = TResult & {
93
95
  error?: string;
94
96
  };
95
- interface Requester {
96
- request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;
97
- }
97
+ type Requester = {
98
+ request: <TResult = unknown>(request: UpstashRequest) => Promise<UpstashResponse<TResult>>;
99
+ };
98
100
  type RetryConfig = false | {
99
101
  /**
100
102
  * The number of retries to attempt before giving up.
@@ -181,7 +183,7 @@ declare class DLQ {
181
183
  /**
182
184
  * List messages in the dlq
183
185
  */
184
- listMessages(opts?: {
186
+ listMessages(options?: {
185
187
  cursor?: string;
186
188
  }): Promise<{
187
189
  messages: DlqMessage[];
@@ -194,7 +196,7 @@ declare class DLQ {
194
196
  /**
195
197
  * Remove multiple messages from the dlq using their `dlqId`s
196
198
  */
197
- deleteMany(req: {
199
+ deleteMany(request: {
198
200
  dlqIds: string[];
199
201
  }): Promise<{
200
202
  deleted: number;
@@ -219,7 +221,7 @@ declare class Queue {
219
221
  /**
220
222
  * Create or update the queue
221
223
  */
222
- upsert(req: UpsertQueueRequest): Promise<void>;
224
+ upsert(request: UpsertQueueRequest): Promise<void>;
223
225
  /**
224
226
  * Get the queue details
225
227
  */
@@ -235,11 +237,11 @@ declare class Queue {
235
237
  /**
236
238
  * Enqueue a message to a queue.
237
239
  */
238
- enqueue(req: EnqueueRequest): Promise<PublishResponse<PublishRequest>>;
240
+ enqueue(request: EnqueueRequest): Promise<PublishResponse<PublishRequest>>;
239
241
  /**
240
242
  * Enqueue a message to a queue, serializing the body to JSON.
241
243
  */
242
- enqueueJSON<TBody = unknown>(req: PublishRequest<TBody>): Promise<PublishResponse<PublishRequest<TBody>>>;
244
+ enqueueJSON<TBody = unknown>(request: PublishRequest<TBody>): Promise<PublishResponse<PublishRequest<TBody>>>;
243
245
  }
244
246
 
245
247
  type Schedule = {
@@ -326,7 +328,7 @@ declare class Schedules {
326
328
  /**
327
329
  * Create a schedule
328
330
  */
329
- create(req: CreateScheduleRequest): Promise<{
331
+ create(request: CreateScheduleRequest): Promise<{
330
332
  scheduleId: string;
331
333
  }>;
332
334
  /**
@@ -391,11 +393,11 @@ declare class Topics {
391
393
  /**
392
394
  * Create a new topic with the given name and endpoints
393
395
  */
394
- addEndpoints(req: AddEndpointsRequest): Promise<void>;
396
+ addEndpoints(request: AddEndpointsRequest): Promise<void>;
395
397
  /**
396
398
  * Remove endpoints from a topic.
397
399
  */
398
- removeEndpoints(req: RemoveEndpointsRequest): Promise<void>;
400
+ removeEndpoints(request: RemoveEndpointsRequest): Promise<void>;
399
401
  /**
400
402
  * Get a list of all topics.
401
403
  */
@@ -612,21 +614,21 @@ declare class Client {
612
614
  *
613
615
  * Create, read, update or delete queues.
614
616
  */
615
- queue(req?: QueueRequest): Queue;
616
- publish<TRequest extends PublishRequest>(req: TRequest): Promise<PublishResponse<TRequest>>;
617
+ queue(request?: QueueRequest): Queue;
618
+ publish<TRequest extends PublishRequest>(request: TRequest): Promise<PublishResponse<TRequest>>;
617
619
  /**
618
620
  * publishJSON is a utility wrapper around `publish` that automatically serializes the body
619
621
  * and sets the `Content-Type` header to `application/json`.
620
622
  */
621
- publishJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(req: TRequest): Promise<PublishResponse<TRequest>>;
623
+ publishJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(request: TRequest): Promise<PublishResponse<TRequest>>;
622
624
  /**
623
625
  * Batch publish messages to QStash.
624
626
  */
625
- batch(req: PublishRequest[]): Promise<PublishResponse<PublishRequest>[]>;
627
+ batch(request: PublishRequest[]): Promise<PublishResponse<PublishRequest>[]>;
626
628
  /**
627
629
  * Batch publish messages to QStash, serializing each body to JSON.
628
630
  */
629
- batchJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(req: TRequest[]): Promise<PublishResponse<TRequest>[]>;
631
+ batchJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(request: TRequest[]): Promise<PublishResponse<TRequest>[]>;
630
632
  /**
631
633
  * Retrieve your logs.
632
634
  *
@@ -646,7 +648,7 @@ declare class Client {
646
648
  * }
647
649
  * ```
648
650
  */
649
- events(req?: EventsRequest): Promise<GetEventsResponse>;
651
+ events(request?: EventsRequest): Promise<GetEventsResponse>;
650
652
  }
651
653
  type PublishToUrlResponse = {
652
654
  messageId: string;
@@ -668,4 +670,4 @@ declare class QstashRatelimitError extends QstashError {
668
670
  constructor(args: unknown);
669
671
  }
670
672
 
671
- export { AddEndpointsRequest, Client, CreateScheduleRequest, Endpoint, Event, EventsRequest, GetEventsResponse, Message, Messages, PublishJsonRequest, PublishRequest, PublishResponse, PublishToTopicResponse, PublishToUrlResponse, QstashError, QstashRatelimitError, QueueRequest, Receiver, ReceiverConfig, RemoveEndpointsRequest, Schedule, Schedules, SignatureError, State, Topic, Topics, VerifyRequest, WithCursor };
673
+ export { type AddEndpointsRequest, Client, type CreateScheduleRequest, type Endpoint, type Event, type EventsRequest, type GetEventsResponse, type Message, Messages, type PublishJsonRequest, type PublishRequest, type PublishResponse, type PublishToTopicResponse, type PublishToUrlResponse, QstashError, QstashRatelimitError, type QueueRequest, Receiver, type ReceiverConfig, type RemoveEndpointsRequest, type Schedule, Schedules, SignatureError, type State, type Topic, Topics, type VerifyRequest, type WithCursor };
@@ -1,3 +1,5 @@
1
+ import { BodyInit, HeadersInit } from 'undici';
2
+
1
3
  /**
2
4
  * Necessary to verify the signature of a request.
3
5
  */
@@ -37,7 +39,7 @@ declare class SignatureError extends Error {
37
39
  constructor(message: string);
38
40
  }
39
41
  /**
40
- * Receiver offers a simlpe way to verify the signature of a request.
42
+ * Receiver offers a simple way to verify the signature of a request.
41
43
  */
42
44
  declare class Receiver {
43
45
  private readonly currentSigningKey;
@@ -52,7 +54,7 @@ declare class Receiver {
52
54
  *
53
55
  * If that fails, the signature is invalid and a `SignatureError` is thrown.
54
56
  */
55
- verify(req: VerifyRequest): Promise<boolean>;
57
+ verify(request: VerifyRequest): Promise<boolean>;
56
58
  /**
57
59
  * Verify signature with a specific signing key
58
60
  */
@@ -92,9 +94,9 @@ type UpstashRequest = {
92
94
  type UpstashResponse<TResult> = TResult & {
93
95
  error?: string;
94
96
  };
95
- interface Requester {
96
- request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;
97
- }
97
+ type Requester = {
98
+ request: <TResult = unknown>(request: UpstashRequest) => Promise<UpstashResponse<TResult>>;
99
+ };
98
100
  type RetryConfig = false | {
99
101
  /**
100
102
  * The number of retries to attempt before giving up.
@@ -181,7 +183,7 @@ declare class DLQ {
181
183
  /**
182
184
  * List messages in the dlq
183
185
  */
184
- listMessages(opts?: {
186
+ listMessages(options?: {
185
187
  cursor?: string;
186
188
  }): Promise<{
187
189
  messages: DlqMessage[];
@@ -194,7 +196,7 @@ declare class DLQ {
194
196
  /**
195
197
  * Remove multiple messages from the dlq using their `dlqId`s
196
198
  */
197
- deleteMany(req: {
199
+ deleteMany(request: {
198
200
  dlqIds: string[];
199
201
  }): Promise<{
200
202
  deleted: number;
@@ -219,7 +221,7 @@ declare class Queue {
219
221
  /**
220
222
  * Create or update the queue
221
223
  */
222
- upsert(req: UpsertQueueRequest): Promise<void>;
224
+ upsert(request: UpsertQueueRequest): Promise<void>;
223
225
  /**
224
226
  * Get the queue details
225
227
  */
@@ -235,11 +237,11 @@ declare class Queue {
235
237
  /**
236
238
  * Enqueue a message to a queue.
237
239
  */
238
- enqueue(req: EnqueueRequest): Promise<PublishResponse<PublishRequest>>;
240
+ enqueue(request: EnqueueRequest): Promise<PublishResponse<PublishRequest>>;
239
241
  /**
240
242
  * Enqueue a message to a queue, serializing the body to JSON.
241
243
  */
242
- enqueueJSON<TBody = unknown>(req: PublishRequest<TBody>): Promise<PublishResponse<PublishRequest<TBody>>>;
244
+ enqueueJSON<TBody = unknown>(request: PublishRequest<TBody>): Promise<PublishResponse<PublishRequest<TBody>>>;
243
245
  }
244
246
 
245
247
  type Schedule = {
@@ -326,7 +328,7 @@ declare class Schedules {
326
328
  /**
327
329
  * Create a schedule
328
330
  */
329
- create(req: CreateScheduleRequest): Promise<{
331
+ create(request: CreateScheduleRequest): Promise<{
330
332
  scheduleId: string;
331
333
  }>;
332
334
  /**
@@ -391,11 +393,11 @@ declare class Topics {
391
393
  /**
392
394
  * Create a new topic with the given name and endpoints
393
395
  */
394
- addEndpoints(req: AddEndpointsRequest): Promise<void>;
396
+ addEndpoints(request: AddEndpointsRequest): Promise<void>;
395
397
  /**
396
398
  * Remove endpoints from a topic.
397
399
  */
398
- removeEndpoints(req: RemoveEndpointsRequest): Promise<void>;
400
+ removeEndpoints(request: RemoveEndpointsRequest): Promise<void>;
399
401
  /**
400
402
  * Get a list of all topics.
401
403
  */
@@ -612,21 +614,21 @@ declare class Client {
612
614
  *
613
615
  * Create, read, update or delete queues.
614
616
  */
615
- queue(req?: QueueRequest): Queue;
616
- publish<TRequest extends PublishRequest>(req: TRequest): Promise<PublishResponse<TRequest>>;
617
+ queue(request?: QueueRequest): Queue;
618
+ publish<TRequest extends PublishRequest>(request: TRequest): Promise<PublishResponse<TRequest>>;
617
619
  /**
618
620
  * publishJSON is a utility wrapper around `publish` that automatically serializes the body
619
621
  * and sets the `Content-Type` header to `application/json`.
620
622
  */
621
- publishJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(req: TRequest): Promise<PublishResponse<TRequest>>;
623
+ publishJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(request: TRequest): Promise<PublishResponse<TRequest>>;
622
624
  /**
623
625
  * Batch publish messages to QStash.
624
626
  */
625
- batch(req: PublishRequest[]): Promise<PublishResponse<PublishRequest>[]>;
627
+ batch(request: PublishRequest[]): Promise<PublishResponse<PublishRequest>[]>;
626
628
  /**
627
629
  * Batch publish messages to QStash, serializing each body to JSON.
628
630
  */
629
- batchJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(req: TRequest[]): Promise<PublishResponse<TRequest>[]>;
631
+ batchJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(request: TRequest[]): Promise<PublishResponse<TRequest>[]>;
630
632
  /**
631
633
  * Retrieve your logs.
632
634
  *
@@ -646,7 +648,7 @@ declare class Client {
646
648
  * }
647
649
  * ```
648
650
  */
649
- events(req?: EventsRequest): Promise<GetEventsResponse>;
651
+ events(request?: EventsRequest): Promise<GetEventsResponse>;
650
652
  }
651
653
  type PublishToUrlResponse = {
652
654
  messageId: string;
@@ -668,4 +670,4 @@ declare class QstashRatelimitError extends QstashError {
668
670
  constructor(args: unknown);
669
671
  }
670
672
 
671
- export { AddEndpointsRequest, Client, CreateScheduleRequest, Endpoint, Event, EventsRequest, GetEventsResponse, Message, Messages, PublishJsonRequest, PublishRequest, PublishResponse, PublishToTopicResponse, PublishToUrlResponse, QstashError, QstashRatelimitError, QueueRequest, Receiver, ReceiverConfig, RemoveEndpointsRequest, Schedule, Schedules, SignatureError, State, Topic, Topics, VerifyRequest, WithCursor };
673
+ export { type AddEndpointsRequest, Client, type CreateScheduleRequest, type Endpoint, type Event, type EventsRequest, type GetEventsResponse, type Message, Messages, type PublishJsonRequest, type PublishRequest, type PublishResponse, type PublishToTopicResponse, type PublishToUrlResponse, QstashError, QstashRatelimitError, type QueueRequest, Receiver, type ReceiverConfig, type RemoveEndpointsRequest, type Schedule, Schedules, SignatureError, type State, type Topic, Topics, type VerifyRequest, type WithCursor };