@upstash/ratelimit 1.1.3 → 1.2.0-canary
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +118 -8
- package/dist/index.d.ts +118 -8
- package/dist/index.js +343 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +343 -90
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -14,15 +14,23 @@ interface EphemeralCache {
|
|
|
14
14
|
incr: (key: string) => number;
|
|
15
15
|
pop: (key: string) => void;
|
|
16
16
|
empty: () => void;
|
|
17
|
+
size: () => number;
|
|
17
18
|
}
|
|
18
19
|
type RegionContext = {
|
|
19
20
|
redis: Redis;
|
|
20
21
|
cache?: EphemeralCache;
|
|
22
|
+
scriptHashes: {
|
|
23
|
+
limitHash?: string;
|
|
24
|
+
getRemainingHash?: string;
|
|
25
|
+
resetHash?: string;
|
|
26
|
+
};
|
|
27
|
+
cacheScripts: boolean;
|
|
21
28
|
};
|
|
22
29
|
type MultiRegionContext = {
|
|
23
|
-
|
|
30
|
+
regionContexts: Omit<RegionContext[], "cache">;
|
|
24
31
|
cache?: EphemeralCache;
|
|
25
32
|
};
|
|
33
|
+
type RatelimitResponseType = "timeout" | "cacheBlock" | "denyList";
|
|
26
34
|
type Context = RegionContext | MultiRegionContext;
|
|
27
35
|
type RatelimitResponse = {
|
|
28
36
|
/**
|
|
@@ -60,13 +68,37 @@ type RatelimitResponse = {
|
|
|
60
68
|
* ```
|
|
61
69
|
*/
|
|
62
70
|
pending: Promise<unknown>;
|
|
71
|
+
/**
|
|
72
|
+
* Reason behind the result in `success` field.
|
|
73
|
+
* - Is set to "timeout" when request times out
|
|
74
|
+
* - Is set to "cacheBlock" when an identifier is blocked through cache without calling redis because it was
|
|
75
|
+
* rate limited previously.
|
|
76
|
+
* - Is set to "denyList" when identifier or one of ip/user-agent/country parameters is in deny list. To enable
|
|
77
|
+
* deny list, see `enableProtection` parameter. To edit the deny list, see the Upstash Ratelimit Dashboard
|
|
78
|
+
* at https://console.upstash.com/ratelimit.
|
|
79
|
+
* - Is set to undefined if rate limit check had to use Redis. This happens in cases when `success` field in
|
|
80
|
+
* the response is true. It can also happen the first time sucecss is false.
|
|
81
|
+
*/
|
|
82
|
+
reason?: RatelimitResponseType;
|
|
83
|
+
/**
|
|
84
|
+
* The value which was in the deny list if reason: "denyList"
|
|
85
|
+
*/
|
|
86
|
+
deniedValue?: string;
|
|
63
87
|
};
|
|
64
88
|
type Algorithm<TContext> = () => {
|
|
65
89
|
limit: (ctx: TContext, identifier: string, rate?: number, opts?: {
|
|
66
90
|
cache?: EphemeralCache;
|
|
67
91
|
}) => Promise<RatelimitResponse>;
|
|
68
92
|
getRemaining: (ctx: TContext, identifier: string) => Promise<number>;
|
|
69
|
-
resetTokens: (ctx: TContext, identifier: string) => void
|
|
93
|
+
resetTokens: (ctx: TContext, identifier: string) => Promise<void>;
|
|
94
|
+
};
|
|
95
|
+
type IsDenied = 0 | 1;
|
|
96
|
+
type LimitOptions = {
|
|
97
|
+
geo?: Geo;
|
|
98
|
+
rate?: number;
|
|
99
|
+
ip?: string;
|
|
100
|
+
userAgent?: string;
|
|
101
|
+
country?: string;
|
|
70
102
|
};
|
|
71
103
|
/**
|
|
72
104
|
* This is all we need from the redis sdk.
|
|
@@ -77,6 +109,9 @@ interface Redis {
|
|
|
77
109
|
[key: string]: TValue;
|
|
78
110
|
}) => Promise<number>;
|
|
79
111
|
eval: <TArgs extends unknown[], TData = unknown>(...args: [script: string, keys: string[], args: TArgs]) => Promise<TData>;
|
|
112
|
+
evalsha: <TArgs extends unknown[], TData = unknown>(...args: [sha1: string, keys: string[], args: TArgs]) => Promise<TData>;
|
|
113
|
+
scriptLoad: (...args: [script: string]) => Promise<string>;
|
|
114
|
+
smismember: (key: string, members: string[]) => Promise<IsDenied[]>;
|
|
80
115
|
}
|
|
81
116
|
|
|
82
117
|
type Geo = {
|
|
@@ -85,10 +120,16 @@ type Geo = {
|
|
|
85
120
|
region?: string;
|
|
86
121
|
ip?: string;
|
|
87
122
|
};
|
|
123
|
+
/**
|
|
124
|
+
* denotes the success field in the analytics submission.
|
|
125
|
+
* Set to true when ratelimit check passes. False when request is ratelimited.
|
|
126
|
+
* Set to "denied" when some request value is in deny list.
|
|
127
|
+
*/
|
|
128
|
+
type EventSuccess = boolean | "denied";
|
|
88
129
|
type Event = Geo & {
|
|
89
130
|
identifier: string;
|
|
90
131
|
time: number;
|
|
91
|
-
success:
|
|
132
|
+
success: EventSuccess;
|
|
92
133
|
};
|
|
93
134
|
type AnalyticsConfig = {
|
|
94
135
|
redis: Redis;
|
|
@@ -124,7 +165,11 @@ declare class Analytics {
|
|
|
124
165
|
identifier: string;
|
|
125
166
|
count: number;
|
|
126
167
|
}[];
|
|
127
|
-
|
|
168
|
+
ratelimited: {
|
|
169
|
+
identifier: string;
|
|
170
|
+
count: number;
|
|
171
|
+
}[];
|
|
172
|
+
denied: {
|
|
128
173
|
identifier: string;
|
|
129
174
|
count: number;
|
|
130
175
|
}[];
|
|
@@ -184,6 +229,14 @@ type RatelimitConfig<TContext> = {
|
|
|
184
229
|
* @default false
|
|
185
230
|
*/
|
|
186
231
|
analytics?: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Enables deny list. If set to true, requests with identifier or ip/user-agent/countrie
|
|
234
|
+
* in the deny list will be rejected automatically. To edit the deny list, check out the
|
|
235
|
+
* ratelimit dashboard at https://console.upstash.com/ratelimit
|
|
236
|
+
*
|
|
237
|
+
* @default false
|
|
238
|
+
*/
|
|
239
|
+
enableProtection?: boolean;
|
|
187
240
|
};
|
|
188
241
|
/**
|
|
189
242
|
* Ratelimiter using serverless redis from https://upstash.com/
|
|
@@ -205,7 +258,9 @@ declare abstract class Ratelimit<TContext extends Context> {
|
|
|
205
258
|
protected readonly ctx: TContext;
|
|
206
259
|
protected readonly prefix: string;
|
|
207
260
|
protected readonly timeout: number;
|
|
261
|
+
protected readonly primaryRedis: Redis;
|
|
208
262
|
protected readonly analytics?: Analytics;
|
|
263
|
+
protected readonly enableProtection: boolean;
|
|
209
264
|
constructor(config: RatelimitConfig<TContext>);
|
|
210
265
|
/**
|
|
211
266
|
* Determine if a request should pass or be rejected based on the identifier and previously chosen ratelimit.
|
|
@@ -243,10 +298,7 @@ declare abstract class Ratelimit<TContext extends Context> {
|
|
|
243
298
|
* return "Yes"
|
|
244
299
|
* ```
|
|
245
300
|
*/
|
|
246
|
-
limit: (identifier: string, req?:
|
|
247
|
-
geo?: Geo;
|
|
248
|
-
rate?: number;
|
|
249
|
-
}) => Promise<RatelimitResponse>;
|
|
301
|
+
limit: (identifier: string, req?: LimitOptions) => Promise<RatelimitResponse>;
|
|
250
302
|
/**
|
|
251
303
|
* Block until the request may pass or timeout is reached.
|
|
252
304
|
*
|
|
@@ -272,6 +324,46 @@ declare abstract class Ratelimit<TContext extends Context> {
|
|
|
272
324
|
blockUntilReady: (identifier: string, timeout: number) => Promise<RatelimitResponse>;
|
|
273
325
|
resetUsedTokens: (identifier: string) => Promise<void>;
|
|
274
326
|
getRemaining: (identifier: string) => Promise<number>;
|
|
327
|
+
/**
|
|
328
|
+
* Checks if the identifier or the values in req are in the deny list cache.
|
|
329
|
+
* If so, returns the default denied response.
|
|
330
|
+
*
|
|
331
|
+
* Otherwise, calls redis to check the rate limit and deny list. Returns after
|
|
332
|
+
* resolving the result. Resolving is overriding the rate limit result if
|
|
333
|
+
* the some value is in deny list.
|
|
334
|
+
*
|
|
335
|
+
* @param identifier identifier to block
|
|
336
|
+
* @param req options with ip, user agent, country, rate and geo info
|
|
337
|
+
* @returns rate limit response
|
|
338
|
+
*/
|
|
339
|
+
private getRatelimitResponse;
|
|
340
|
+
/**
|
|
341
|
+
* Creates an array with the original response promise and a timeout promise
|
|
342
|
+
* if this.timeout > 0.
|
|
343
|
+
*
|
|
344
|
+
* @param response Ratelimit response promise
|
|
345
|
+
* @returns array with the response and timeout promise. also includes the timeout id
|
|
346
|
+
*/
|
|
347
|
+
private applyTimeout;
|
|
348
|
+
/**
|
|
349
|
+
* submits analytics if this.analytics is set
|
|
350
|
+
*
|
|
351
|
+
* @param ratelimitResponse final rate limit response
|
|
352
|
+
* @param identifier identifier to submit
|
|
353
|
+
* @param req limit options
|
|
354
|
+
* @returns rate limit response after updating the .pending field
|
|
355
|
+
*/
|
|
356
|
+
private submitAnalytics;
|
|
357
|
+
private getKey;
|
|
358
|
+
/**
|
|
359
|
+
* returns a list of defined values from
|
|
360
|
+
* [identifier, req.ip, req.userAgent, req.country]
|
|
361
|
+
*
|
|
362
|
+
* @param identifier identifier
|
|
363
|
+
* @param req limit options
|
|
364
|
+
* @returns list of defined values
|
|
365
|
+
*/
|
|
366
|
+
private getDefinedMembers;
|
|
275
367
|
}
|
|
276
368
|
|
|
277
369
|
type MultiRegionRatelimitConfig = {
|
|
@@ -324,6 +416,13 @@ type MultiRegionRatelimitConfig = {
|
|
|
324
416
|
* @default false
|
|
325
417
|
*/
|
|
326
418
|
analytics?: boolean;
|
|
419
|
+
/**
|
|
420
|
+
* If enabled, lua scripts will be sent to Redis with SCRIPT LOAD durint the first request.
|
|
421
|
+
* In the subsequent requests, hash of the script will be used to invoke it
|
|
422
|
+
*
|
|
423
|
+
* @default true
|
|
424
|
+
*/
|
|
425
|
+
cacheScripts?: boolean;
|
|
327
426
|
};
|
|
328
427
|
/**
|
|
329
428
|
* Ratelimiter using serverless redis from https://upstash.com/
|
|
@@ -451,6 +550,17 @@ type RegionRatelimitConfig = {
|
|
|
451
550
|
* @default false
|
|
452
551
|
*/
|
|
453
552
|
analytics?: boolean;
|
|
553
|
+
/**
|
|
554
|
+
* If enabled, lua scripts will be sent to Redis with SCRIPT LOAD durint the first request.
|
|
555
|
+
* In the subsequent requests, hash of the script will be used to invoke it
|
|
556
|
+
*
|
|
557
|
+
* @default true
|
|
558
|
+
*/
|
|
559
|
+
cacheScripts?: boolean;
|
|
560
|
+
/**
|
|
561
|
+
* @default false
|
|
562
|
+
*/
|
|
563
|
+
enableProtection?: boolean;
|
|
454
564
|
};
|
|
455
565
|
/**
|
|
456
566
|
* Ratelimiter using serverless redis from https://upstash.com/
|
package/dist/index.d.ts
CHANGED
|
@@ -14,15 +14,23 @@ interface EphemeralCache {
|
|
|
14
14
|
incr: (key: string) => number;
|
|
15
15
|
pop: (key: string) => void;
|
|
16
16
|
empty: () => void;
|
|
17
|
+
size: () => number;
|
|
17
18
|
}
|
|
18
19
|
type RegionContext = {
|
|
19
20
|
redis: Redis;
|
|
20
21
|
cache?: EphemeralCache;
|
|
22
|
+
scriptHashes: {
|
|
23
|
+
limitHash?: string;
|
|
24
|
+
getRemainingHash?: string;
|
|
25
|
+
resetHash?: string;
|
|
26
|
+
};
|
|
27
|
+
cacheScripts: boolean;
|
|
21
28
|
};
|
|
22
29
|
type MultiRegionContext = {
|
|
23
|
-
|
|
30
|
+
regionContexts: Omit<RegionContext[], "cache">;
|
|
24
31
|
cache?: EphemeralCache;
|
|
25
32
|
};
|
|
33
|
+
type RatelimitResponseType = "timeout" | "cacheBlock" | "denyList";
|
|
26
34
|
type Context = RegionContext | MultiRegionContext;
|
|
27
35
|
type RatelimitResponse = {
|
|
28
36
|
/**
|
|
@@ -60,13 +68,37 @@ type RatelimitResponse = {
|
|
|
60
68
|
* ```
|
|
61
69
|
*/
|
|
62
70
|
pending: Promise<unknown>;
|
|
71
|
+
/**
|
|
72
|
+
* Reason behind the result in `success` field.
|
|
73
|
+
* - Is set to "timeout" when request times out
|
|
74
|
+
* - Is set to "cacheBlock" when an identifier is blocked through cache without calling redis because it was
|
|
75
|
+
* rate limited previously.
|
|
76
|
+
* - Is set to "denyList" when identifier or one of ip/user-agent/country parameters is in deny list. To enable
|
|
77
|
+
* deny list, see `enableProtection` parameter. To edit the deny list, see the Upstash Ratelimit Dashboard
|
|
78
|
+
* at https://console.upstash.com/ratelimit.
|
|
79
|
+
* - Is set to undefined if rate limit check had to use Redis. This happens in cases when `success` field in
|
|
80
|
+
* the response is true. It can also happen the first time sucecss is false.
|
|
81
|
+
*/
|
|
82
|
+
reason?: RatelimitResponseType;
|
|
83
|
+
/**
|
|
84
|
+
* The value which was in the deny list if reason: "denyList"
|
|
85
|
+
*/
|
|
86
|
+
deniedValue?: string;
|
|
63
87
|
};
|
|
64
88
|
type Algorithm<TContext> = () => {
|
|
65
89
|
limit: (ctx: TContext, identifier: string, rate?: number, opts?: {
|
|
66
90
|
cache?: EphemeralCache;
|
|
67
91
|
}) => Promise<RatelimitResponse>;
|
|
68
92
|
getRemaining: (ctx: TContext, identifier: string) => Promise<number>;
|
|
69
|
-
resetTokens: (ctx: TContext, identifier: string) => void
|
|
93
|
+
resetTokens: (ctx: TContext, identifier: string) => Promise<void>;
|
|
94
|
+
};
|
|
95
|
+
type IsDenied = 0 | 1;
|
|
96
|
+
type LimitOptions = {
|
|
97
|
+
geo?: Geo;
|
|
98
|
+
rate?: number;
|
|
99
|
+
ip?: string;
|
|
100
|
+
userAgent?: string;
|
|
101
|
+
country?: string;
|
|
70
102
|
};
|
|
71
103
|
/**
|
|
72
104
|
* This is all we need from the redis sdk.
|
|
@@ -77,6 +109,9 @@ interface Redis {
|
|
|
77
109
|
[key: string]: TValue;
|
|
78
110
|
}) => Promise<number>;
|
|
79
111
|
eval: <TArgs extends unknown[], TData = unknown>(...args: [script: string, keys: string[], args: TArgs]) => Promise<TData>;
|
|
112
|
+
evalsha: <TArgs extends unknown[], TData = unknown>(...args: [sha1: string, keys: string[], args: TArgs]) => Promise<TData>;
|
|
113
|
+
scriptLoad: (...args: [script: string]) => Promise<string>;
|
|
114
|
+
smismember: (key: string, members: string[]) => Promise<IsDenied[]>;
|
|
80
115
|
}
|
|
81
116
|
|
|
82
117
|
type Geo = {
|
|
@@ -85,10 +120,16 @@ type Geo = {
|
|
|
85
120
|
region?: string;
|
|
86
121
|
ip?: string;
|
|
87
122
|
};
|
|
123
|
+
/**
|
|
124
|
+
* denotes the success field in the analytics submission.
|
|
125
|
+
* Set to true when ratelimit check passes. False when request is ratelimited.
|
|
126
|
+
* Set to "denied" when some request value is in deny list.
|
|
127
|
+
*/
|
|
128
|
+
type EventSuccess = boolean | "denied";
|
|
88
129
|
type Event = Geo & {
|
|
89
130
|
identifier: string;
|
|
90
131
|
time: number;
|
|
91
|
-
success:
|
|
132
|
+
success: EventSuccess;
|
|
92
133
|
};
|
|
93
134
|
type AnalyticsConfig = {
|
|
94
135
|
redis: Redis;
|
|
@@ -124,7 +165,11 @@ declare class Analytics {
|
|
|
124
165
|
identifier: string;
|
|
125
166
|
count: number;
|
|
126
167
|
}[];
|
|
127
|
-
|
|
168
|
+
ratelimited: {
|
|
169
|
+
identifier: string;
|
|
170
|
+
count: number;
|
|
171
|
+
}[];
|
|
172
|
+
denied: {
|
|
128
173
|
identifier: string;
|
|
129
174
|
count: number;
|
|
130
175
|
}[];
|
|
@@ -184,6 +229,14 @@ type RatelimitConfig<TContext> = {
|
|
|
184
229
|
* @default false
|
|
185
230
|
*/
|
|
186
231
|
analytics?: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Enables deny list. If set to true, requests with identifier or ip/user-agent/countrie
|
|
234
|
+
* in the deny list will be rejected automatically. To edit the deny list, check out the
|
|
235
|
+
* ratelimit dashboard at https://console.upstash.com/ratelimit
|
|
236
|
+
*
|
|
237
|
+
* @default false
|
|
238
|
+
*/
|
|
239
|
+
enableProtection?: boolean;
|
|
187
240
|
};
|
|
188
241
|
/**
|
|
189
242
|
* Ratelimiter using serverless redis from https://upstash.com/
|
|
@@ -205,7 +258,9 @@ declare abstract class Ratelimit<TContext extends Context> {
|
|
|
205
258
|
protected readonly ctx: TContext;
|
|
206
259
|
protected readonly prefix: string;
|
|
207
260
|
protected readonly timeout: number;
|
|
261
|
+
protected readonly primaryRedis: Redis;
|
|
208
262
|
protected readonly analytics?: Analytics;
|
|
263
|
+
protected readonly enableProtection: boolean;
|
|
209
264
|
constructor(config: RatelimitConfig<TContext>);
|
|
210
265
|
/**
|
|
211
266
|
* Determine if a request should pass or be rejected based on the identifier and previously chosen ratelimit.
|
|
@@ -243,10 +298,7 @@ declare abstract class Ratelimit<TContext extends Context> {
|
|
|
243
298
|
* return "Yes"
|
|
244
299
|
* ```
|
|
245
300
|
*/
|
|
246
|
-
limit: (identifier: string, req?:
|
|
247
|
-
geo?: Geo;
|
|
248
|
-
rate?: number;
|
|
249
|
-
}) => Promise<RatelimitResponse>;
|
|
301
|
+
limit: (identifier: string, req?: LimitOptions) => Promise<RatelimitResponse>;
|
|
250
302
|
/**
|
|
251
303
|
* Block until the request may pass or timeout is reached.
|
|
252
304
|
*
|
|
@@ -272,6 +324,46 @@ declare abstract class Ratelimit<TContext extends Context> {
|
|
|
272
324
|
blockUntilReady: (identifier: string, timeout: number) => Promise<RatelimitResponse>;
|
|
273
325
|
resetUsedTokens: (identifier: string) => Promise<void>;
|
|
274
326
|
getRemaining: (identifier: string) => Promise<number>;
|
|
327
|
+
/**
|
|
328
|
+
* Checks if the identifier or the values in req are in the deny list cache.
|
|
329
|
+
* If so, returns the default denied response.
|
|
330
|
+
*
|
|
331
|
+
* Otherwise, calls redis to check the rate limit and deny list. Returns after
|
|
332
|
+
* resolving the result. Resolving is overriding the rate limit result if
|
|
333
|
+
* the some value is in deny list.
|
|
334
|
+
*
|
|
335
|
+
* @param identifier identifier to block
|
|
336
|
+
* @param req options with ip, user agent, country, rate and geo info
|
|
337
|
+
* @returns rate limit response
|
|
338
|
+
*/
|
|
339
|
+
private getRatelimitResponse;
|
|
340
|
+
/**
|
|
341
|
+
* Creates an array with the original response promise and a timeout promise
|
|
342
|
+
* if this.timeout > 0.
|
|
343
|
+
*
|
|
344
|
+
* @param response Ratelimit response promise
|
|
345
|
+
* @returns array with the response and timeout promise. also includes the timeout id
|
|
346
|
+
*/
|
|
347
|
+
private applyTimeout;
|
|
348
|
+
/**
|
|
349
|
+
* submits analytics if this.analytics is set
|
|
350
|
+
*
|
|
351
|
+
* @param ratelimitResponse final rate limit response
|
|
352
|
+
* @param identifier identifier to submit
|
|
353
|
+
* @param req limit options
|
|
354
|
+
* @returns rate limit response after updating the .pending field
|
|
355
|
+
*/
|
|
356
|
+
private submitAnalytics;
|
|
357
|
+
private getKey;
|
|
358
|
+
/**
|
|
359
|
+
* returns a list of defined values from
|
|
360
|
+
* [identifier, req.ip, req.userAgent, req.country]
|
|
361
|
+
*
|
|
362
|
+
* @param identifier identifier
|
|
363
|
+
* @param req limit options
|
|
364
|
+
* @returns list of defined values
|
|
365
|
+
*/
|
|
366
|
+
private getDefinedMembers;
|
|
275
367
|
}
|
|
276
368
|
|
|
277
369
|
type MultiRegionRatelimitConfig = {
|
|
@@ -324,6 +416,13 @@ type MultiRegionRatelimitConfig = {
|
|
|
324
416
|
* @default false
|
|
325
417
|
*/
|
|
326
418
|
analytics?: boolean;
|
|
419
|
+
/**
|
|
420
|
+
* If enabled, lua scripts will be sent to Redis with SCRIPT LOAD durint the first request.
|
|
421
|
+
* In the subsequent requests, hash of the script will be used to invoke it
|
|
422
|
+
*
|
|
423
|
+
* @default true
|
|
424
|
+
*/
|
|
425
|
+
cacheScripts?: boolean;
|
|
327
426
|
};
|
|
328
427
|
/**
|
|
329
428
|
* Ratelimiter using serverless redis from https://upstash.com/
|
|
@@ -451,6 +550,17 @@ type RegionRatelimitConfig = {
|
|
|
451
550
|
* @default false
|
|
452
551
|
*/
|
|
453
552
|
analytics?: boolean;
|
|
553
|
+
/**
|
|
554
|
+
* If enabled, lua scripts will be sent to Redis with SCRIPT LOAD durint the first request.
|
|
555
|
+
* In the subsequent requests, hash of the script will be used to invoke it
|
|
556
|
+
*
|
|
557
|
+
* @default true
|
|
558
|
+
*/
|
|
559
|
+
cacheScripts?: boolean;
|
|
560
|
+
/**
|
|
561
|
+
* @default false
|
|
562
|
+
*/
|
|
563
|
+
enableProtection?: boolean;
|
|
454
564
|
};
|
|
455
565
|
/**
|
|
456
566
|
* Ratelimiter using serverless redis from https://upstash.com/
|