@upstash/qstash 2.1.0 → 2.1.1-canary.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 +0 -13
- package/dist/{chunk-G4FL5XMG.mjs → chunk-A74IFAVZ.cjs} +12 -12
- package/dist/chunk-A74IFAVZ.cjs.map +1 -0
- package/dist/chunk-EQTYEU4U.js +11 -11
- package/dist/chunk-EQTYEU4U.js.map +1 -1
- package/dist/{index.mjs → index.cjs} +35 -35
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +34 -34
- package/dist/index.js.map +1 -1
- package/dist/{nextjs.mjs → nextjs.cjs} +18 -18
- package/dist/nextjs.cjs.map +1 -0
- package/dist/nextjs.js +17 -17
- package/dist/nextjs.js.map +1 -1
- package/package.json +14 -3
- package/dist/chunk-G4FL5XMG.mjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/nextjs.mjs.map +0 -1
- /package/dist/{index.d.mts → index.d.cts} +0 -0
- /package/dist/{nextjs.d.mts → nextjs.d.cts} +0 -0
package/README.md
CHANGED
|
@@ -17,13 +17,6 @@ It is 100% built on stateless HTTP requests and designed for:
|
|
|
17
17
|
- WebAssembly
|
|
18
18
|
- and other environments where HTTP is preferred over TCP.
|
|
19
19
|
|
|
20
|
-
## Status of the SDK
|
|
21
|
-
|
|
22
|
-
It is currently in beta and we are actively collecting feedback from the
|
|
23
|
-
community. Please report any issues you encounter or feature requests in the
|
|
24
|
-
[GitHub issues](https://github.com/upstash/sdk-qstash-ts/issues) or talk to us
|
|
25
|
-
on [Discord](https://discord.gg/w9SenAtbme). Thank you!
|
|
26
|
-
|
|
27
20
|
## How does QStash work?
|
|
28
21
|
|
|
29
22
|
QStash is the message broker between your serverless apps. You send an HTTP
|
|
@@ -42,12 +35,6 @@ the message later, to guarentee at-least-once delivery.
|
|
|
42
35
|
npm install @upstash/qstash
|
|
43
36
|
```
|
|
44
37
|
|
|
45
|
-
#### Deno
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
import { Client } from "https://deno.land/x/upstash_qstash/mod.ts";
|
|
49
|
-
```
|
|
50
|
-
|
|
51
38
|
### Get your authorization token
|
|
52
39
|
|
|
53
40
|
Go to [upstash](https://console.upstash.com/qstash) and copy the token.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
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; } }var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -45,8 +45,8 @@ var __async = (__this, __arguments, generator) => {
|
|
|
45
45
|
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
46
46
|
|
|
47
47
|
// src/receiver.ts
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
var _jose = require('jose'); var jose = _interopRequireWildcard(_jose);
|
|
49
|
+
var _cryptojs = require('crypto-js'); var crypto = _interopRequireWildcard(_cryptojs);
|
|
50
50
|
var SignatureError = class extends Error {
|
|
51
51
|
constructor(message) {
|
|
52
52
|
super(message);
|
|
@@ -101,12 +101,12 @@ var Receiver = class {
|
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
//# sourceMappingURL=chunk-
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
exports.__spreadValues = __spreadValues; exports.__spreadProps = __spreadProps; exports.__async = __async; exports.__forAwait = __forAwait; exports.SignatureError = SignatureError; exports.Receiver = Receiver;
|
|
112
|
+
//# sourceMappingURL=chunk-A74IFAVZ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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"]}
|
package/dist/chunk-EQTYEU4U.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -45,8 +45,8 @@ var __async = (__this, __arguments, generator) => {
|
|
|
45
45
|
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
46
46
|
|
|
47
47
|
// src/receiver.ts
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
import * as jose from "jose";
|
|
49
|
+
import * as crypto from "crypto-js";
|
|
50
50
|
var SignatureError = class extends Error {
|
|
51
51
|
constructor(message) {
|
|
52
52
|
super(message);
|
|
@@ -101,12 +101,12 @@ var Receiver = class {
|
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
104
|
+
export {
|
|
105
|
+
__spreadValues,
|
|
106
|
+
__spreadProps,
|
|
107
|
+
__async,
|
|
108
|
+
__forAwait,
|
|
109
|
+
SignatureError,
|
|
110
|
+
Receiver
|
|
111
|
+
};
|
|
112
112
|
//# sourceMappingURL=chunk-EQTYEU4U.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/receiver.ts"],"
|
|
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":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkA74IFAVZcjs = require('./chunk-A74IFAVZ.cjs');
|
|
8
8
|
|
|
9
9
|
// src/client/error.ts
|
|
10
10
|
var QstashError = class extends Error {
|
|
@@ -33,7 +33,7 @@ var HttpClient = class {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
request(req) {
|
|
36
|
-
return __async(this, null, function* () {
|
|
36
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
37
37
|
var _a, _b;
|
|
38
38
|
const headers = new Headers(req.headers);
|
|
39
39
|
headers.set("Authorization", this.authorization);
|
|
@@ -82,7 +82,7 @@ var Topics = class {
|
|
|
82
82
|
* Create a new topic with the given name and endpoints
|
|
83
83
|
*/
|
|
84
84
|
addEndpoints(req) {
|
|
85
|
-
return __async(this, null, function* () {
|
|
85
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
86
86
|
return yield this.http.request({
|
|
87
87
|
method: "POST",
|
|
88
88
|
path: ["v2", "topics", req.name],
|
|
@@ -95,7 +95,7 @@ var Topics = class {
|
|
|
95
95
|
* Remove endpoints from a topic.
|
|
96
96
|
*/
|
|
97
97
|
removeEndpoints(req) {
|
|
98
|
-
return __async(this, null, function* () {
|
|
98
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
99
99
|
return yield this.http.request({
|
|
100
100
|
method: "DELETE",
|
|
101
101
|
path: ["v2", "topics", req.name],
|
|
@@ -108,7 +108,7 @@ var Topics = class {
|
|
|
108
108
|
* Get a list of all topics.
|
|
109
109
|
*/
|
|
110
110
|
list() {
|
|
111
|
-
return __async(this, null, function* () {
|
|
111
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
112
112
|
return yield this.http.request({
|
|
113
113
|
method: "GET",
|
|
114
114
|
path: ["v2", "topics"]
|
|
@@ -119,7 +119,7 @@ var Topics = class {
|
|
|
119
119
|
* Get a single topic
|
|
120
120
|
*/
|
|
121
121
|
get(name) {
|
|
122
|
-
return __async(this, null, function* () {
|
|
122
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
123
123
|
return yield this.http.request({
|
|
124
124
|
method: "GET",
|
|
125
125
|
path: ["v2", "topics", name]
|
|
@@ -130,7 +130,7 @@ var Topics = class {
|
|
|
130
130
|
* Delete a topic
|
|
131
131
|
*/
|
|
132
132
|
delete(name) {
|
|
133
|
-
return __async(this, null, function* () {
|
|
133
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
134
134
|
return yield this.http.request({
|
|
135
135
|
method: "DELETE",
|
|
136
136
|
path: ["v2", "topics", name]
|
|
@@ -148,7 +148,7 @@ var Messages = class {
|
|
|
148
148
|
* Get a message
|
|
149
149
|
*/
|
|
150
150
|
get(messageId) {
|
|
151
|
-
return __async(this, null, function* () {
|
|
151
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
152
152
|
return yield this.http.request({
|
|
153
153
|
method: "GET",
|
|
154
154
|
path: ["v2", "messages", messageId]
|
|
@@ -159,7 +159,7 @@ var Messages = class {
|
|
|
159
159
|
* Cancel a message
|
|
160
160
|
*/
|
|
161
161
|
delete(messageId) {
|
|
162
|
-
return __async(this, null, function* () {
|
|
162
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
163
163
|
return yield this.http.request({
|
|
164
164
|
method: "DELETE",
|
|
165
165
|
path: ["v2", "messages", messageId]
|
|
@@ -177,7 +177,7 @@ var Schedules = class {
|
|
|
177
177
|
* Create a schedule
|
|
178
178
|
*/
|
|
179
179
|
create(req) {
|
|
180
|
-
return __async(this, null, function* () {
|
|
180
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
181
181
|
return yield this.http.request({
|
|
182
182
|
method: "POST",
|
|
183
183
|
headers: { "Content-Type": "application/json" },
|
|
@@ -190,7 +190,7 @@ var Schedules = class {
|
|
|
190
190
|
* Get a schedule
|
|
191
191
|
*/
|
|
192
192
|
get(scheduleId) {
|
|
193
|
-
return __async(this, null, function* () {
|
|
193
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
194
194
|
return yield this.http.request({
|
|
195
195
|
method: "GET",
|
|
196
196
|
path: ["v2", "schedules", scheduleId]
|
|
@@ -201,7 +201,7 @@ var Schedules = class {
|
|
|
201
201
|
* List your schedules
|
|
202
202
|
*/
|
|
203
203
|
list() {
|
|
204
|
-
return __async(this, null, function* () {
|
|
204
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
205
205
|
return yield this.http.request({
|
|
206
206
|
method: "GET",
|
|
207
207
|
path: ["v2", "schedules"]
|
|
@@ -212,7 +212,7 @@ var Schedules = class {
|
|
|
212
212
|
* Delete a schedule
|
|
213
213
|
*/
|
|
214
214
|
delete(scheduleId) {
|
|
215
|
-
return __async(this, null, function* () {
|
|
215
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
216
216
|
return yield this.http.request({
|
|
217
217
|
method: "DELETE",
|
|
218
218
|
path: ["v2", "schedules", scheduleId]
|
|
@@ -230,7 +230,7 @@ var DLQ = class {
|
|
|
230
230
|
* List messages in the dlq
|
|
231
231
|
*/
|
|
232
232
|
listMessages() {
|
|
233
|
-
return __async(this, null, function* () {
|
|
233
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
234
234
|
return yield this.http.request({
|
|
235
235
|
method: "GET",
|
|
236
236
|
path: ["v2", "dlq", "messages"]
|
|
@@ -241,7 +241,7 @@ var DLQ = class {
|
|
|
241
241
|
* Remove a message from the dlq using it's `dlqId`
|
|
242
242
|
*/
|
|
243
243
|
delete(dlqMessageId) {
|
|
244
|
-
return __async(this, null, function* () {
|
|
244
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
245
245
|
return yield this.http.request({
|
|
246
246
|
method: "DELETE",
|
|
247
247
|
path: ["v2", "dlq", "messages", dlqMessageId]
|
|
@@ -292,7 +292,7 @@ var Client = class {
|
|
|
292
292
|
return new Schedules(this.http);
|
|
293
293
|
}
|
|
294
294
|
publish(req) {
|
|
295
|
-
return __async(this, null, function* () {
|
|
295
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
296
296
|
var _a, _b;
|
|
297
297
|
const headers = new Headers(req.headers);
|
|
298
298
|
headers.set("Upstash-Method", (_a = req.method) != null ? _a : "POST");
|
|
@@ -328,10 +328,10 @@ var Client = class {
|
|
|
328
328
|
* and sets the `Content-Type` header to `application/json`.
|
|
329
329
|
*/
|
|
330
330
|
publishJSON(req) {
|
|
331
|
-
return __async(this, null, function* () {
|
|
331
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
332
332
|
const headers = new Headers(req.headers);
|
|
333
333
|
headers.set("Content-Type", "application/json");
|
|
334
|
-
const res = yield this.publish(__spreadProps(__spreadValues({}, req), {
|
|
334
|
+
const res = yield this.publish(_chunkA74IFAVZcjs.__spreadProps.call(void 0, _chunkA74IFAVZcjs.__spreadValues.call(void 0, {}, req), {
|
|
335
335
|
headers,
|
|
336
336
|
body: JSON.stringify(req.body)
|
|
337
337
|
}));
|
|
@@ -358,7 +358,7 @@ var Client = class {
|
|
|
358
358
|
* ```
|
|
359
359
|
*/
|
|
360
360
|
events(req) {
|
|
361
|
-
return __async(this, null, function* () {
|
|
361
|
+
return _chunkA74IFAVZcjs.__async.call(void 0, this, null, function* () {
|
|
362
362
|
const query = {};
|
|
363
363
|
if ((req == null ? void 0 : req.cursor) && req.cursor > 0) {
|
|
364
364
|
query.cursor = req.cursor;
|
|
@@ -372,13 +372,13 @@ var Client = class {
|
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
};
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
//# sourceMappingURL=index.
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
exports.Client = Client; exports.Messages = Messages; exports.QstashError = QstashError; exports.Receiver = _chunkA74IFAVZcjs.Receiver; exports.Schedules = Schedules; exports.SignatureError = _chunkA74IFAVZcjs.SignatureError; exports.Topics = Topics;
|
|
384
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\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","import { QstashError } 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};\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\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\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<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\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 });\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 crated.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: 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 });\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};\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 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 * 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 * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\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 return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\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 });\n }\n}\n","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(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\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\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\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 * 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 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"]}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import {
|
|
2
|
+
Receiver,
|
|
3
|
+
SignatureError,
|
|
4
|
+
__async,
|
|
5
|
+
__spreadProps,
|
|
6
|
+
__spreadValues
|
|
7
|
+
} from "./chunk-EQTYEU4U.js";
|
|
8
8
|
|
|
9
9
|
// src/client/error.ts
|
|
10
10
|
var QstashError = class extends Error {
|
|
@@ -33,7 +33,7 @@ var HttpClient = class {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
request(req) {
|
|
36
|
-
return
|
|
36
|
+
return __async(this, null, function* () {
|
|
37
37
|
var _a, _b;
|
|
38
38
|
const headers = new Headers(req.headers);
|
|
39
39
|
headers.set("Authorization", this.authorization);
|
|
@@ -82,7 +82,7 @@ var Topics = class {
|
|
|
82
82
|
* Create a new topic with the given name and endpoints
|
|
83
83
|
*/
|
|
84
84
|
addEndpoints(req) {
|
|
85
|
-
return
|
|
85
|
+
return __async(this, null, function* () {
|
|
86
86
|
return yield this.http.request({
|
|
87
87
|
method: "POST",
|
|
88
88
|
path: ["v2", "topics", req.name],
|
|
@@ -95,7 +95,7 @@ var Topics = class {
|
|
|
95
95
|
* Remove endpoints from a topic.
|
|
96
96
|
*/
|
|
97
97
|
removeEndpoints(req) {
|
|
98
|
-
return
|
|
98
|
+
return __async(this, null, function* () {
|
|
99
99
|
return yield this.http.request({
|
|
100
100
|
method: "DELETE",
|
|
101
101
|
path: ["v2", "topics", req.name],
|
|
@@ -108,7 +108,7 @@ var Topics = class {
|
|
|
108
108
|
* Get a list of all topics.
|
|
109
109
|
*/
|
|
110
110
|
list() {
|
|
111
|
-
return
|
|
111
|
+
return __async(this, null, function* () {
|
|
112
112
|
return yield this.http.request({
|
|
113
113
|
method: "GET",
|
|
114
114
|
path: ["v2", "topics"]
|
|
@@ -119,7 +119,7 @@ var Topics = class {
|
|
|
119
119
|
* Get a single topic
|
|
120
120
|
*/
|
|
121
121
|
get(name) {
|
|
122
|
-
return
|
|
122
|
+
return __async(this, null, function* () {
|
|
123
123
|
return yield this.http.request({
|
|
124
124
|
method: "GET",
|
|
125
125
|
path: ["v2", "topics", name]
|
|
@@ -130,7 +130,7 @@ var Topics = class {
|
|
|
130
130
|
* Delete a topic
|
|
131
131
|
*/
|
|
132
132
|
delete(name) {
|
|
133
|
-
return
|
|
133
|
+
return __async(this, null, function* () {
|
|
134
134
|
return yield this.http.request({
|
|
135
135
|
method: "DELETE",
|
|
136
136
|
path: ["v2", "topics", name]
|
|
@@ -148,7 +148,7 @@ var Messages = class {
|
|
|
148
148
|
* Get a message
|
|
149
149
|
*/
|
|
150
150
|
get(messageId) {
|
|
151
|
-
return
|
|
151
|
+
return __async(this, null, function* () {
|
|
152
152
|
return yield this.http.request({
|
|
153
153
|
method: "GET",
|
|
154
154
|
path: ["v2", "messages", messageId]
|
|
@@ -159,7 +159,7 @@ var Messages = class {
|
|
|
159
159
|
* Cancel a message
|
|
160
160
|
*/
|
|
161
161
|
delete(messageId) {
|
|
162
|
-
return
|
|
162
|
+
return __async(this, null, function* () {
|
|
163
163
|
return yield this.http.request({
|
|
164
164
|
method: "DELETE",
|
|
165
165
|
path: ["v2", "messages", messageId]
|
|
@@ -177,7 +177,7 @@ var Schedules = class {
|
|
|
177
177
|
* Create a schedule
|
|
178
178
|
*/
|
|
179
179
|
create(req) {
|
|
180
|
-
return
|
|
180
|
+
return __async(this, null, function* () {
|
|
181
181
|
return yield this.http.request({
|
|
182
182
|
method: "POST",
|
|
183
183
|
headers: { "Content-Type": "application/json" },
|
|
@@ -190,7 +190,7 @@ var Schedules = class {
|
|
|
190
190
|
* Get a schedule
|
|
191
191
|
*/
|
|
192
192
|
get(scheduleId) {
|
|
193
|
-
return
|
|
193
|
+
return __async(this, null, function* () {
|
|
194
194
|
return yield this.http.request({
|
|
195
195
|
method: "GET",
|
|
196
196
|
path: ["v2", "schedules", scheduleId]
|
|
@@ -201,7 +201,7 @@ var Schedules = class {
|
|
|
201
201
|
* List your schedules
|
|
202
202
|
*/
|
|
203
203
|
list() {
|
|
204
|
-
return
|
|
204
|
+
return __async(this, null, function* () {
|
|
205
205
|
return yield this.http.request({
|
|
206
206
|
method: "GET",
|
|
207
207
|
path: ["v2", "schedules"]
|
|
@@ -212,7 +212,7 @@ var Schedules = class {
|
|
|
212
212
|
* Delete a schedule
|
|
213
213
|
*/
|
|
214
214
|
delete(scheduleId) {
|
|
215
|
-
return
|
|
215
|
+
return __async(this, null, function* () {
|
|
216
216
|
return yield this.http.request({
|
|
217
217
|
method: "DELETE",
|
|
218
218
|
path: ["v2", "schedules", scheduleId]
|
|
@@ -230,7 +230,7 @@ var DLQ = class {
|
|
|
230
230
|
* List messages in the dlq
|
|
231
231
|
*/
|
|
232
232
|
listMessages() {
|
|
233
|
-
return
|
|
233
|
+
return __async(this, null, function* () {
|
|
234
234
|
return yield this.http.request({
|
|
235
235
|
method: "GET",
|
|
236
236
|
path: ["v2", "dlq", "messages"]
|
|
@@ -241,7 +241,7 @@ var DLQ = class {
|
|
|
241
241
|
* Remove a message from the dlq using it's `dlqId`
|
|
242
242
|
*/
|
|
243
243
|
delete(dlqMessageId) {
|
|
244
|
-
return
|
|
244
|
+
return __async(this, null, function* () {
|
|
245
245
|
return yield this.http.request({
|
|
246
246
|
method: "DELETE",
|
|
247
247
|
path: ["v2", "dlq", "messages", dlqMessageId]
|
|
@@ -292,7 +292,7 @@ var Client = class {
|
|
|
292
292
|
return new Schedules(this.http);
|
|
293
293
|
}
|
|
294
294
|
publish(req) {
|
|
295
|
-
return
|
|
295
|
+
return __async(this, null, function* () {
|
|
296
296
|
var _a, _b;
|
|
297
297
|
const headers = new Headers(req.headers);
|
|
298
298
|
headers.set("Upstash-Method", (_a = req.method) != null ? _a : "POST");
|
|
@@ -328,10 +328,10 @@ var Client = class {
|
|
|
328
328
|
* and sets the `Content-Type` header to `application/json`.
|
|
329
329
|
*/
|
|
330
330
|
publishJSON(req) {
|
|
331
|
-
return
|
|
331
|
+
return __async(this, null, function* () {
|
|
332
332
|
const headers = new Headers(req.headers);
|
|
333
333
|
headers.set("Content-Type", "application/json");
|
|
334
|
-
const res = yield this.publish(
|
|
334
|
+
const res = yield this.publish(__spreadProps(__spreadValues({}, req), {
|
|
335
335
|
headers,
|
|
336
336
|
body: JSON.stringify(req.body)
|
|
337
337
|
}));
|
|
@@ -358,7 +358,7 @@ var Client = class {
|
|
|
358
358
|
* ```
|
|
359
359
|
*/
|
|
360
360
|
events(req) {
|
|
361
|
-
return
|
|
361
|
+
return __async(this, null, function* () {
|
|
362
362
|
const query = {};
|
|
363
363
|
if ((req == null ? void 0 : req.cursor) && req.cursor > 0) {
|
|
364
364
|
query.cursor = req.cursor;
|
|
@@ -372,13 +372,13 @@ var Client = class {
|
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
};
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
375
|
+
export {
|
|
376
|
+
Client,
|
|
377
|
+
Messages,
|
|
378
|
+
QstashError,
|
|
379
|
+
Receiver,
|
|
380
|
+
Schedules,
|
|
381
|
+
SignatureError,
|
|
382
|
+
Topics
|
|
383
|
+
};
|
|
384
384
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\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","import { QstashError } 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};\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\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\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<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\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 });\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 crated.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: 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 });\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};\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 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 * 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 * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\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 return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\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 });\n }\n}\n","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(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\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\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\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 * 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 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
|
+
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"sourcesContent":["/**\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","import { QstashError } 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};\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\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\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<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\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 });\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 crated.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: 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 });\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};\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 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 * 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 * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\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 return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\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 });\n }\n}\n","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(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\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\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\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 * 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 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":"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","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
var _chunkA74IFAVZcjs = require('./chunk-A74IFAVZ.cjs');
|
|
6
6
|
|
|
7
7
|
// src/nextjs.ts
|
|
8
|
-
|
|
8
|
+
var _server = require('next/server');
|
|
9
9
|
function verifySignature(handler, config) {
|
|
10
10
|
var _a, _b;
|
|
11
11
|
const currentSigningKey = (_a = config == null ? void 0 : config.currentSigningKey) != null ? _a : process.env.QSTASH_CURRENT_SIGNING_KEY;
|
|
@@ -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 Receiver({
|
|
23
|
+
const receiver = new (0, _chunkA74IFAVZcjs.Receiver)({
|
|
24
24
|
currentSigningKey,
|
|
25
25
|
nextSigningKey
|
|
26
26
|
});
|
|
27
|
-
return (req, res) => __async(this, null, function* () {
|
|
27
|
+
return (req, res) => _chunkA74IFAVZcjs.__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 = __forAwait(req), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
|
|
40
|
+
for (var iter = _chunkA74IFAVZcjs.__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,15 +89,15 @@ 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 Receiver({
|
|
92
|
+
const receiver = new (0, _chunkA74IFAVZcjs.Receiver)({
|
|
93
93
|
currentSigningKey,
|
|
94
94
|
nextSigningKey
|
|
95
95
|
});
|
|
96
|
-
return (req, nfe) => __async(this, null, function* () {
|
|
96
|
+
return (req, nfe) => _chunkA74IFAVZcjs.__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) {
|
|
100
|
-
return new NextResponse(new TextEncoder().encode("`Upstash-Signature` header is missing"), {
|
|
100
|
+
return new (0, _server.NextResponse)(new TextEncoder().encode("`Upstash-Signature` header is missing"), {
|
|
101
101
|
status: 403
|
|
102
102
|
});
|
|
103
103
|
}
|
|
@@ -111,7 +111,7 @@ function verifySignatureEdge(handler, config) {
|
|
|
111
111
|
clockTolerance: config == null ? void 0 : config.clockTolerance
|
|
112
112
|
});
|
|
113
113
|
if (!isValid) {
|
|
114
|
-
return new NextResponse(new TextEncoder().encode("invalid signature"), { status: 403 });
|
|
114
|
+
return new (0, _server.NextResponse)(new TextEncoder().encode("invalid signature"), { status: 403 });
|
|
115
115
|
}
|
|
116
116
|
let parsedBody = void 0;
|
|
117
117
|
try {
|
|
@@ -126,8 +126,8 @@ function verifySignatureEdge(handler, config) {
|
|
|
126
126
|
return handler(reqClone, nfe);
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//# sourceMappingURL=nextjs.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
exports.verifySignature = verifySignature; exports.verifySignatureEdge = verifySignatureEdge;
|
|
133
|
+
//# sourceMappingURL=nextjs.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/nextjs.ts"],"names":[],"mappings":";;;;;;;AACA,SAAsC,oBAAoB;AAsBnD,SAAS,gBACd,SACA,QACgB;AA1BlB;AA2BE,QAAM,qBAAoB,sCAAQ,sBAAR,YAA6B,QAAQ,IAAI;AACnE,MAAI,CAAC,mBAAmB;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,kBAAiB,sCAAQ,mBAAR,YAA0B,QAAQ,IAAI;AAC7D,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,IAAI,SAAS;AAAA,IAC5B;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,CAAO,KAAqB,QAAyB;AAE1D,UAAM,YAAY,IAAI,QAAQ,mBAAmB;AACjD,QAAI,CAAC,WAAW;AACd,UAAI,OAAO,GAAG;AACd,UAAI,KAAK,uCAAuC;AAChD,UAAI,IAAI;AACR;AAAA,IACF;AACA,QAAI,OAAO,cAAc,UAAU;AACjC,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,SAAS,CAAC;AAChB;AAAA,iCAA0B,MAA1B,0EAA+B;AAApB,cAAM,QAAjB;AAEE,eAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,MACpE;AAAA,aAHA,MA1DJ;AA0DI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,UAAM,OAAO,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO;AAEnD,UAAM,UAAU,MAAM,SAAS,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA,gBAAgB,iCAAQ;AAAA,IAC1B,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,UAAI,OAAO,GAAG;AACd,UAAI,KAAK,mBAAmB;AAC5B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,QAAI;AACF,UAAI,IAAI,QAAQ,cAAc,MAAM,oBAAoB;AACtD,YAAI,OAAO,KAAK,MAAM,IAAI;AAAA,MAC5B,OAAO;AACL,YAAI,OAAO;AAAA,MACb;AAAA,IACF,SAAQ;AACN,UAAI,OAAO;AAAA,IACb;AAEA,WAAO,QAAQ,KAAK,GAAG;AAAA,EACzB;AACF;AAEO,SAAS,oBACd,SACA,QACA;AA7FF;AA8FE,QAAM,qBAAoB,sCAAQ,sBAAR,YAA6B,QAAQ,IAAI;AACnE,MAAI,CAAC,mBAAmB;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,kBAAiB,sCAAQ,mBAAR,YAA0B,QAAQ,IAAI;AAC7D,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,IAAI,SAAS;AAAA,IAC5B;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,CAAO,KAAkB,QAAwB;AACtD,UAAM,WAAW,IAAI,MAAM;AAE3B,UAAM,YAAY,IAAI,QAAQ,IAAI,mBAAmB;AACrD,QAAI,CAAC,WAAW;AACd,aAAO,IAAI,aAAa,IAAI,YAAY,EAAE,OAAO,uCAAuC,GAAG;AAAA,QACzF,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,QAAI,OAAO,cAAc,UAAU;AACjC,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,UAAU,MAAM,SAAS,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA,gBAAgB,iCAAQ;AAAA,IAC1B,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,aAAO,IAAI,aAAa,IAAI,YAAY,EAAE,OAAO,mBAAmB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACxF;AAEA,QAAI,aAAsB;AAE1B,QAAI;AACF,UAAI,IAAI,QAAQ,IAAI,cAAc,MAAM,oBAAoB;AAC1D,qBAAa,KAAK,MAAM,IAAI;AAAA,MAC9B,OAAO;AACL,qBAAa;AAAA,MACf;AAAA,IACF,SAAQ;AACN,mBAAa;AAAA,IACf;AAEA,WAAO,QAAQ,UAAU,GAAG;AAAA,EAC9B;AACF","sourcesContent":["import type { NextApiHandler, NextApiRequest, NextApiResponse } from \"next\";\nimport { NextRequest, NextFetchEvent, NextResponse } from \"next/server\";\nimport { Receiver } from \"./receiver\";\n\nexport type VerifySignaturConfig = {\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?: VerifySignaturConfig,\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?: VerifySignaturConfig,\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"]}
|
package/dist/nextjs.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
Receiver,
|
|
3
|
+
__async,
|
|
4
|
+
__forAwait
|
|
5
|
+
} from "./chunk-EQTYEU4U.js";
|
|
6
6
|
|
|
7
7
|
// src/nextjs.ts
|
|
8
|
-
|
|
8
|
+
import { NextResponse } from "next/server";
|
|
9
9
|
function verifySignature(handler, config) {
|
|
10
10
|
var _a, _b;
|
|
11
11
|
const currentSigningKey = (_a = config == null ? void 0 : config.currentSigningKey) != null ? _a : process.env.QSTASH_CURRENT_SIGNING_KEY;
|
|
@@ -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
|
|
23
|
+
const receiver = new Receiver({
|
|
24
24
|
currentSigningKey,
|
|
25
25
|
nextSigningKey
|
|
26
26
|
});
|
|
27
|
-
return (req, res) =>
|
|
27
|
+
return (req, res) => __async(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 =
|
|
40
|
+
for (var iter = __forAwait(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,15 +89,15 @@ 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
|
|
92
|
+
const receiver = new Receiver({
|
|
93
93
|
currentSigningKey,
|
|
94
94
|
nextSigningKey
|
|
95
95
|
});
|
|
96
|
-
return (req, nfe) =>
|
|
96
|
+
return (req, nfe) => __async(this, null, function* () {
|
|
97
97
|
const reqClone = req.clone();
|
|
98
98
|
const signature = req.headers.get("upstash-signature");
|
|
99
99
|
if (!signature) {
|
|
100
|
-
return new
|
|
100
|
+
return new NextResponse(new TextEncoder().encode("`Upstash-Signature` header is missing"), {
|
|
101
101
|
status: 403
|
|
102
102
|
});
|
|
103
103
|
}
|
|
@@ -111,7 +111,7 @@ function verifySignatureEdge(handler, config) {
|
|
|
111
111
|
clockTolerance: config == null ? void 0 : config.clockTolerance
|
|
112
112
|
});
|
|
113
113
|
if (!isValid) {
|
|
114
|
-
return new
|
|
114
|
+
return new NextResponse(new TextEncoder().encode("invalid signature"), { status: 403 });
|
|
115
115
|
}
|
|
116
116
|
let parsedBody = void 0;
|
|
117
117
|
try {
|
|
@@ -126,8 +126,8 @@ function verifySignatureEdge(handler, config) {
|
|
|
126
126
|
return handler(reqClone, nfe);
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
export {
|
|
130
|
+
verifySignature,
|
|
131
|
+
verifySignatureEdge
|
|
132
|
+
};
|
|
133
133
|
//# sourceMappingURL=nextjs.js.map
|
package/dist/nextjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/nextjs.ts"],"
|
|
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 VerifySignaturConfig = {\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?: VerifySignaturConfig,\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?: VerifySignaturConfig,\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":[]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upstash/qstash",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1-canary.1",
|
|
4
4
|
"description": "Official Typescript client for QStash",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/upstash/sdk-qstash-ts.git"
|
|
8
8
|
},
|
|
9
|
-
"module": "./dist/index.
|
|
9
|
+
"module": "./dist/index.mjs",
|
|
10
10
|
"main": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"keywords": [
|
|
@@ -37,16 +37,27 @@
|
|
|
37
37
|
"crypto-js": "^4.1.1",
|
|
38
38
|
"jose": "^4.14.4"
|
|
39
39
|
},
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"import:": "./dist/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./nextjs": {
|
|
46
|
+
"types": "./dist/nextjs.d.ts",
|
|
47
|
+
"import:": "./dist/nextjs.js"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
40
50
|
"typesVersions": {
|
|
41
51
|
"*": {
|
|
42
52
|
".": [
|
|
43
53
|
"./dist/index.d.ts"
|
|
44
54
|
],
|
|
45
|
-
"nextjs": [
|
|
55
|
+
"./nextjs": [
|
|
46
56
|
"./dist/nextjs.d.ts"
|
|
47
57
|
]
|
|
48
58
|
}
|
|
49
59
|
},
|
|
60
|
+
"type": "module",
|
|
50
61
|
"scripts": {
|
|
51
62
|
"build": "tsup",
|
|
52
63
|
"fmt": "pnpm rome check . --apply-unsafe && pnpm rome format . --write"
|
|
@@ -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.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"sourcesContent":["/**\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","import { QstashError } 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};\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\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\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<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\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 });\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 crated.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: 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 });\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};\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 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 * 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 * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\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 return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\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 });\n }\n}\n","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(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\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\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\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 * 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 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":"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","names":[]}
|
package/dist/nextjs.mjs.map
DELETED
|
@@ -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 VerifySignaturConfig = {\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?: VerifySignaturConfig,\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?: VerifySignaturConfig,\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":[]}
|
|
File without changes
|
|
File without changes
|