@upstash/ratelimit 1.1.2 → 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/README.md +19 -76
- package/dist/index.d.mts +118 -8
- package/dist/index.d.ts +118 -8
- package/dist/index.js +347 -78
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +347 -78
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Upstash Rate Limit
|
|
2
2
|
|
|
3
|
-
[](https://github.com/upstash/ratelimit/actions/workflows/tests.yaml)
|
|
4
3
|
[](https://www.npmjs.com/package/@upstash/ratelimit)
|
|
4
|
+
[](https://github.com/upstash/ratelimit/actions/workflows/tests.yaml)
|
|
5
5
|
|
|
6
6
|
> [!NOTE] > **This project is in GA Stage.**
|
|
7
7
|
> The Upstash Professional Support fully covers this project. It receives regular updates, and bug fixes. The Upstash team is committed to maintaining and improving its functionality.
|
|
@@ -69,84 +69,13 @@ doExpensiveCalculation();
|
|
|
69
69
|
return "Here you go!";
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
For
|
|
73
|
-
|
|
74
|
-
```ts
|
|
75
|
-
import { Redis } from "@upstash/redis/cloudflare"; // for cloudflare workers and pages
|
|
76
|
-
import { Redis } from "@upstash/redis/fastly"; // for fastly compute@edge
|
|
77
|
-
```
|
|
72
|
+
For more information on getting started, you can refer to [our documentation](https://upstash.com/docs/oss/sdks/ts/ratelimit/gettingstarted).
|
|
78
73
|
|
|
79
74
|
[Here's a complete nextjs example](https://github.com/upstash/ratelimit/tree/main/examples/nextjs)
|
|
80
75
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
````ts
|
|
84
|
-
export type RatelimitResponse = {
|
|
85
|
-
/**
|
|
86
|
-
* Whether the request may pass(true) or exceeded the limit(false)
|
|
87
|
-
*/
|
|
88
|
-
success: boolean;
|
|
89
|
-
/**
|
|
90
|
-
* Maximum number of requests allowed within a window.
|
|
91
|
-
*/
|
|
92
|
-
limit: number;
|
|
93
|
-
/**
|
|
94
|
-
* How many requests the user has left within the current window.
|
|
95
|
-
*/
|
|
96
|
-
remaining: number;
|
|
97
|
-
/**
|
|
98
|
-
* Unix timestamp in milliseconds when the limits are reset.
|
|
99
|
-
*/
|
|
100
|
-
reset: number;
|
|
76
|
+
## Documentation
|
|
101
77
|
|
|
102
|
-
|
|
103
|
-
* For the MultiRegion setup we do some synchronizing in the background, after returning the current limit.
|
|
104
|
-
* Or when analytics is enabled, we send the analytics asynchronously after returning the limit.
|
|
105
|
-
* In most case you can simply ignore this.
|
|
106
|
-
*
|
|
107
|
-
* On Vercel Edge or Cloudflare workers, you need to explicitly handle the pending Promise like this:
|
|
108
|
-
*
|
|
109
|
-
* ```ts
|
|
110
|
-
* const { pending } = await ratelimit.limit("id")
|
|
111
|
-
* context.waitUntil(pending)
|
|
112
|
-
* ```
|
|
113
|
-
*
|
|
114
|
-
* See `waitUntil` documentation in
|
|
115
|
-
* [Cloudflare](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil)
|
|
116
|
-
* and [Vercel](https://vercel.com/docs/functions/edge-middleware/middleware-api#waituntil)
|
|
117
|
-
* for more details.
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
pending: Promise<unknown>;
|
|
121
|
-
};
|
|
122
|
-
````
|
|
123
|
-
|
|
124
|
-
### Docs
|
|
125
|
-
|
|
126
|
-
See [the documentation](https://upstash.com/docs/oss/sdks/ts/ratelimit/overview) for more information details.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
### Using with CloudFlare Workers and Vercel Edge
|
|
130
|
-
|
|
131
|
-
When we use CloudFlare Workers and Vercel Edge, we need to be careful about
|
|
132
|
-
making sure that the rate limiting operations complete correctly before the runtime ends
|
|
133
|
-
after returning the response.
|
|
134
|
-
|
|
135
|
-
This is important in two cases where we do some operations in the backgroung asynchronously after `limit` is called:
|
|
136
|
-
|
|
137
|
-
1. Using MultiRegion: synchronize Redis instances in different regions
|
|
138
|
-
2. Enabling analytics: send analytics to Redis
|
|
139
|
-
|
|
140
|
-
In these cases, we need to wait for these operations to finish before sending the response to the user. Otherwise, the runtime will end and we won't be able to complete our chores.
|
|
141
|
-
|
|
142
|
-
In order to wait for these operations to finish, use the `pending` promise:
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
const { pending } = await ratelimit.limit("id");
|
|
146
|
-
context.waitUntil(pending);
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
See `waitUntil` documentation in [Cloudflare](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil) and [Vercel](https://vercel.com/docs/functions/edge-middleware/middleware-api#waituntil) for more details.
|
|
78
|
+
See [the documentation](https://upstash.com/docs/oss/sdks/ts/ratelimit/overview) for more information details about this package.
|
|
150
79
|
|
|
151
80
|
## Contributing
|
|
152
81
|
|
|
@@ -157,6 +86,20 @@ the url and token.
|
|
|
157
86
|
|
|
158
87
|
### Running tests
|
|
159
88
|
|
|
89
|
+
To run the tests, you will need to set some environment variables. Here is a list of
|
|
90
|
+
variables to set:
|
|
91
|
+
- `UPSTASH_REDIS_REST_URL`
|
|
92
|
+
- `UPSTASH_REDIS_REST_TOKEN`
|
|
93
|
+
- `US1_UPSTASH_REDIS_REST_URL`
|
|
94
|
+
- `US1_UPSTASH_REDIS_REST_TOKEN`
|
|
95
|
+
- `APN_UPSTASH_REDIS_REST_URL`
|
|
96
|
+
- `APN_UPSTASH_REDIS_REST_TOKEN`
|
|
97
|
+
- `EU2_UPSTASH_REDIS_REST_URL`
|
|
98
|
+
- `EU2_UPSTASH_REDIS_REST_TOKEN`
|
|
99
|
+
|
|
100
|
+
You can create a single Upstash Redis and use its URL and token for all four above.
|
|
101
|
+
|
|
102
|
+
Once you set the environment variables, simply run:
|
|
160
103
|
```sh
|
|
161
|
-
|
|
104
|
+
pnpm test
|
|
162
105
|
```
|
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/
|