@upstash/qstash 2.1.11-canary → 2.2.0-canary

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.
@@ -109,4 +109,3 @@ var Receiver = class {
109
109
 
110
110
 
111
111
  exports.__spreadValues = __spreadValues; exports.__spreadProps = __spreadProps; exports.__async = __async; exports.__forAwait = __forAwait; exports.SignatureError = SignatureError; exports.Receiver = Receiver;
112
- //# sourceMappingURL=chunk-EQTYEU4U.js.map
@@ -109,4 +109,3 @@ export {
109
109
  SignatureError,
110
110
  Receiver
111
111
  };
112
- //# sourceMappingURL=chunk-G4FL5XMG.mjs.map
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- var _chunkEQTYEU4Ujs = require('./chunk-EQTYEU4U.js');
7
+ var _chunkEROSIHWEjs = require('./chunk-EROSIHWE.js');
8
8
 
9
9
  // src/client/dlq.ts
10
10
  var DLQ = class {
@@ -15,7 +15,7 @@ var DLQ = class {
15
15
  * List messages in the dlq
16
16
  */
17
17
  listMessages(opts) {
18
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
18
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
19
19
  return yield this.http.request({
20
20
  method: "GET",
21
21
  path: ["v2", "dlq"],
@@ -27,7 +27,7 @@ var DLQ = class {
27
27
  * Remove a message from the dlq using it's `dlqId`
28
28
  */
29
29
  delete(dlqMessageId) {
30
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
30
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
31
31
  return yield this.http.request({
32
32
  method: "DELETE",
33
33
  path: ["v2", "dlq", dlqMessageId],
@@ -70,7 +70,7 @@ var HttpClient = class {
70
70
  }
71
71
  }
72
72
  request(req) {
73
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
73
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
74
74
  var _a;
75
75
  const headers = new Headers(req.headers);
76
76
  headers.set("Authorization", this.authorization);
@@ -131,7 +131,7 @@ var Messages = class {
131
131
  * Get a message
132
132
  */
133
133
  get(messageId) {
134
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
134
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
135
135
  return yield this.http.request({
136
136
  method: "GET",
137
137
  path: ["v2", "messages", messageId]
@@ -142,7 +142,7 @@ var Messages = class {
142
142
  * Cancel a message
143
143
  */
144
144
  delete(messageId) {
145
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
145
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
146
146
  return yield this.http.request({
147
147
  method: "DELETE",
148
148
  path: ["v2", "messages", messageId],
@@ -161,7 +161,7 @@ var Schedules = class {
161
161
  * Create a schedule
162
162
  */
163
163
  create(req) {
164
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
164
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
165
165
  const headers = new Headers(req.headers);
166
166
  if (!headers.has("Content-Type")) {
167
167
  headers.set("Content-Type", "application/json");
@@ -194,7 +194,7 @@ var Schedules = class {
194
194
  * Get a schedule
195
195
  */
196
196
  get(scheduleId) {
197
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
197
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
198
198
  return yield this.http.request({
199
199
  method: "GET",
200
200
  path: ["v2", "schedules", scheduleId]
@@ -205,7 +205,7 @@ var Schedules = class {
205
205
  * List your schedules
206
206
  */
207
207
  list() {
208
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
208
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
209
209
  return yield this.http.request({
210
210
  method: "GET",
211
211
  path: ["v2", "schedules"]
@@ -216,7 +216,7 @@ var Schedules = class {
216
216
  * Delete a schedule
217
217
  */
218
218
  delete(scheduleId) {
219
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
219
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
220
220
  return yield this.http.request({
221
221
  method: "DELETE",
222
222
  path: ["v2", "schedules", scheduleId],
@@ -235,7 +235,7 @@ var Topics = class {
235
235
  * Create a new topic with the given name and endpoints
236
236
  */
237
237
  addEndpoints(req) {
238
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
238
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
239
239
  yield this.http.request({
240
240
  method: "POST",
241
241
  path: ["v2", "topics", req.name, "endpoints"],
@@ -249,7 +249,7 @@ var Topics = class {
249
249
  * Remove endpoints from a topic.
250
250
  */
251
251
  removeEndpoints(req) {
252
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
252
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
253
253
  yield this.http.request({
254
254
  method: "DELETE",
255
255
  path: ["v2", "topics", req.name, "endpoints"],
@@ -263,7 +263,7 @@ var Topics = class {
263
263
  * Get a list of all topics.
264
264
  */
265
265
  list() {
266
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
266
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
267
267
  return yield this.http.request({
268
268
  method: "GET",
269
269
  path: ["v2", "topics"]
@@ -274,7 +274,7 @@ var Topics = class {
274
274
  * Get a single topic
275
275
  */
276
276
  get(name) {
277
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
277
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
278
278
  return yield this.http.request({
279
279
  method: "GET",
280
280
  path: ["v2", "topics", name]
@@ -285,7 +285,7 @@ var Topics = class {
285
285
  * Delete a topic
286
286
  */
287
287
  delete(name) {
288
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
288
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
289
289
  return yield this.http.request({
290
290
  method: "DELETE",
291
291
  path: ["v2", "topics", name],
@@ -337,7 +337,7 @@ var Client = class {
337
337
  return new Schedules(this.http);
338
338
  }
339
339
  publish(req) {
340
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
340
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
341
341
  var _a, _b;
342
342
  const headers = new Headers(req.headers);
343
343
  headers.set("Upstash-Method", (_a = req.method) != null ? _a : "POST");
@@ -376,10 +376,10 @@ var Client = class {
376
376
  * and sets the `Content-Type` header to `application/json`.
377
377
  */
378
378
  publishJSON(req) {
379
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
379
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
380
380
  const headers = new Headers(req.headers);
381
381
  headers.set("Content-Type", "application/json");
382
- const res = yield this.publish(_chunkEQTYEU4Ujs.__spreadProps.call(void 0, _chunkEQTYEU4Ujs.__spreadValues.call(void 0, {}, req), {
382
+ const res = yield this.publish(_chunkEROSIHWEjs.__spreadProps.call(void 0, _chunkEROSIHWEjs.__spreadValues.call(void 0, {}, req), {
383
383
  headers,
384
384
  body: JSON.stringify(req.body)
385
385
  }));
@@ -406,7 +406,7 @@ var Client = class {
406
406
  * ```
407
407
  */
408
408
  events(req) {
409
- return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
409
+ return _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
410
410
  const query = {};
411
411
  if ((req == null ? void 0 : req.cursor) && req.cursor > 0) {
412
412
  query.cursor = req.cursor;
@@ -429,5 +429,4 @@ var Client = class {
429
429
 
430
430
 
431
431
 
432
- exports.Client = Client; exports.Messages = Messages; exports.QstashError = QstashError; exports.QstashRatelimitError = QstashRatelimitError; exports.Receiver = _chunkEQTYEU4Ujs.Receiver; exports.Schedules = Schedules; exports.SignatureError = _chunkEQTYEU4Ujs.SignatureError; exports.Topics = Topics;
433
- //# sourceMappingURL=index.js.map
432
+ exports.Client = Client; exports.Messages = Messages; exports.QstashError = QstashError; exports.QstashRatelimitError = QstashRatelimitError; exports.Receiver = _chunkEROSIHWEjs.Receiver; exports.Schedules = Schedules; exports.SignatureError = _chunkEROSIHWEjs.SignatureError; exports.Topics = Topics;
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  __async,
5
5
  __spreadProps,
6
6
  __spreadValues
7
- } from "./chunk-G4FL5XMG.mjs";
7
+ } from "./chunk-FK4ORXI6.mjs";
8
8
 
9
9
  // src/client/dlq.ts
10
10
  var DLQ = class {
@@ -430,4 +430,3 @@ export {
430
430
  SignatureError,
431
431
  Topics
432
432
  };
433
- //# sourceMappingURL=index.mjs.map
package/dist/nextjs.d.mts CHANGED
@@ -19,5 +19,7 @@ type VerifySignatureConfig = {
19
19
  };
20
20
  declare function verifySignature(handler: NextApiHandler, config?: VerifySignatureConfig): NextApiHandler;
21
21
  declare function verifySignatureEdge(handler: (req: NextRequest, nfe?: NextFetchEvent) => NextResponse | Promise<NextResponse>, config?: VerifySignatureConfig): (req: NextRequest, nfe: NextFetchEvent) => Promise<NextResponse<unknown>>;
22
+ type VerifySignatureAppRouterResponse = NextResponse | Promise<NextResponse>;
23
+ declare function verifySignatureAppRouter(handler: ((req: Request) => VerifySignatureAppRouterResponse) | ((req: NextRequest) => VerifySignatureAppRouterResponse), config?: VerifySignatureConfig): (req: NextRequest | Request) => Promise<NextResponse<unknown>>;
22
24
 
23
- export { VerifySignatureConfig, verifySignature, verifySignatureEdge };
25
+ export { VerifySignatureConfig, verifySignature, verifySignatureAppRouter, verifySignatureEdge };
package/dist/nextjs.d.ts CHANGED
@@ -19,5 +19,7 @@ type VerifySignatureConfig = {
19
19
  };
20
20
  declare function verifySignature(handler: NextApiHandler, config?: VerifySignatureConfig): NextApiHandler;
21
21
  declare function verifySignatureEdge(handler: (req: NextRequest, nfe?: NextFetchEvent) => NextResponse | Promise<NextResponse>, config?: VerifySignatureConfig): (req: NextRequest, nfe: NextFetchEvent) => Promise<NextResponse<unknown>>;
22
+ type VerifySignatureAppRouterResponse = NextResponse | Promise<NextResponse>;
23
+ declare function verifySignatureAppRouter(handler: ((req: Request) => VerifySignatureAppRouterResponse) | ((req: NextRequest) => VerifySignatureAppRouterResponse), config?: VerifySignatureConfig): (req: NextRequest | Request) => Promise<NextResponse<unknown>>;
22
24
 
23
- export { VerifySignatureConfig, verifySignature, verifySignatureEdge };
25
+ export { VerifySignatureConfig, verifySignature, verifySignatureAppRouter, verifySignatureEdge };
package/dist/nextjs.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkEQTYEU4Ujs = require('./chunk-EQTYEU4U.js');
5
+ var _chunkEROSIHWEjs = require('./chunk-EROSIHWE.js');
6
6
 
7
7
  // src/nextjs.ts
8
8
  var _server = require('next/server');
@@ -20,11 +20,11 @@ function verifySignature(handler, config) {
20
20
  "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY"
21
21
  );
22
22
  }
23
- const receiver = new (0, _chunkEQTYEU4Ujs.Receiver)({
23
+ const receiver = new (0, _chunkEROSIHWEjs.Receiver)({
24
24
  currentSigningKey,
25
25
  nextSigningKey
26
26
  });
27
- return (req, res) => _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
27
+ return (req, res) => _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
28
28
  const signature = req.headers["upstash-signature"];
29
29
  if (!signature) {
30
30
  res.status(400);
@@ -37,7 +37,7 @@ function verifySignature(handler, config) {
37
37
  }
38
38
  const chunks = [];
39
39
  try {
40
- for (var iter = _chunkEQTYEU4Ujs.__forAwait.call(void 0, req), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
40
+ for (var iter = _chunkEROSIHWEjs.__forAwait.call(void 0, req), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
41
41
  const chunk = temp.value;
42
42
  chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
43
43
  }
@@ -89,11 +89,11 @@ function verifySignatureEdge(handler, config) {
89
89
  "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY"
90
90
  );
91
91
  }
92
- const receiver = new (0, _chunkEQTYEU4Ujs.Receiver)({
92
+ const receiver = new (0, _chunkEROSIHWEjs.Receiver)({
93
93
  currentSigningKey,
94
94
  nextSigningKey
95
95
  });
96
- return (req, nfe) => _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
96
+ return (req, nfe) => _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
97
97
  const reqClone = req.clone();
98
98
  const signature = req.headers.get("upstash-signature");
99
99
  if (!signature) {
@@ -113,21 +113,52 @@ function verifySignatureEdge(handler, config) {
113
113
  if (!isValid) {
114
114
  return new (0, _server.NextResponse)(new TextEncoder().encode("invalid signature"), { status: 403 });
115
115
  }
116
- let parsedBody = void 0;
117
- try {
118
- if (req.headers.get("content-type") === "application/json") {
119
- parsedBody = JSON.parse(body);
120
- } else {
121
- parsedBody = body;
122
- }
123
- } catch (e) {
124
- parsedBody = body;
125
- }
126
116
  return handler(reqClone, nfe);
127
117
  });
128
118
  }
119
+ function verifySignatureAppRouter(handler, config) {
120
+ var _a, _b;
121
+ const currentSigningKey = (_a = config == null ? void 0 : config.currentSigningKey) != null ? _a : process.env.QSTASH_CURRENT_SIGNING_KEY;
122
+ if (!currentSigningKey) {
123
+ throw new Error(
124
+ "currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY"
125
+ );
126
+ }
127
+ const nextSigningKey = (_b = config == null ? void 0 : config.nextSigningKey) != null ? _b : process.env.QSTASH_NEXT_SIGNING_KEY;
128
+ if (!nextSigningKey) {
129
+ throw new Error(
130
+ "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY"
131
+ );
132
+ }
133
+ const receiver = new (0, _chunkEROSIHWEjs.Receiver)({
134
+ currentSigningKey,
135
+ nextSigningKey
136
+ });
137
+ return (req) => _chunkEROSIHWEjs.__async.call(void 0, this, null, function* () {
138
+ const reqClone = req.clone();
139
+ const signature = req.headers.get("upstash-signature");
140
+ if (!signature) {
141
+ return new (0, _server.NextResponse)(new TextEncoder().encode("`Upstash-Signature` header is missing"), {
142
+ status: 403
143
+ });
144
+ }
145
+ if (typeof signature !== "string") {
146
+ throw new Error("`Upstash-Signature` header is not a string");
147
+ }
148
+ const body = yield req.text();
149
+ const isValid = yield receiver.verify({
150
+ signature,
151
+ body,
152
+ clockTolerance: config == null ? void 0 : config.clockTolerance
153
+ });
154
+ if (!isValid) {
155
+ return new (0, _server.NextResponse)(new TextEncoder().encode("invalid signature"), { status: 403 });
156
+ }
157
+ return handler(reqClone);
158
+ });
159
+ }
160
+
129
161
 
130
162
 
131
163
 
132
- exports.verifySignature = verifySignature; exports.verifySignatureEdge = verifySignatureEdge;
133
- //# sourceMappingURL=nextjs.js.map
164
+ exports.verifySignature = verifySignature; exports.verifySignatureAppRouter = verifySignatureAppRouter; exports.verifySignatureEdge = verifySignatureEdge;
package/dist/nextjs.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  Receiver,
3
3
  __async,
4
4
  __forAwait
5
- } from "./chunk-G4FL5XMG.mjs";
5
+ } from "./chunk-FK4ORXI6.mjs";
6
6
 
7
7
  // src/nextjs.ts
8
8
  import { NextResponse } from "next/server";
@@ -113,21 +113,52 @@ function verifySignatureEdge(handler, config) {
113
113
  if (!isValid) {
114
114
  return new NextResponse(new TextEncoder().encode("invalid signature"), { status: 403 });
115
115
  }
116
- let parsedBody = void 0;
117
- try {
118
- if (req.headers.get("content-type") === "application/json") {
119
- parsedBody = JSON.parse(body);
120
- } else {
121
- parsedBody = body;
122
- }
123
- } catch (e) {
124
- parsedBody = body;
125
- }
126
116
  return handler(reqClone, nfe);
127
117
  });
128
118
  }
119
+ function verifySignatureAppRouter(handler, config) {
120
+ var _a, _b;
121
+ const currentSigningKey = (_a = config == null ? void 0 : config.currentSigningKey) != null ? _a : process.env.QSTASH_CURRENT_SIGNING_KEY;
122
+ if (!currentSigningKey) {
123
+ throw new Error(
124
+ "currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY"
125
+ );
126
+ }
127
+ const nextSigningKey = (_b = config == null ? void 0 : config.nextSigningKey) != null ? _b : process.env.QSTASH_NEXT_SIGNING_KEY;
128
+ if (!nextSigningKey) {
129
+ throw new Error(
130
+ "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY"
131
+ );
132
+ }
133
+ const receiver = new Receiver({
134
+ currentSigningKey,
135
+ nextSigningKey
136
+ });
137
+ return (req) => __async(this, null, function* () {
138
+ const reqClone = req.clone();
139
+ const signature = req.headers.get("upstash-signature");
140
+ if (!signature) {
141
+ return new NextResponse(new TextEncoder().encode("`Upstash-Signature` header is missing"), {
142
+ status: 403
143
+ });
144
+ }
145
+ if (typeof signature !== "string") {
146
+ throw new Error("`Upstash-Signature` header is not a string");
147
+ }
148
+ const body = yield req.text();
149
+ const isValid = yield receiver.verify({
150
+ signature,
151
+ body,
152
+ clockTolerance: config == null ? void 0 : config.clockTolerance
153
+ });
154
+ if (!isValid) {
155
+ return new NextResponse(new TextEncoder().encode("invalid signature"), { status: 403 });
156
+ }
157
+ return handler(reqClone);
158
+ });
159
+ }
129
160
  export {
130
161
  verifySignature,
162
+ verifySignatureAppRouter,
131
163
  verifySignatureEdge
132
164
  };
133
- //# sourceMappingURL=nextjs.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upstash/qstash",
3
- "version": "v2.1.11-canary",
3
+ "version": "v2.2.0-canary",
4
4
  "description": "Official Typescript client for QStash",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,15 +26,15 @@
26
26
  "dist"
27
27
  ],
28
28
  "devDependencies": {
29
- "@types/crypto-js": "^4.1.1",
29
+ "@biomejs/biome": "^1.3.3",
30
+ "@types/crypto-js": "^4.2.0",
30
31
  "@types/node": "^20.5.7",
31
- "next": "^13.4.19",
32
- "rome": "12.1.3",
32
+ "next": "^14.0.2",
33
33
  "tsup": "^7.2.0",
34
34
  "typescript": "^5.2.2"
35
35
  },
36
36
  "dependencies": {
37
- "crypto-js": "^4.1.1",
37
+ "crypto-js": "^4.2.0",
38
38
  "jose": "^4.14.4"
39
39
  },
40
40
  "typesVersions": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/receiver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,YAAY,UAAU;AACtB,YAAY,YAAY;AA0CjB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAIO,IAAM,WAAN,MAAe;AAAA,EAIpB,YAAY,QAAwB;AAClC,SAAK,oBAAoB,OAAO;AAChC,SAAK,iBAAiB,OAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWa,OAAO,KAAsC;AAAA;AACxD,YAAM,UAAU,MAAM,KAAK,cAAc,KAAK,mBAAmB,GAAG;AACpE,UAAI,SAAS;AACX,eAAO;AAAA,MACT;AACA,aAAO,KAAK,cAAc,KAAK,gBAAgB,GAAG;AAAA,IACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKc,cAAc,KAAa,KAAsC;AAAA;AAC7E,YAAM,MAAM,MACT,eAAU,IAAI,WAAW,IAAI,YAAY,EAAE,OAAO,GAAG,GAAG;AAAA,QACvD,QAAQ;AAAA,QACR,gBAAgB,IAAI;AAAA,MACtB,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,cAAM,IAAI,eAAgB,EAAY,OAAO;AAAA,MAC/C,CAAC;AAEH,YAAM,IAAI,IAAI;AAUd,UAAI,OAAO,IAAI,QAAQ,eAAe,EAAE,QAAQ,IAAI,KAAK;AACvD,cAAM,IAAI,eAAe,oBAAoB,EAAE,GAAG,WAAW,IAAI,GAAG,EAAE;AAAA,MACxE;AAEA,YAAM,WAAkB,cAAO,IAAI,IAAc,EAAE,SAAgB,WAAI,SAAS;AAEhF,YAAM,UAAU,IAAI,OAAO,KAAK;AAEhC,UAAI,EAAE,KAAK,QAAQ,SAAS,EAAE,MAAM,SAAS,QAAQ,SAAS,EAAE,GAAG;AACjE,cAAM,IAAI,eAAe,mCAAmC,EAAE,IAAI,UAAU,QAAQ,EAAE;AAAA,MACxF;AAEA,aAAO;AAAA,IACT;AAAA;AACF","sourcesContent":["import * as jose from \"jose\";\nimport * as crypto from \"crypto-js\";\n\n/**\n * Necessary to verify the signature of a request.\n */\nexport type ReceiverConfig = {\n /**\n * The current signing key. Get it from `https://console.upstash.com/qstash\n */\n currentSigningKey: string;\n /**\n * The next signing key. Get it from `https://console.upstash.com/qstash\n */\n nextSigningKey: string;\n};\n\nexport type VerifyRequest = {\n /**\n * The signature from the `upstash-signature` header.\n */\n signature: string;\n\n /**\n * The raw request body.\n */\n body: string;\n\n /**\n * URL of the endpoint where the request was sent to.\n *\n * Omit empty to disable checking the url.\n */\n url?: string;\n\n /**\n * Number of seconds to tolerate when checking `nbf` and `exp` claims, to deal with small clock differences among different servers\n *\n * @default 0\n */\n clockTolerance?: number;\n};\n\nexport class SignatureError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SignatureError\";\n }\n}\n/**\n * Receiver offers a simlpe way to verify the signature of a request.\n */\nexport class Receiver {\n private readonly currentSigningKey: string;\n private readonly nextSigningKey: string;\n\n constructor(config: ReceiverConfig) {\n this.currentSigningKey = config.currentSigningKey;\n this.nextSigningKey = config.nextSigningKey;\n }\n\n /**\n * Verify the signature of a request.\n *\n * Tries to verify the signature with the current signing key.\n * If that fails, maybe because you have rotated the keys recently, it will\n * try to verify the signature with the next signing key.\n *\n * If that fails, the signature is invalid and a `SignatureError` is thrown.\n */\n public async verify(req: VerifyRequest): Promise<boolean> {\n const isValid = await this.verifyWithKey(this.currentSigningKey, req);\n if (isValid) {\n return true;\n }\n return this.verifyWithKey(this.nextSigningKey, req);\n }\n\n /**\n * Verify signature with a specific signing key\n */\n private async verifyWithKey(key: string, req: VerifyRequest): Promise<boolean> {\n const jwt = await jose\n .jwtVerify(req.signature, new TextEncoder().encode(key), {\n issuer: \"Upstash\",\n clockTolerance: req.clockTolerance,\n })\n .catch((e) => {\n throw new SignatureError((e as Error).message);\n });\n\n const p = jwt.payload as {\n iss: string;\n sub: string;\n exp: number;\n nbf: number;\n iat: number;\n jti: string;\n body: string;\n };\n\n if (typeof req.url !== \"undefined\" && p.sub !== req.url) {\n throw new SignatureError(`invalid subject: ${p.sub}, want: ${req.url}`);\n }\n\n const bodyHash = crypto.SHA256(req.body as string).toString(crypto.enc.Base64url);\n\n const padding = new RegExp(/=+$/);\n\n if (p.body.replace(padding, \"\") !== bodyHash.replace(padding, \"\")) {\n throw new SignatureError(`body hash does not match, want: ${p.body}, got: ${bodyHash}`);\n }\n\n return true;\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/receiver.ts"],"sourcesContent":["import * as jose from \"jose\";\nimport * as crypto from \"crypto-js\";\n\n/**\n * Necessary to verify the signature of a request.\n */\nexport type ReceiverConfig = {\n /**\n * The current signing key. Get it from `https://console.upstash.com/qstash\n */\n currentSigningKey: string;\n /**\n * The next signing key. Get it from `https://console.upstash.com/qstash\n */\n nextSigningKey: string;\n};\n\nexport type VerifyRequest = {\n /**\n * The signature from the `upstash-signature` header.\n */\n signature: string;\n\n /**\n * The raw request body.\n */\n body: string;\n\n /**\n * URL of the endpoint where the request was sent to.\n *\n * Omit empty to disable checking the url.\n */\n url?: string;\n\n /**\n * Number of seconds to tolerate when checking `nbf` and `exp` claims, to deal with small clock differences among different servers\n *\n * @default 0\n */\n clockTolerance?: number;\n};\n\nexport class SignatureError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SignatureError\";\n }\n}\n/**\n * Receiver offers a simlpe way to verify the signature of a request.\n */\nexport class Receiver {\n private readonly currentSigningKey: string;\n private readonly nextSigningKey: string;\n\n constructor(config: ReceiverConfig) {\n this.currentSigningKey = config.currentSigningKey;\n this.nextSigningKey = config.nextSigningKey;\n }\n\n /**\n * Verify the signature of a request.\n *\n * Tries to verify the signature with the current signing key.\n * If that fails, maybe because you have rotated the keys recently, it will\n * try to verify the signature with the next signing key.\n *\n * If that fails, the signature is invalid and a `SignatureError` is thrown.\n */\n public async verify(req: VerifyRequest): Promise<boolean> {\n const isValid = await this.verifyWithKey(this.currentSigningKey, req);\n if (isValid) {\n return true;\n }\n return this.verifyWithKey(this.nextSigningKey, req);\n }\n\n /**\n * Verify signature with a specific signing key\n */\n private async verifyWithKey(key: string, req: VerifyRequest): Promise<boolean> {\n const jwt = await jose\n .jwtVerify(req.signature, new TextEncoder().encode(key), {\n issuer: \"Upstash\",\n clockTolerance: req.clockTolerance,\n })\n .catch((e) => {\n throw new SignatureError((e as Error).message);\n });\n\n const p = jwt.payload as {\n iss: string;\n sub: string;\n exp: number;\n nbf: number;\n iat: number;\n jti: string;\n body: string;\n };\n\n if (typeof req.url !== \"undefined\" && p.sub !== req.url) {\n throw new SignatureError(`invalid subject: ${p.sub}, want: ${req.url}`);\n }\n\n const bodyHash = crypto.SHA256(req.body as string).toString(crypto.enc.Base64url);\n\n const padding = new RegExp(/=+$/);\n\n if (p.body.replace(padding, \"\") !== bodyHash.replace(padding, \"\")) {\n throw new SignatureError(`body hash does not match, want: ${p.body}, got: ${bodyHash}`);\n }\n\n return true;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,YAAY,UAAU;AACtB,YAAY,YAAY;AA0CjB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAIO,IAAM,WAAN,MAAe;AAAA,EAIpB,YAAY,QAAwB;AAClC,SAAK,oBAAoB,OAAO;AAChC,SAAK,iBAAiB,OAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWa,OAAO,KAAsC;AAAA;AACxD,YAAM,UAAU,MAAM,KAAK,cAAc,KAAK,mBAAmB,GAAG;AACpE,UAAI,SAAS;AACX,eAAO;AAAA,MACT;AACA,aAAO,KAAK,cAAc,KAAK,gBAAgB,GAAG;AAAA,IACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKc,cAAc,KAAa,KAAsC;AAAA;AAC7E,YAAM,MAAM,MACT,eAAU,IAAI,WAAW,IAAI,YAAY,EAAE,OAAO,GAAG,GAAG;AAAA,QACvD,QAAQ;AAAA,QACR,gBAAgB,IAAI;AAAA,MACtB,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,cAAM,IAAI,eAAgB,EAAY,OAAO;AAAA,MAC/C,CAAC;AAEH,YAAM,IAAI,IAAI;AAUd,UAAI,OAAO,IAAI,QAAQ,eAAe,EAAE,QAAQ,IAAI,KAAK;AACvD,cAAM,IAAI,eAAe,oBAAoB,EAAE,GAAG,WAAW,IAAI,GAAG,EAAE;AAAA,MACxE;AAEA,YAAM,WAAkB,cAAO,IAAI,IAAc,EAAE,SAAgB,WAAI,SAAS;AAEhF,YAAM,UAAU,IAAI,OAAO,KAAK;AAEhC,UAAI,EAAE,KAAK,QAAQ,SAAS,EAAE,MAAM,SAAS,QAAQ,SAAS,EAAE,GAAG;AACjE,cAAM,IAAI,eAAe,mCAAmC,EAAE,IAAI,UAAU,QAAQ,EAAE;AAAA,MACxF;AAEA,aAAO;AAAA,IACT;AAAA;AACF;","names":[]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client/dlq.ts","../src/client/error.ts","../src/client/http.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/topics.ts","../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { Requester } from \"./http\";\nimport type { Message } from \"./messages\";\n\ntype DlqMessage = Message & {\n dlqId: string;\n};\n\nexport class DLQ {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * List messages in the dlq\n */\n public async listMessages(opts?: { cursor?: string }): Promise<{\n messages: DlqMessage[];\n cursor?: string;\n }> {\n return await this.http.request({\n method: \"GET\",\n path: [\"v2\", \"dlq\"],\n query: { cursor: opts?.cursor },\n });\n }\n\n /**\n * Remove a message from the dlq using it's `dlqId`\n */\n public async delete(dlqMessageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"dlq\", dlqMessageId],\n parseResponseAsJson: false, // there is no response\n });\n }\n}\n","/**\n * Result of 500 Internal Server Error\n */\nexport class QstashError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"QstashError\";\n }\n}\n\nexport class QstashRatelimitError extends QstashError {\n constructor(args: unknown) {\n super(`You have been ratelimited. ${JSON.stringify(args)} `);\n }\n}\n","import { QstashError, QstashRatelimitError } from \"./error\";\n\nexport type UpstashRequest = {\n /**\n * The path to the resource.\n */\n path: string[];\n\n /**\n * A BodyInit object or null to set request's body.\n */\n body?: BodyInit | null;\n\n /**\n * A Headers object, an object literal, or an array of two-item arrays to set\n * request's headers.\n */\n headers?: HeadersInit;\n\n /**\n * A boolean to set request's keepalive.\n */\n keepalive?: boolean;\n\n /**\n * A string to set request's method.\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\n query?: Record<string, string | number | boolean | undefined>;\n\n /**\n * if enabled, call `res.json()`\n *\n * @default true\n */\n parseResponseAsJson?: boolean;\n};\nexport type UpstashResponse<TResult> = TResult & { error?: string };\n\nexport interface Requester {\n request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;\n}\n\nexport type RetryConfig =\n | false\n | {\n /**\n * The number of retries to attempt before giving up.\n *\n * @default 5\n */\n retries?: number;\n /**\n * A backoff function receives the current retry cound and returns a number in milliseconds to wait before retrying.\n *\n * @default\n * ```ts\n * Math.exp(retryCount) * 50\n * ```\n */\n backoff?: (retryCount: number) => number;\n };\n\nexport type HttpClientConfig = {\n baseUrl: string;\n authorization: string;\n retry?: RetryConfig;\n};\n\nexport class HttpClient implements Requester {\n public readonly baseUrl: string;\n\n public readonly authorization: string;\n\n public readonly options?: { backend?: string };\n\n public retry: {\n attempts: number;\n backoff: (retryCount: number) => number;\n };\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n this.authorization = config.authorization;\n\n if (typeof config?.retry === \"boolean\" && config?.retry === false) {\n this.retry = {\n attempts: 1,\n backoff: () => 0,\n };\n } else {\n this.retry = {\n attempts: config.retry?.retries ? config.retry.retries + 1 : 5,\n backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n };\n }\n }\n\n public async request<TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> {\n const headers = new Headers(req.headers);\n headers.set(\"Authorization\", this.authorization);\n\n const requestOptions: RequestInit & { backend?: string } = {\n method: req.method,\n headers,\n body: req.body,\n keepalive: req.keepalive,\n };\n\n const url = new URL([this.baseUrl, ...(req.path ?? [])].join(\"/\"));\n if (req.query) {\n for (const [key, value] of Object.entries(req.query)) {\n if (typeof value !== \"undefined\") {\n url.searchParams.set(key, value.toString());\n }\n }\n }\n\n let res: Response | null = null;\n let error: Error | null = null;\n for (let i = 0; i < this.retry.attempts; i++) {\n try {\n res = await fetch(url.toString(), requestOptions);\n break;\n } catch (err) {\n error = err as Error;\n await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n }\n }\n if (!res) {\n throw error ?? new Error(\"Exhausted all retries\");\n }\n if (res.status === 429) {\n throw new QstashRatelimitError({\n limit: res.headers.get(\"Burst-RateLimit-Limit\"),\n remaining: res.headers.get(\"Burst-RateLimit-Remaining\"),\n reset: res.headers.get(\"Burst-RateLimit-Reset\"),\n });\n }\n\n if (res.status < 200 || res.status >= 300) {\n const body = await res.text();\n throw new QstashError(body.length > 0 ? body : `Error: status=${res.status}`);\n }\n if (req.parseResponseAsJson === false) {\n return undefined as unknown as UpstashResponse<TResult>;\n } else {\n return (await res.json()) as UpstashResponse<TResult>;\n }\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Message = {\n /**\n * A unique identifier for this message.\n */\n messageId: string;\n\n /**\n * The topic name if this message was sent to a topic.\n */\n topicName?: string;\n\n /**\n * The url where this message is sent to.\n */\n url: string;\n\n /**\n * The http method used to deliver the message\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The http headers sent along with the message to your API.\n */\n header?: Record<string, string[]>;\n\n /**\n * The http body sent to your API\n */\n body?: string;\n\n /**\n * Maxmimum number of retries.\n */\n maxRetries?: number;\n\n /**\n * A unix timestamp (milliseconds) after which this message may get delivered.\n */\n notBefore?: number;\n\n /**\n * A unix timestamp (milliseconds) when this messages was created.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: string;\n\n /**\n * The failure callback url if configured.\n */\n failureCallback?: string;\n};\n\nexport class Messages {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Get a message\n */\n public async get(messageId: string): Promise<Message> {\n return await this.http.request<Message>({\n method: \"GET\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n\n /**\n * Cancel a message\n */\n public async delete(messageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"messages\", messageId],\n parseResponseAsJson: false,\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Schedule = {\n scheduleId: string;\n cron: string;\n createdAt: number;\n destination: string;\n method: string;\n header?: Record<string, string[]>;\n body?: string;\n retries: number;\n delay?: number;\n callback?: string;\n failureCallback?: string;\n};\n\nexport type CreateScheduleRequest = {\n /**\n * Either a URL or topic name\n */\n destination: string;\n\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * In case your destination server is unavailable or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * Use a failure callback url to handle messages that could not be delivered.\n *\n * The failure callback url must be publicly accessible\n *\n * @default undefined\n */\n failureCallback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * Specify a cron expression to repeatedly send this message to the destination.\n */\n cron: string;\n};\n\nexport class Schedules {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a schedule\n */\n public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {\n const headers = new Headers(req.headers);\n\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n headers.set(\"Upstash-Cron\", req.cron);\n\n if (typeof req.method !== \"undefined\") {\n headers.set(\"Upstash-Method\", req.method);\n }\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n if (typeof req.failureCallback !== \"undefined\") {\n headers.set(\"Upstash-Failure-Callback\", req.failureCallback);\n }\n\n return await this.http.request({\n method: \"POST\",\n headers,\n path: [\"v2\", \"schedules\", req.destination],\n body: req.body,\n });\n }\n\n /**\n * Get a schedule\n */\n public async get(scheduleId: string): Promise<Schedule> {\n return await this.http.request<Schedule>({\n method: \"GET\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n\n /**\n * List your schedules\n */\n public async list(): Promise<Schedule[]> {\n return await this.http.request<Schedule[]>({\n method: \"GET\",\n path: [\"v2\", \"schedules\"],\n });\n }\n\n /**\n * Delete a schedule\n */\n public async delete(scheduleId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"schedules\", scheduleId],\n parseResponseAsJson: false,\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Endpoint = {\n /**\n * The name of the endpoint (optional)\n */\n name?: string;\n\n /**\n * The url of the endpoint\n */\n url: string;\n};\n\nexport type AddEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: Endpoint[];\n};\n\nexport type RemoveEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: (\n | {\n name: string;\n url?: string;\n }\n | {\n name?: string;\n url: string;\n }\n )[];\n};\n\nexport type Topic = {\n /**\n * The name of this topic.\n */\n name: string;\n\n /**\n * A list of all subscribed endpoints\n */\n endpoints: Endpoint[];\n};\n\nexport class Topics {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a new topic with the given name and endpoints\n */\n public async addEndpoints(req: AddEndpointsRequest): Promise<void> {\n await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name, \"endpoints\"],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n parseResponseAsJson: false,\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<void> {\n await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name, \"endpoints\"],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n parseResponseAsJson: false,\n });\n }\n\n /**\n * Get a list of all topics.\n */\n public async list(): Promise<Topic[]> {\n return await this.http.request<Topic[]>({\n method: \"GET\",\n path: [\"v2\", \"topics\"],\n });\n }\n\n /**\n * Get a single topic\n */\n public async get(name: string): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"GET\",\n path: [\"v2\", \"topics\", name],\n });\n }\n\n /**\n * Delete a topic\n */\n public async delete(name: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", name],\n parseResponseAsJson: false,\n });\n }\n}\n","import { DLQ } from \"./dlq\";\nimport { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Topics } from \"./topics\";\nimport { Event } from \"./types\";\ntype ClientConfig = {\n /**\n * Url of the qstash api server.\n *\n * This is only used for testing.\n *\n * @default \"https://qstash.upstash.io\"\n */\n baseUrl?: string;\n\n /**\n * The authorization token from the upstash console.\n */\n token: string;\n\n /**\n * Configure how the client should retry requests.\n */\n retry?: RetryConfig;\n};\n\nexport type PublishRequest<TBody = BodyInit> = {\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: TBody;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * Optionally set the absolute delay of this message.\n * This will override the delay option.\n * The message will not delivered until the specified time.\n *\n * Unix timestamp in seconds.\n *\n * @default undefined\n */\n notBefore?: number;\n\n /**\n * Provide a unique id for deduplication. This id will be used to detect duplicate messages.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default undefined\n */\n deduplicationId?: string;\n\n /**\n * If true, the message content will get hashed and used as deduplication id.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * The content based hash includes the following values:\n * - All headers, except Upstash-Authorization, this includes all headers you are sending.\n * - The entire raw request body The destination from the url path\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default false\n */\n contentBasedDeduplication?: boolean;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * Use a failure callback url to handle messages that could not be delivered.\n *\n * The failure callback url must be publicly accessible\n *\n * @default undefined\n */\n failureCallback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n} & (\n | {\n /**\n * The url where the message should be sent to.\n */\n url: string;\n topic?: never;\n }\n | {\n url?: never;\n /**\n * The url where the message should be sent to.\n */\n topic: string;\n }\n);\n\nexport type PublishJsonRequest = Omit<PublishRequest, \"body\"> & {\n /**\n * The message to send.\n * This can be anything as long as it can be serialized to JSON.\n */\n body: unknown;\n};\n\nexport type EventsRequest = {\n cursor?: number;\n};\n\nexport type GetEventsResponse = {\n cursor?: number;\n events: Event[];\n};\n\nexport class Client {\n public http: Requester;\n\n public constructor(config: ClientConfig) {\n this.http = new HttpClient({\n retry: config.retry,\n baseUrl: config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"https://qstash.upstash.io\",\n authorization: `Bearer ${config.token}`,\n });\n }\n\n /**\n * Access the topic API.\n *\n * Create, read, update or delete topics.\n */\n public get topics(): Topics {\n return new Topics(this.http);\n }\n\n /**\n * Access the dlq API.\n *\n * List or remove messages from the DLQ.\n */\n public get dlq(): DLQ {\n return new DLQ(this.http);\n }\n\n /**\n * Access the message API.\n *\n * Read or cancel messages.\n */\n public get messages(): Messages {\n return new Messages(this.http);\n }\n\n /**\n * Access the schedule API.\n *\n * Create, read or delete schedules.\n */\n public get schedules(): Schedules {\n return new Schedules(this.http);\n }\n public async publish<TRequest extends PublishRequest>(\n req: TRequest,\n ): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n\n headers.set(\"Upstash-Method\", req.method ?? \"POST\");\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.notBefore !== \"undefined\") {\n headers.set(\"Upstash-Not-Before\", req.notBefore.toFixed());\n }\n\n if (typeof req.deduplicationId !== \"undefined\") {\n headers.set(\"Upstash-Deduplication-Id\", req.deduplicationId);\n }\n\n if (typeof req.contentBasedDeduplication !== \"undefined\") {\n headers.set(\"Upstash-Content-Based-Deduplication\", \"true\");\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n if (typeof req.failureCallback !== \"undefined\") {\n headers.set(\"Upstash-Failure-Callback\", req.failureCallback);\n }\n\n const res = await this.http.request<PublishResponse<TRequest>>({\n path: [\"v2\", \"publish\", req.url ?? req.topic],\n body: req.body,\n headers,\n method: \"POST\",\n });\n return res;\n }\n\n /**\n * publishJSON is a utility wrapper around `publish` that automatically serializes the body\n * and sets the `Content-Type` header to `application/json`.\n */\n public async publishJSON<\n TBody = unknown,\n TRequest extends PublishRequest<TBody> = PublishRequest<TBody>,\n >(req: TRequest): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n headers.set(\"Content-Type\", \"application/json\");\n\n // @ts-ignore it's just internal\n const res = await this.publish<TRequest>({\n ...req,\n headers,\n body: JSON.stringify(req.body),\n } as PublishRequest);\n return res;\n }\n\n /**\n * Retrieve your logs.\n *\n * The logs endpoint is paginated and returns only 100 logs at a time.\n * If you want to receive more logs, you can use the cursor to paginate.\n *\n * The cursor is a unix timestamp with millisecond precision\n *\n * @example\n * ```ts\n * let cursor = Date.now()\n * const logs: Log[] = []\n * while (cursor > 0) {\n * const res = await qstash.logs({ cursor })\n * logs.push(...res.logs)\n * cursor = res.cursor ?? 0\n * }\n * ```\n */\n public async events(req?: EventsRequest): Promise<GetEventsResponse> {\n const query: Record<string, number> = {};\n if (req?.cursor && req.cursor > 0) {\n query.cursor = req.cursor;\n }\n const res = await this.http.request<GetEventsResponse>({\n path: [\"v2\", \"events\"],\n method: \"GET\",\n query,\n });\n return res;\n }\n}\ntype PublishToUrlResponse = {\n messageId: string;\n url: string;\n deduplicated?: boolean;\n};\n\ntype PublishToTopicResponse = PublishToUrlResponse[];\n\ntype PublishResponse<R> = R extends { url: string } ? PublishToUrlResponse : PublishToTopicResponse;\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client/dlq.ts","../src/client/error.ts","../src/client/http.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/topics.ts","../src/client/client.ts"],"sourcesContent":["import { Requester } from \"./http\";\nimport type { Message } from \"./messages\";\n\ntype DlqMessage = Message & {\n dlqId: string;\n};\n\nexport class DLQ {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * List messages in the dlq\n */\n public async listMessages(opts?: { cursor?: string }): Promise<{\n messages: DlqMessage[];\n cursor?: string;\n }> {\n return await this.http.request({\n method: \"GET\",\n path: [\"v2\", \"dlq\"],\n query: { cursor: opts?.cursor },\n });\n }\n\n /**\n * Remove a message from the dlq using it's `dlqId`\n */\n public async delete(dlqMessageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"dlq\", dlqMessageId],\n parseResponseAsJson: false, // there is no response\n });\n }\n}\n","/**\n * Result of 500 Internal Server Error\n */\nexport class QstashError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"QstashError\";\n }\n}\n\nexport class QstashRatelimitError extends QstashError {\n constructor(args: unknown) {\n super(`You have been ratelimited. ${JSON.stringify(args)} `);\n }\n}\n","import { QstashError, QstashRatelimitError } from \"./error\";\n\nexport type UpstashRequest = {\n /**\n * The path to the resource.\n */\n path: string[];\n\n /**\n * A BodyInit object or null to set request's body.\n */\n body?: BodyInit | null;\n\n /**\n * A Headers object, an object literal, or an array of two-item arrays to set\n * request's headers.\n */\n headers?: HeadersInit;\n\n /**\n * A boolean to set request's keepalive.\n */\n keepalive?: boolean;\n\n /**\n * A string to set request's method.\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\n query?: Record<string, string | number | boolean | undefined>;\n\n /**\n * if enabled, call `res.json()`\n *\n * @default true\n */\n parseResponseAsJson?: boolean;\n};\nexport type UpstashResponse<TResult> = TResult & { error?: string };\n\nexport interface Requester {\n request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;\n}\n\nexport type RetryConfig =\n | false\n | {\n /**\n * The number of retries to attempt before giving up.\n *\n * @default 5\n */\n retries?: number;\n /**\n * A backoff function receives the current retry cound and returns a number in milliseconds to wait before retrying.\n *\n * @default\n * ```ts\n * Math.exp(retryCount) * 50\n * ```\n */\n backoff?: (retryCount: number) => number;\n };\n\nexport type HttpClientConfig = {\n baseUrl: string;\n authorization: string;\n retry?: RetryConfig;\n};\n\nexport class HttpClient implements Requester {\n public readonly baseUrl: string;\n\n public readonly authorization: string;\n\n public readonly options?: { backend?: string };\n\n public retry: {\n attempts: number;\n backoff: (retryCount: number) => number;\n };\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n this.authorization = config.authorization;\n\n if (typeof config?.retry === \"boolean\" && config?.retry === false) {\n this.retry = {\n attempts: 1,\n backoff: () => 0,\n };\n } else {\n this.retry = {\n attempts: config.retry?.retries ? config.retry.retries + 1 : 5,\n backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n };\n }\n }\n\n public async request<TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> {\n const headers = new Headers(req.headers);\n headers.set(\"Authorization\", this.authorization);\n\n const requestOptions: RequestInit & { backend?: string } = {\n method: req.method,\n headers,\n body: req.body,\n keepalive: req.keepalive,\n };\n\n const url = new URL([this.baseUrl, ...(req.path ?? [])].join(\"/\"));\n if (req.query) {\n for (const [key, value] of Object.entries(req.query)) {\n if (typeof value !== \"undefined\") {\n url.searchParams.set(key, value.toString());\n }\n }\n }\n\n let res: Response | null = null;\n let error: Error | null = null;\n for (let i = 0; i < this.retry.attempts; i++) {\n try {\n res = await fetch(url.toString(), requestOptions);\n break;\n } catch (err) {\n error = err as Error;\n await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n }\n }\n if (!res) {\n throw error ?? new Error(\"Exhausted all retries\");\n }\n if (res.status === 429) {\n throw new QstashRatelimitError({\n limit: res.headers.get(\"Burst-RateLimit-Limit\"),\n remaining: res.headers.get(\"Burst-RateLimit-Remaining\"),\n reset: res.headers.get(\"Burst-RateLimit-Reset\"),\n });\n }\n\n if (res.status < 200 || res.status >= 300) {\n const body = await res.text();\n throw new QstashError(body.length > 0 ? body : `Error: status=${res.status}`);\n }\n if (req.parseResponseAsJson === false) {\n return undefined as unknown as UpstashResponse<TResult>;\n } else {\n return (await res.json()) as UpstashResponse<TResult>;\n }\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Message = {\n /**\n * A unique identifier for this message.\n */\n messageId: string;\n\n /**\n * The topic name if this message was sent to a topic.\n */\n topicName?: string;\n\n /**\n * The url where this message is sent to.\n */\n url: string;\n\n /**\n * The http method used to deliver the message\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The http headers sent along with the message to your API.\n */\n header?: Record<string, string[]>;\n\n /**\n * The http body sent to your API\n */\n body?: string;\n\n /**\n * Maxmimum number of retries.\n */\n maxRetries?: number;\n\n /**\n * A unix timestamp (milliseconds) after which this message may get delivered.\n */\n notBefore?: number;\n\n /**\n * A unix timestamp (milliseconds) when this messages was created.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: string;\n\n /**\n * The failure callback url if configured.\n */\n failureCallback?: string;\n};\n\nexport class Messages {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Get a message\n */\n public async get(messageId: string): Promise<Message> {\n return await this.http.request<Message>({\n method: \"GET\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n\n /**\n * Cancel a message\n */\n public async delete(messageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"messages\", messageId],\n parseResponseAsJson: false,\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Schedule = {\n scheduleId: string;\n cron: string;\n createdAt: number;\n destination: string;\n method: string;\n header?: Record<string, string[]>;\n body?: string;\n retries: number;\n delay?: number;\n callback?: string;\n failureCallback?: string;\n};\n\nexport type CreateScheduleRequest = {\n /**\n * Either a URL or topic name\n */\n destination: string;\n\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * In case your destination server is unavailable or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * Use a failure callback url to handle messages that could not be delivered.\n *\n * The failure callback url must be publicly accessible\n *\n * @default undefined\n */\n failureCallback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * Specify a cron expression to repeatedly send this message to the destination.\n */\n cron: string;\n};\n\nexport class Schedules {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a schedule\n */\n public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {\n const headers = new Headers(req.headers);\n\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n headers.set(\"Upstash-Cron\", req.cron);\n\n if (typeof req.method !== \"undefined\") {\n headers.set(\"Upstash-Method\", req.method);\n }\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n if (typeof req.failureCallback !== \"undefined\") {\n headers.set(\"Upstash-Failure-Callback\", req.failureCallback);\n }\n\n return await this.http.request({\n method: \"POST\",\n headers,\n path: [\"v2\", \"schedules\", req.destination],\n body: req.body,\n });\n }\n\n /**\n * Get a schedule\n */\n public async get(scheduleId: string): Promise<Schedule> {\n return await this.http.request<Schedule>({\n method: \"GET\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n\n /**\n * List your schedules\n */\n public async list(): Promise<Schedule[]> {\n return await this.http.request<Schedule[]>({\n method: \"GET\",\n path: [\"v2\", \"schedules\"],\n });\n }\n\n /**\n * Delete a schedule\n */\n public async delete(scheduleId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"schedules\", scheduleId],\n parseResponseAsJson: false,\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Endpoint = {\n /**\n * The name of the endpoint (optional)\n */\n name?: string;\n\n /**\n * The url of the endpoint\n */\n url: string;\n};\n\nexport type AddEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: Endpoint[];\n};\n\nexport type RemoveEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: (\n | {\n name: string;\n url?: string;\n }\n | {\n name?: string;\n url: string;\n }\n )[];\n};\n\nexport type Topic = {\n /**\n * The name of this topic.\n */\n name: string;\n\n /**\n * A list of all subscribed endpoints\n */\n endpoints: Endpoint[];\n};\n\nexport class Topics {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a new topic with the given name and endpoints\n */\n public async addEndpoints(req: AddEndpointsRequest): Promise<void> {\n await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name, \"endpoints\"],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n parseResponseAsJson: false,\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<void> {\n await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name, \"endpoints\"],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n parseResponseAsJson: false,\n });\n }\n\n /**\n * Get a list of all topics.\n */\n public async list(): Promise<Topic[]> {\n return await this.http.request<Topic[]>({\n method: \"GET\",\n path: [\"v2\", \"topics\"],\n });\n }\n\n /**\n * Get a single topic\n */\n public async get(name: string): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"GET\",\n path: [\"v2\", \"topics\", name],\n });\n }\n\n /**\n * Delete a topic\n */\n public async delete(name: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", name],\n parseResponseAsJson: false,\n });\n }\n}\n","import { DLQ } from \"./dlq\";\nimport { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Topics } from \"./topics\";\nimport { Event } from \"./types\";\ntype ClientConfig = {\n /**\n * Url of the qstash api server.\n *\n * This is only used for testing.\n *\n * @default \"https://qstash.upstash.io\"\n */\n baseUrl?: string;\n\n /**\n * The authorization token from the upstash console.\n */\n token: string;\n\n /**\n * Configure how the client should retry requests.\n */\n retry?: RetryConfig;\n};\n\nexport type PublishRequest<TBody = BodyInit> = {\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: TBody;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * Optionally set the absolute delay of this message.\n * This will override the delay option.\n * The message will not delivered until the specified time.\n *\n * Unix timestamp in seconds.\n *\n * @default undefined\n */\n notBefore?: number;\n\n /**\n * Provide a unique id for deduplication. This id will be used to detect duplicate messages.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default undefined\n */\n deduplicationId?: string;\n\n /**\n * If true, the message content will get hashed and used as deduplication id.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * The content based hash includes the following values:\n * - All headers, except Upstash-Authorization, this includes all headers you are sending.\n * - The entire raw request body The destination from the url path\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default false\n */\n contentBasedDeduplication?: boolean;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * Use a failure callback url to handle messages that could not be delivered.\n *\n * The failure callback url must be publicly accessible\n *\n * @default undefined\n */\n failureCallback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n} & (\n | {\n /**\n * The url where the message should be sent to.\n */\n url: string;\n topic?: never;\n }\n | {\n url?: never;\n /**\n * The url where the message should be sent to.\n */\n topic: string;\n }\n);\n\nexport type PublishJsonRequest = Omit<PublishRequest, \"body\"> & {\n /**\n * The message to send.\n * This can be anything as long as it can be serialized to JSON.\n */\n body: unknown;\n};\n\nexport type EventsRequest = {\n cursor?: number;\n};\n\nexport type GetEventsResponse = {\n cursor?: number;\n events: Event[];\n};\n\nexport class Client {\n public http: Requester;\n\n public constructor(config: ClientConfig) {\n this.http = new HttpClient({\n retry: config.retry,\n baseUrl: config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"https://qstash.upstash.io\",\n authorization: `Bearer ${config.token}`,\n });\n }\n\n /**\n * Access the topic API.\n *\n * Create, read, update or delete topics.\n */\n public get topics(): Topics {\n return new Topics(this.http);\n }\n\n /**\n * Access the dlq API.\n *\n * List or remove messages from the DLQ.\n */\n public get dlq(): DLQ {\n return new DLQ(this.http);\n }\n\n /**\n * Access the message API.\n *\n * Read or cancel messages.\n */\n public get messages(): Messages {\n return new Messages(this.http);\n }\n\n /**\n * Access the schedule API.\n *\n * Create, read or delete schedules.\n */\n public get schedules(): Schedules {\n return new Schedules(this.http);\n }\n public async publish<TRequest extends PublishRequest>(\n req: TRequest,\n ): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n\n headers.set(\"Upstash-Method\", req.method ?? \"POST\");\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.notBefore !== \"undefined\") {\n headers.set(\"Upstash-Not-Before\", req.notBefore.toFixed());\n }\n\n if (typeof req.deduplicationId !== \"undefined\") {\n headers.set(\"Upstash-Deduplication-Id\", req.deduplicationId);\n }\n\n if (typeof req.contentBasedDeduplication !== \"undefined\") {\n headers.set(\"Upstash-Content-Based-Deduplication\", \"true\");\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n if (typeof req.failureCallback !== \"undefined\") {\n headers.set(\"Upstash-Failure-Callback\", req.failureCallback);\n }\n\n const res = await this.http.request<PublishResponse<TRequest>>({\n path: [\"v2\", \"publish\", req.url ?? req.topic],\n body: req.body,\n headers,\n method: \"POST\",\n });\n return res;\n }\n\n /**\n * publishJSON is a utility wrapper around `publish` that automatically serializes the body\n * and sets the `Content-Type` header to `application/json`.\n */\n public async publishJSON<\n TBody = unknown,\n TRequest extends PublishRequest<TBody> = PublishRequest<TBody>,\n >(req: TRequest): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n headers.set(\"Content-Type\", \"application/json\");\n\n // @ts-ignore it's just internal\n const res = await this.publish<TRequest>({\n ...req,\n headers,\n body: JSON.stringify(req.body),\n } as PublishRequest);\n return res;\n }\n\n /**\n * Retrieve your logs.\n *\n * The logs endpoint is paginated and returns only 100 logs at a time.\n * If you want to receive more logs, you can use the cursor to paginate.\n *\n * The cursor is a unix timestamp with millisecond precision\n *\n * @example\n * ```ts\n * let cursor = Date.now()\n * const logs: Log[] = []\n * while (cursor > 0) {\n * const res = await qstash.logs({ cursor })\n * logs.push(...res.logs)\n * cursor = res.cursor ?? 0\n * }\n * ```\n */\n public async events(req?: EventsRequest): Promise<GetEventsResponse> {\n const query: Record<string, number> = {};\n if (req?.cursor && req.cursor > 0) {\n query.cursor = req.cursor;\n }\n const res = await this.http.request<GetEventsResponse>({\n path: [\"v2\", \"events\"],\n method: \"GET\",\n query,\n });\n return res;\n }\n}\ntype PublishToUrlResponse = {\n messageId: string;\n url: string;\n deduplicated?: boolean;\n};\n\ntype PublishToTopicResponse = PublishToUrlResponse[];\n\ntype PublishResponse<R> = R extends { url: string } ? PublishToUrlResponse : PublishToTopicResponse;\n"],"mappings":";;;;;;;;;AAOO,IAAM,MAAN,MAAU;AAAA,EAGf,YAAY,MAAiB;AAC3B,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKa,aAAa,MAGvB;AAAA;AACD,aAAO,MAAM,KAAK,KAAK,QAAQ;AAAA,QAC7B,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,KAAK;AAAA,QAClB,OAAO,EAAE,QAAQ,6BAAM,OAAO;AAAA,MAChC,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,OAAO,cAAqC;AAAA;AACvD,aAAO,MAAM,KAAK,KAAK,QAAc;AAAA,QACnC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,OAAO,YAAY;AAAA,QAChC,qBAAqB;AAAA;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AACF;;;ACnCO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,YAAY;AAAA,EACpD,YAAY,MAAe;AACzB,UAAM,8BAA8B,KAAK,UAAU,IAAI,CAAC,GAAG;AAAA,EAC7D;AACF;;;ACwDO,IAAM,aAAN,MAAsC;AAAA,EAYpC,YAAY,QAA0B;AAlF/C;AAmFI,SAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAE/C,SAAK,gBAAgB,OAAO;AAE5B,QAAI,QAAO,iCAAQ,WAAU,cAAa,iCAAQ,WAAU,OAAO;AACjE,WAAK,QAAQ;AAAA,QACX,UAAU;AAAA,QACV,SAAS,MAAM;AAAA,MACjB;AAAA,IACF,OAAO;AACL,WAAK,QAAQ;AAAA,QACX,YAAU,YAAO,UAAP,mBAAc,WAAU,OAAO,MAAM,UAAU,IAAI;AAAA,QAC7D,UAAS,kBAAO,UAAP,mBAAc,YAAd,YAA0B,CAAC,eAAe,KAAK,IAAI,UAAU,IAAI;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AAAA,EAEa,QAAiB,KAAwD;AAAA;AApGxF;AAqGI,YAAM,UAAU,IAAI,QAAQ,IAAI,OAAO;AACvC,cAAQ,IAAI,iBAAiB,KAAK,aAAa;AAE/C,YAAM,iBAAqD;AAAA,QACzD,QAAQ,IAAI;AAAA,QACZ;AAAA,QACA,MAAM,IAAI;AAAA,QACV,WAAW,IAAI;AAAA,MACjB;AAEA,YAAM,MAAM,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,SAAI,SAAJ,YAAY,CAAC,CAAE,EAAE,KAAK,GAAG,CAAC;AACjE,UAAI,IAAI,OAAO;AACb,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,KAAK,GAAG;AACpD,cAAI,OAAO,UAAU,aAAa;AAChC,gBAAI,aAAa,IAAI,KAAK,MAAM,SAAS,CAAC;AAAA,UAC5C;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAuB;AAC3B,UAAI,QAAsB;AAC1B,eAAS,IAAI,GAAG,IAAI,KAAK,MAAM,UAAU,KAAK;AAC5C,YAAI;AACF,gBAAM,MAAM,MAAM,IAAI,SAAS,GAAG,cAAc;AAChD;AAAA,QACF,SAAS,KAAK;AACZ,kBAAQ;AACR,gBAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,QAC/D;AAAA,MACF;AACA,UAAI,CAAC,KAAK;AACR,cAAM,wBAAS,IAAI,MAAM,uBAAuB;AAAA,MAClD;AACA,UAAI,IAAI,WAAW,KAAK;AACtB,cAAM,IAAI,qBAAqB;AAAA,UAC7B,OAAO,IAAI,QAAQ,IAAI,uBAAuB;AAAA,UAC9C,WAAW,IAAI,QAAQ,IAAI,2BAA2B;AAAA,UACtD,OAAO,IAAI,QAAQ,IAAI,uBAAuB;AAAA,QAChD,CAAC;AAAA,MACH;AAEA,UAAI,IAAI,SAAS,OAAO,IAAI,UAAU,KAAK;AACzC,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,cAAM,IAAI,YAAY,KAAK,SAAS,IAAI,OAAO,iBAAiB,IAAI,MAAM,EAAE;AAAA,MAC9E;AACA,UAAI,IAAI,wBAAwB,OAAO;AACrC,eAAO;AAAA,MACT,OAAO;AACL,eAAQ,MAAM,IAAI,KAAK;AAAA,MACzB;AAAA,IACF;AAAA;AACF;;;AC7FO,IAAM,WAAN,MAAe;AAAA,EAGpB,YAAY,MAAiB;AAC3B,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKa,IAAI,WAAqC;AAAA;AACpD,aAAO,MAAM,KAAK,KAAK,QAAiB;AAAA,QACtC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,YAAY,SAAS;AAAA,MACpC,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,OAAO,WAAkC;AAAA;AACpD,aAAO,MAAM,KAAK,KAAK,QAAc;AAAA,QACnC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,YAAY,SAAS;AAAA,QAClC,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AACF;;;ACIO,IAAM,YAAN,MAAgB;AAAA,EAGrB,YAAY,MAAiB;AAC3B,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKa,OAAO,KAA6D;AAAA;AAC/E,YAAM,UAAU,IAAI,QAAQ,IAAI,OAAO;AAEvC,UAAI,CAAC,QAAQ,IAAI,cAAc,GAAG;AAChC,gBAAQ,IAAI,gBAAgB,kBAAkB;AAAA,MAChD;AAEA,cAAQ,IAAI,gBAAgB,IAAI,IAAI;AAEpC,UAAI,OAAO,IAAI,WAAW,aAAa;AACrC,gBAAQ,IAAI,kBAAkB,IAAI,MAAM;AAAA,MAC1C;AAEA,UAAI,OAAO,IAAI,UAAU,aAAa;AACpC,gBAAQ,IAAI,iBAAiB,GAAG,IAAI,MAAM,QAAQ,CAAC,GAAG;AAAA,MACxD;AAEA,UAAI,OAAO,IAAI,YAAY,aAAa;AACtC,gBAAQ,IAAI,mBAAmB,IAAI,QAAQ,QAAQ,CAAC;AAAA,MACtD;AAEA,UAAI,OAAO,IAAI,aAAa,aAAa;AACvC,gBAAQ,IAAI,oBAAoB,IAAI,QAAQ;AAAA,MAC9C;AAEA,UAAI,OAAO,IAAI,oBAAoB,aAAa;AAC9C,gBAAQ,IAAI,4BAA4B,IAAI,eAAe;AAAA,MAC7D;AAEA,aAAO,MAAM,KAAK,KAAK,QAAQ;AAAA,QAC7B,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,CAAC,MAAM,aAAa,IAAI,WAAW;AAAA,QACzC,MAAM,IAAI;AAAA,MACZ,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,IAAI,YAAuC;AAAA;AACtD,aAAO,MAAM,KAAK,KAAK,QAAkB;AAAA,QACvC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,aAAa,UAAU;AAAA,MACtC,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,OAA4B;AAAA;AACvC,aAAO,MAAM,KAAK,KAAK,QAAoB;AAAA,QACzC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,WAAW;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,OAAO,YAAmC;AAAA;AACrD,aAAO,MAAM,KAAK,KAAK,QAAc;AAAA,QACnC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,aAAa,UAAU;AAAA,QACpC,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AACF;;;AChHO,IAAM,SAAN,MAAa;AAAA,EAGlB,YAAY,MAAiB;AAC3B,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKa,aAAa,KAAyC;AAAA;AACjE,YAAM,KAAK,KAAK,QAAe;AAAA,QAC7B,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,UAAU,IAAI,MAAM,WAAW;AAAA,QAC5C,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,IAAI,UAAU,CAAC;AAAA,QACjD,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,gBAAgB,KAA4C;AAAA;AACvE,YAAM,KAAK,KAAK,QAAe;AAAA,QAC7B,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,UAAU,IAAI,MAAM,WAAW;AAAA,QAC5C,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,WAAW,IAAI,UAAU,CAAC;AAAA,QACjD,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,OAAyB;AAAA;AACpC,aAAO,MAAM,KAAK,KAAK,QAAiB;AAAA,QACtC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,QAAQ;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,IAAI,MAA8B;AAAA;AAC7C,aAAO,MAAM,KAAK,KAAK,QAAe;AAAA,QACpC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,UAAU,IAAI;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKa,OAAO,MAA6B;AAAA;AAC/C,aAAO,MAAM,KAAK,KAAK,QAAc;AAAA,QACnC,QAAQ;AAAA,QACR,MAAM,CAAC,MAAM,UAAU,IAAI;AAAA,QAC3B,qBAAqB;AAAA,MACvB,CAAC;AAAA,IACH;AAAA;AACF;;;AC8CO,IAAM,SAAN,MAAa;AAAA,EAGX,YAAY,QAAsB;AACvC,SAAK,OAAO,IAAI,WAAW;AAAA,MACzB,OAAO,OAAO;AAAA,MACd,SAAS,OAAO,UAAU,OAAO,QAAQ,QAAQ,OAAO,EAAE,IAAI;AAAA,MAC9D,eAAe,UAAU,OAAO,KAAK;AAAA,IACvC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,SAAiB;AAC1B,WAAO,IAAI,OAAO,KAAK,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,MAAW;AACpB,WAAO,IAAI,IAAI,KAAK,IAAI;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,WAAqB;AAC9B,WAAO,IAAI,SAAS,KAAK,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,YAAuB;AAChC,WAAO,IAAI,UAAU,KAAK,IAAI;AAAA,EAChC;AAAA,EACa,QACX,KACoC;AAAA;AApNxC;AAqNI,YAAM,UAAU,IAAI,QAAQ,IAAI,OAAO;AAEvC,cAAQ,IAAI,mBAAkB,SAAI,WAAJ,YAAc,MAAM;AAElD,UAAI,OAAO,IAAI,UAAU,aAAa;AACpC,gBAAQ,IAAI,iBAAiB,GAAG,IAAI,MAAM,QAAQ,CAAC,GAAG;AAAA,MACxD;AAEA,UAAI,OAAO,IAAI,cAAc,aAAa;AACxC,gBAAQ,IAAI,sBAAsB,IAAI,UAAU,QAAQ,CAAC;AAAA,MAC3D;AAEA,UAAI,OAAO,IAAI,oBAAoB,aAAa;AAC9C,gBAAQ,IAAI,4BAA4B,IAAI,eAAe;AAAA,MAC7D;AAEA,UAAI,OAAO,IAAI,8BAA8B,aAAa;AACxD,gBAAQ,IAAI,uCAAuC,MAAM;AAAA,MAC3D;AAEA,UAAI,OAAO,IAAI,YAAY,aAAa;AACtC,gBAAQ,IAAI,mBAAmB,IAAI,QAAQ,QAAQ,CAAC;AAAA,MACtD;AAEA,UAAI,OAAO,IAAI,aAAa,aAAa;AACvC,gBAAQ,IAAI,oBAAoB,IAAI,QAAQ;AAAA,MAC9C;AAEA,UAAI,OAAO,IAAI,oBAAoB,aAAa;AAC9C,gBAAQ,IAAI,4BAA4B,IAAI,eAAe;AAAA,MAC7D;AAEA,YAAM,MAAM,MAAM,KAAK,KAAK,QAAmC;AAAA,QAC7D,MAAM,CAAC,MAAM,YAAW,SAAI,QAAJ,YAAW,IAAI,KAAK;AAAA,QAC5C,MAAM,IAAI;AAAA,QACV;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AACD,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMa,YAGX,KAAmD;AAAA;AACnD,YAAM,UAAU,IAAI,QAAQ,IAAI,OAAO;AACvC,cAAQ,IAAI,gBAAgB,kBAAkB;AAG9C,YAAM,MAAM,MAAM,KAAK,QAAkB,iCACpC,MADoC;AAAA,QAEvC;AAAA,QACA,MAAM,KAAK,UAAU,IAAI,IAAI;AAAA,MAC/B,EAAmB;AACnB,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBa,OAAO,KAAiD;AAAA;AACnE,YAAM,QAAgC,CAAC;AACvC,WAAI,2BAAK,WAAU,IAAI,SAAS,GAAG;AACjC,cAAM,SAAS,IAAI;AAAA,MACrB;AACA,YAAM,MAAM,MAAM,KAAK,KAAK,QAA2B;AAAA,QACrD,MAAM,CAAC,MAAM,QAAQ;AAAA,QACrB,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAAA;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/nextjs.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NextApiHandler, NextApiRequest, NextApiResponse } from \"next\";\nimport { NextRequest, NextFetchEvent, NextResponse } from \"next/server\";\nimport { Receiver } from \"./receiver\";\n\nexport type VerifySignatureConfig = {\n currentSigningKey?: string;\n nextSigningKey?: string;\n\n /**\n * The url of this api route, including the protocol.\n *\n * If you omit this, the url will be automatically determined by checking the `VERCEL_URL` env variable and assuming `https`\n */\n url?: string;\n\n /**\n * Number of seconds to tolerate when checking `nbf` and `exp` claims, to deal with small clock differences among different servers\n *\n * @default 0\n */\n clockTolerance?: number;\n};\n\nexport function verifySignature(\n handler: NextApiHandler,\n config?: VerifySignatureConfig,\n): NextApiHandler {\n const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY;\n if (!currentSigningKey) {\n throw new Error(\n \"currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY\",\n );\n }\n const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY;\n if (!nextSigningKey) {\n throw new Error(\n \"nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY\",\n );\n }\n const receiver = new Receiver({\n currentSigningKey,\n nextSigningKey,\n });\n\n return async (req: NextApiRequest, res: NextApiResponse) => {\n // @ts-ignore This can throw errors during vercel build\n const signature = req.headers[\"upstash-signature\"];\n if (!signature) {\n res.status(400);\n res.send(\"`Upstash-Signature` header is missing\");\n res.end();\n return;\n }\n if (typeof signature !== \"string\") {\n throw new Error(\"`Upstash-Signature` header is not a string\");\n }\n\n const chunks = [];\n for await (const chunk of req) {\n // @ts-ignore\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n const body = Buffer.concat(chunks).toString(\"utf-8\");\n\n const isValid = await receiver.verify({\n signature,\n body,\n clockTolerance: config?.clockTolerance,\n });\n if (!isValid) {\n res.status(400);\n res.send(\"Invalid signature\");\n res.end();\n return;\n }\n\n try {\n if (req.headers[\"content-type\"] === \"application/json\") {\n req.body = JSON.parse(body);\n } else {\n req.body = body;\n }\n } catch {\n req.body = body;\n }\n\n return handler(req, res);\n };\n}\n\nexport function verifySignatureEdge(\n handler: (req: NextRequest, nfe?: NextFetchEvent) => NextResponse | Promise<NextResponse>,\n config?: VerifySignatureConfig,\n) {\n const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY;\n if (!currentSigningKey) {\n throw new Error(\n \"currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY\",\n );\n }\n const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY;\n if (!nextSigningKey) {\n throw new Error(\n \"nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY\",\n );\n }\n const receiver = new Receiver({\n currentSigningKey,\n nextSigningKey,\n });\n\n return async (req: NextRequest, nfe: NextFetchEvent) => {\n const reqClone = req.clone() as NextRequest;\n // @ts-ignore This can throw errors during vercel build\n const signature = req.headers.get(\"upstash-signature\");\n if (!signature) {\n return new NextResponse(new TextEncoder().encode(\"`Upstash-Signature` header is missing\"), {\n status: 403,\n });\n }\n if (typeof signature !== \"string\") {\n throw new Error(\"`Upstash-Signature` header is not a string\");\n }\n\n const body = await req.text();\n const isValid = await receiver.verify({\n signature,\n body,\n clockTolerance: config?.clockTolerance,\n });\n if (!isValid) {\n return new NextResponse(new TextEncoder().encode(\"invalid signature\"), { status: 403 });\n }\n\n let parsedBody: unknown = undefined;\n\n try {\n if (req.headers.get(\"content-type\") === \"application/json\") {\n parsedBody = JSON.parse(body);\n } else {\n parsedBody = body;\n }\n } catch {\n parsedBody = body;\n }\n\n return handler(reqClone, nfe);\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/nextjs.ts"],"sourcesContent":["import type { NextApiHandler, NextApiRequest, NextApiResponse } from \"next\";\nimport { NextRequest, NextFetchEvent, NextResponse } from \"next/server\";\nimport { Receiver } from \"./receiver\";\n\nexport type VerifySignatureConfig = {\n currentSigningKey?: string;\n nextSigningKey?: string;\n\n /**\n * The url of this api route, including the protocol.\n *\n * If you omit this, the url will be automatically determined by checking the `VERCEL_URL` env variable and assuming `https`\n */\n url?: string;\n\n /**\n * Number of seconds to tolerate when checking `nbf` and `exp` claims, to deal with small clock differences among different servers\n *\n * @default 0\n */\n clockTolerance?: number;\n};\n\nexport function verifySignature(\n handler: NextApiHandler,\n config?: VerifySignatureConfig,\n): NextApiHandler {\n const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY;\n if (!currentSigningKey) {\n throw new Error(\n \"currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY\",\n );\n }\n const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY;\n if (!nextSigningKey) {\n throw new Error(\n \"nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY\",\n );\n }\n const receiver = new Receiver({\n currentSigningKey,\n nextSigningKey,\n });\n\n return async (req: NextApiRequest, res: NextApiResponse) => {\n // @ts-ignore This can throw errors during vercel build\n const signature = req.headers[\"upstash-signature\"];\n if (!signature) {\n res.status(400);\n res.send(\"`Upstash-Signature` header is missing\");\n res.end();\n return;\n }\n if (typeof signature !== \"string\") {\n throw new Error(\"`Upstash-Signature` header is not a string\");\n }\n\n const chunks = [];\n for await (const chunk of req) {\n // @ts-ignore\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n const body = Buffer.concat(chunks).toString(\"utf-8\");\n\n const isValid = await receiver.verify({\n signature,\n body,\n clockTolerance: config?.clockTolerance,\n });\n if (!isValid) {\n res.status(400);\n res.send(\"Invalid signature\");\n res.end();\n return;\n }\n\n try {\n if (req.headers[\"content-type\"] === \"application/json\") {\n req.body = JSON.parse(body);\n } else {\n req.body = body;\n }\n } catch {\n req.body = body;\n }\n\n return handler(req, res);\n };\n}\n\nexport function verifySignatureEdge(\n handler: (req: NextRequest, nfe?: NextFetchEvent) => NextResponse | Promise<NextResponse>,\n config?: VerifySignatureConfig,\n) {\n const currentSigningKey = config?.currentSigningKey ?? process.env.QSTASH_CURRENT_SIGNING_KEY;\n if (!currentSigningKey) {\n throw new Error(\n \"currentSigningKey is required, either in the config or as env variable QSTASH_CURRENT_SIGNING_KEY\",\n );\n }\n const nextSigningKey = config?.nextSigningKey ?? process.env.QSTASH_NEXT_SIGNING_KEY;\n if (!nextSigningKey) {\n throw new Error(\n \"nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY\",\n );\n }\n const receiver = new Receiver({\n currentSigningKey,\n nextSigningKey,\n });\n\n return async (req: NextRequest, nfe: NextFetchEvent) => {\n const reqClone = req.clone() as NextRequest;\n // @ts-ignore This can throw errors during vercel build\n const signature = req.headers.get(\"upstash-signature\");\n if (!signature) {\n return new NextResponse(new TextEncoder().encode(\"`Upstash-Signature` header is missing\"), {\n status: 403,\n });\n }\n if (typeof signature !== \"string\") {\n throw new Error(\"`Upstash-Signature` header is not a string\");\n }\n\n const body = await req.text();\n const isValid = await receiver.verify({\n signature,\n body,\n clockTolerance: config?.clockTolerance,\n });\n if (!isValid) {\n return new NextResponse(new TextEncoder().encode(\"invalid signature\"), { status: 403 });\n }\n\n let parsedBody: unknown = undefined;\n\n try {\n if (req.headers.get(\"content-type\") === \"application/json\") {\n parsedBody = JSON.parse(body);\n } else {\n parsedBody = body;\n }\n } catch {\n parsedBody = body;\n }\n\n return handler(reqClone, nfe);\n };\n}\n"],"mappings":"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","names":[]}