ioredis-toolkit 0.0.9 → 0.5.0
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/CHANGELOG.md +67 -0
- package/LICENSE +1 -1
- package/README.md +68 -1058
- package/dist/cache/cache.d.ts +30 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +59 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/config.d.ts +12 -0
- package/dist/cache/config.d.ts.map +1 -0
- package/dist/cache/config.js +13 -0
- package/dist/cache/config.js.map +1 -0
- package/dist/cache/types.d.ts +32 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +5 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/index.d.ts +43 -51
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -44
- package/dist/index.js.map +1 -0
- package/dist/lock/config.d.ts +12 -0
- package/dist/lock/config.d.ts.map +1 -0
- package/dist/lock/config.js +8 -0
- package/dist/lock/config.js.map +1 -0
- package/dist/lock/lock.d.ts +20 -0
- package/dist/lock/lock.d.ts.map +1 -0
- package/dist/lock/lock.js +44 -0
- package/dist/lock/lock.js.map +1 -0
- package/dist/lock/types.d.ts +19 -0
- package/dist/lock/types.d.ts.map +1 -0
- package/dist/lock/types.js +2 -0
- package/dist/lock/types.js.map +1 -0
- package/dist/modules-config.d.ts +3 -0
- package/dist/modules-config.d.ts.map +1 -0
- package/dist/modules-config.js +2 -0
- package/dist/modules-config.js.map +1 -0
- package/dist/pubsub/config.d.ts +11 -0
- package/dist/pubsub/config.d.ts.map +1 -0
- package/dist/pubsub/config.js +6 -0
- package/dist/pubsub/config.js.map +1 -0
- package/dist/pubsub/pubsub.d.ts +20 -0
- package/dist/pubsub/pubsub.d.ts.map +1 -0
- package/dist/pubsub/pubsub.js +54 -0
- package/dist/pubsub/pubsub.js.map +1 -0
- package/dist/pubsub/types.d.ts +24 -0
- package/dist/pubsub/types.d.ts.map +1 -0
- package/dist/pubsub/types.js +2 -0
- package/dist/pubsub/types.js.map +1 -0
- package/dist/rate-limit/config.d.ts +12 -0
- package/dist/rate-limit/config.d.ts.map +1 -0
- package/dist/rate-limit/config.js +6 -0
- package/dist/rate-limit/config.js.map +1 -0
- package/dist/rate-limit/rate-limiter.d.ts +18 -0
- package/dist/rate-limit/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limit/rate-limiter.js +37 -0
- package/dist/rate-limit/rate-limiter.js.map +1 -0
- package/dist/rate-limit/types.d.ts +27 -0
- package/dist/rate-limit/types.d.ts.map +1 -0
- package/dist/rate-limit/types.js +2 -0
- package/dist/rate-limit/types.js.map +1 -0
- package/dist/redis/client-facade.d.ts +77 -0
- package/dist/redis/client-facade.d.ts.map +1 -0
- package/dist/redis/client-facade.js +102 -0
- package/dist/redis/client-facade.js.map +1 -0
- package/dist/redis/client.d.ts +10 -0
- package/dist/redis/client.d.ts.map +1 -0
- package/dist/redis/client.js +29 -0
- package/dist/redis/client.js.map +1 -0
- package/dist/redis/cluster.d.ts +7 -0
- package/dist/redis/cluster.d.ts.map +1 -0
- package/dist/redis/cluster.js +47 -0
- package/dist/redis/cluster.js.map +1 -0
- package/dist/redis/config.d.ts +39 -0
- package/dist/redis/config.d.ts.map +1 -0
- package/dist/redis/config.js +52 -0
- package/dist/redis/config.js.map +1 -0
- package/dist/redis/errors.d.ts +5 -0
- package/dist/redis/errors.d.ts.map +1 -0
- package/dist/redis/errors.js +5 -0
- package/dist/redis/errors.js.map +1 -0
- package/dist/redis/types.d.ts +135 -0
- package/dist/redis/types.d.ts.map +1 -0
- package/dist/redis/types.js +2 -0
- package/dist/redis/types.js.map +1 -0
- package/dist/redis/wrapper.d.ts +88 -0
- package/dist/redis/wrapper.d.ts.map +1 -0
- package/dist/redis/wrapper.js +206 -0
- package/dist/redis/wrapper.js.map +1 -0
- package/dist/session/config.d.ts +47 -0
- package/dist/session/config.d.ts.map +1 -0
- package/dist/session/config.js +101 -0
- package/dist/session/config.js.map +1 -0
- package/dist/session/cookie.d.ts +16 -0
- package/dist/session/cookie.d.ts.map +1 -0
- package/dist/session/cookie.js +28 -0
- package/dist/session/cookie.js.map +1 -0
- package/dist/session/errors.d.ts +56 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +58 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/factory.d.ts +21 -0
- package/dist/session/factory.d.ts.map +1 -0
- package/dist/session/factory.js +30 -0
- package/dist/session/factory.js.map +1 -0
- package/dist/session/health.d.ts +12 -0
- package/dist/session/health.d.ts.map +1 -0
- package/dist/session/health.js +23 -0
- package/dist/session/health.js.map +1 -0
- package/dist/session/keys.d.ts +23 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +27 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/manager.d.ts +34 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +31 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/metrics.d.ts +11 -0
- package/dist/session/metrics.d.ts.map +1 -0
- package/dist/session/metrics.js +10 -0
- package/dist/session/metrics.js.map +1 -0
- package/dist/session/repository.d.ts +49 -0
- package/dist/session/repository.d.ts.map +1 -0
- package/dist/session/repository.js +203 -0
- package/dist/session/repository.js.map +1 -0
- package/dist/session/revocation.d.ts +22 -0
- package/dist/session/revocation.d.ts.map +1 -0
- package/dist/session/revocation.js +41 -0
- package/dist/session/revocation.js.map +1 -0
- package/dist/session/script-sources.d.ts +11 -0
- package/dist/session/script-sources.d.ts.map +1 -0
- package/dist/session/script-sources.js +140 -0
- package/dist/session/script-sources.js.map +1 -0
- package/dist/session/scripts.d.ts +15 -0
- package/dist/session/scripts.d.ts.map +1 -0
- package/dist/session/scripts.js +41 -0
- package/dist/session/scripts.js.map +1 -0
- package/dist/session/serializer.d.ts +12 -0
- package/dist/session/serializer.d.ts.map +1 -0
- package/dist/session/serializer.js +77 -0
- package/dist/session/serializer.js.map +1 -0
- package/dist/session/service.d.ts +48 -0
- package/dist/session/service.d.ts.map +1 -0
- package/dist/session/service.js +235 -0
- package/dist/session/service.js.map +1 -0
- package/dist/session/token.d.ts +16 -0
- package/dist/session/token.d.ts.map +1 -0
- package/dist/session/token.js +32 -0
- package/dist/session/token.js.map +1 -0
- package/dist/session/types.d.ts +134 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/streams/config.d.ts +12 -0
- package/dist/streams/config.d.ts.map +1 -0
- package/dist/streams/config.js +6 -0
- package/dist/streams/config.js.map +1 -0
- package/dist/streams/streams.d.ts +24 -0
- package/dist/streams/streams.d.ts.map +1 -0
- package/dist/streams/streams.js +55 -0
- package/dist/streams/streams.js.map +1 -0
- package/dist/streams/types.d.ts +32 -0
- package/dist/streams/types.d.ts.map +1 -0
- package/dist/streams/types.js +2 -0
- package/dist/streams/types.js.map +1 -0
- package/docs/ACCEPTANCE-REPORT.md +70 -0
- package/docs/ARCHITECTURE.md +61 -0
- package/docs/CAPACITY.md +33 -0
- package/docs/DEPLOYMENT.md +22 -0
- package/docs/README-API.md +15 -0
- package/docs/STATE-MACHINE.md +38 -0
- package/docs/TESTING.md +37 -0
- package/docs/THREAT-MODEL.md +23 -0
- package/docs/TYPE-SAFETY.md +34 -0
- package/docs/modules/cache/README.md +7 -0
- package/docs/modules/cache/usage.md +156 -0
- package/docs/modules/lock/README.md +7 -0
- package/docs/modules/lock/usage.md +105 -0
- package/docs/modules/pubsub/README.md +7 -0
- package/docs/modules/pubsub/usage.md +106 -0
- package/docs/modules/rate-limit/README.md +7 -0
- package/docs/modules/rate-limit/usage.md +100 -0
- package/docs/modules/sessions/README.md +7 -0
- package/docs/modules/sessions/usage.md +262 -0
- package/docs/modules/streams/README.md +7 -0
- package/docs/modules/streams/usage.md +141 -0
- package/package.json +50 -60
- package/src/scripts/cleanup-index.lua +4 -0
- package/src/scripts/conditional-update.lua +21 -0
- package/src/scripts/consume-session.lua +21 -0
- package/src/scripts/create-session.lua +28 -0
- package/src/scripts/delete.lua +2 -0
- package/src/scripts/destroy-user.lua +13 -0
- package/src/scripts/enforce-limit.lua +17 -0
- package/src/scripts/revoke-session.lua +13 -0
- package/src/scripts/rotate.lua +24 -0
- package/src/scripts/touch-session.lua +28 -0
- package/src/scripts/update-session.lua +18 -0
- package/dist/cache.d.ts +0 -796
- package/dist/cache.js +0 -1120
- package/dist/client.d.ts +0 -284
- package/dist/client.js +0 -1114
- package/dist/cluster-slot.d.ts +0 -4
- package/dist/cluster-slot.js +0 -31
- package/dist/cluster.d.ts +0 -79
- package/dist/cluster.js +0 -156
- package/dist/errors.d.ts +0 -30
- package/dist/errors.js +0 -63
- package/dist/health.d.ts +0 -180
- package/dist/health.js +0 -239
- package/dist/lock.d.ts +0 -248
- package/dist/lock.js +0 -397
- package/dist/logger.d.ts +0 -12
- package/dist/logger.js +0 -40
- package/dist/pubsub.d.ts +0 -423
- package/dist/pubsub.js +0 -537
- package/dist/ratelimiter.d.ts +0 -441
- package/dist/ratelimiter.js +0 -539
- package/dist/session/index.d.ts +0 -23
- package/dist/session/index.js +0 -16
- package/dist/session/revocation-store.d.ts +0 -176
- package/dist/session/revocation-store.js +0 -318
- package/dist/session/scripts/cleanup-index.lua +0 -21
- package/dist/session/scripts/conditional-update-encrypted.lua +0 -60
- package/dist/session/scripts/conditional-update.lua +0 -63
- package/dist/session/scripts/create.lua +0 -83
- package/dist/session/scripts/delete-by-user.lua +0 -29
- package/dist/session/scripts/delete.lua +0 -15
- package/dist/session/scripts/enforce-limit.lua +0 -38
- package/dist/session/scripts/revoke.lua +0 -61
- package/dist/session/scripts/rotate-encrypted.lua +0 -110
- package/dist/session/scripts/rotate.lua +0 -122
- package/dist/session/scripts/touch-encrypted.lua +0 -89
- package/dist/session/scripts/touch.lua +0 -72
- package/dist/session/scripts/validate.lua +0 -90
- package/dist/session/session-circuit-breaker.d.ts +0 -42
- package/dist/session/session-circuit-breaker.js +0 -129
- package/dist/session/session-config.d.ts +0 -335
- package/dist/session/session-config.js +0 -162
- package/dist/session/session-cookie.d.ts +0 -72
- package/dist/session/session-cookie.js +0 -101
- package/dist/session/session-encryption.d.ts +0 -87
- package/dist/session/session-encryption.js +0 -139
- package/dist/session/session-errors.d.ts +0 -85
- package/dist/session/session-errors.js +0 -145
- package/dist/session/session-health.d.ts +0 -38
- package/dist/session/session-health.js +0 -60
- package/dist/session/session-keys.d.ts +0 -51
- package/dist/session/session-keys.js +0 -113
- package/dist/session/session-manager.d.ts +0 -73
- package/dist/session/session-manager.js +0 -94
- package/dist/session/session-metrics.d.ts +0 -33
- package/dist/session/session-metrics.js +0 -112
- package/dist/session/session-repository.d.ts +0 -161
- package/dist/session/session-repository.js +0 -683
- package/dist/session/session-scripts.d.ts +0 -36
- package/dist/session/session-scripts.js +0 -130
- package/dist/session/session-serializer.d.ts +0 -42
- package/dist/session/session-serializer.js +0 -248
- package/dist/session/session-service.d.ts +0 -104
- package/dist/session/session-service.js +0 -611
- package/dist/session/session-token.d.ts +0 -38
- package/dist/session/session-token.js +0 -86
- package/dist/session/session-types.d.ts +0 -253
- package/dist/session/session-types.js +0 -16
- package/dist/types.d.ts +0 -924
- package/dist/types.js +0 -151
- package/dist/utils/deepmerge.d.ts +0 -9
- package/dist/utils/deepmerge.js +0 -61
package/dist/ratelimiter.d.ts
DELETED
|
@@ -1,441 +0,0 @@
|
|
|
1
|
-
import { RedisClientWrapper } from './client.js';
|
|
2
|
-
import { LoggerLike } from './logger.js';
|
|
3
|
-
import { RateLimitOptionsInput } from './types.js';
|
|
4
|
-
/**
|
|
5
|
-
* Window algorithm used by the rate limiter.
|
|
6
|
-
* - `fixed` - fixed window via `INCR`/`EXPIRE` (simple, cheapest)
|
|
7
|
-
* - `sliding` - sliding window via an atomic Lua script over a sorted set (smoothest)
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Window algorithm used by the rate limiter.
|
|
11
|
-
*
|
|
12
|
-
* - `fixed` - Fixed window via `INCR`/`EXPIRE` (simple, cheapest).
|
|
13
|
-
* - `sliding` - Sliding window via an atomic Lua script over a sorted set (smoothest,
|
|
14
|
-
* precise rolling window).
|
|
15
|
-
*/
|
|
16
|
-
export type RateLimitAlgorithm = 'fixed' | 'sliding';
|
|
17
|
-
/**
|
|
18
|
-
* Options for a rate limiter instance or an individual call.
|
|
19
|
-
*/
|
|
20
|
-
/**
|
|
21
|
-
* Options for a rate limiter instance or an individual call.
|
|
22
|
-
*
|
|
23
|
-
* **Algorithm Details:**
|
|
24
|
-
* - `sliding` (default): Uses a sorted set with a Lua script for a precise rolling window.
|
|
25
|
-
* New entries are added with the current timestamp, and old entries outside the window
|
|
26
|
-
* are purged before counting. This provides the smoothest rate limiting experience.
|
|
27
|
-
* - `fixed`: Uses a simple counter with `INCR`/`EXPIRE`. The window resets at fixed
|
|
28
|
-
* boundaries (e.g., every 60 seconds from the start). This is the cheapest algorithm
|
|
29
|
-
* but has slightly less precise rate limiting.
|
|
30
|
-
*
|
|
31
|
-
* **Key Naming:**
|
|
32
|
-
* Keys are namespaced as `ratelimit:{namespace}:{resource}:{identifier}` so each
|
|
33
|
-
* resource + identifier pair is tracked independently.
|
|
34
|
-
*/
|
|
35
|
-
export interface RateLimitOptions {
|
|
36
|
-
/** Maximum allowed requests within `duration`. Default: `100`. */
|
|
37
|
-
limit?: number;
|
|
38
|
-
/** Window length in seconds. Default: `60`. */
|
|
39
|
-
duration?: number;
|
|
40
|
-
/** Window algorithm. Default: `'sliding'`. */
|
|
41
|
-
algorithm?: RateLimitAlgorithm;
|
|
42
|
-
/** Redis key prefix. Default: `'ratelimit'`. */
|
|
43
|
-
namespace?: string;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Result of a rate limit `consume`/`check` call.
|
|
47
|
-
*/
|
|
48
|
-
/**
|
|
49
|
-
* Result of a rate limit `consume`/`check` call.
|
|
50
|
-
*
|
|
51
|
-
* **Fields:**
|
|
52
|
-
* - `allowed`: `true` when the request is within the rate limit and may proceed.
|
|
53
|
-
* - `limit`: The configured maximum number of requests within the window.
|
|
54
|
-
* - `used`: The number of requests already counted in the current window.
|
|
55
|
-
* - `remaining`: The number of requests still available (`limit - used`, floored at `0`).
|
|
56
|
-
* - `resetAt`: Epoch milliseconds when the current window resets. `0` when the request
|
|
57
|
-
* is allowed (indicating the window is still open).
|
|
58
|
-
* - `retryAfter`: Seconds to wait before retrying the request. `0` when the request
|
|
59
|
-
* is allowed.
|
|
60
|
-
*
|
|
61
|
-
* **Example:**
|
|
62
|
-
* ```ts
|
|
63
|
-
* const result = await limiter.consume('/api/login', 'ip-10.0.0.1');
|
|
64
|
-
* if (!result.allowed) {
|
|
65
|
-
* // result.retryAfter tells you how many seconds to wait before retrying
|
|
66
|
-
* console.log(`Retry after ${result.retryAfter}s`);
|
|
67
|
-
* console.log(`Window resets at ${new Date(result.resetAt)}`);
|
|
68
|
-
* }
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
export interface RateLimitResult {
|
|
72
|
-
/** `true` when the request is within the limit. */
|
|
73
|
-
allowed: boolean;
|
|
74
|
-
/** The configured maximum within the window. */
|
|
75
|
-
limit: number;
|
|
76
|
-
/** Requests already counted in the current window. */
|
|
77
|
-
used: number;
|
|
78
|
-
/** Requests still available (`limit - used`, floored at `0`). */
|
|
79
|
-
remaining: number;
|
|
80
|
-
/** Epoch milliseconds when the window resets. */
|
|
81
|
-
resetAt: number;
|
|
82
|
-
/** Seconds to wait before retrying; `0` when allowed. */
|
|
83
|
-
retryAfter: number;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Generic Redis-backed rate limiter that works for any resource: routes, API
|
|
87
|
-
* endpoints, users, IPs, databases, email sending, etc.
|
|
88
|
-
*
|
|
89
|
-
* Keys are namespaced as `ratelimit:{namespace}:{resource}:{identifier}` so each
|
|
90
|
-
* resource + identifier combination is tracked independently. Supports fixed-window
|
|
91
|
-
* (`INCR`/`EXPIRE`) and sliding-window (atomic Lua over a sorted set) algorithms.
|
|
92
|
-
* Fails open when Redis is unavailable.
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* ```ts
|
|
96
|
-
* const limiter = new RateLimiter(client, { limit: 100, duration: 60 });
|
|
97
|
-
*
|
|
98
|
-
* const result = await limiter.consume('/api/login', 'ip-10.0.0.1');
|
|
99
|
-
* if (!result.allowed) {
|
|
100
|
-
* throw new Error(`Slow down, retry in ${result.retryAfter}s`);
|
|
101
|
-
* }
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
|
-
export declare class RateLimiter {
|
|
105
|
-
private client;
|
|
106
|
-
private logger;
|
|
107
|
-
private defaultLimit;
|
|
108
|
-
private defaultDuration;
|
|
109
|
-
private defaultAlgorithm;
|
|
110
|
-
private defaultNamespace;
|
|
111
|
-
/**
|
|
112
|
-
* Creates a rate limiter bound to a Redis client.
|
|
113
|
-
*
|
|
114
|
-
* @param client - The underlying {@link RedisClientWrapper}.
|
|
115
|
-
* @param options - Defaults applied when a call does not override them:
|
|
116
|
-
* `limit` (default `100`), `duration` in seconds (default `60`),
|
|
117
|
-
* `algorithm` (default `'sliding'`), `namespace` (default `'ratelimit'`).
|
|
118
|
-
* @param logger - Optional pino-compatible logger; defaults to `console`.
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```ts
|
|
122
|
-
* const limiter = new RateLimiter(client, { limit: 10, duration: 1, algorithm: 'fixed' });
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
constructor(client: RedisClientWrapper, options?: RateLimitOptionsInput, logger?: LoggerLike);
|
|
126
|
-
/**
|
|
127
|
-
* Creates a rate limiter bound to a Redis client.
|
|
128
|
-
*
|
|
129
|
-
* **Default Configuration:**
|
|
130
|
-
* - `limit`: `100` requests per window
|
|
131
|
-
* - `duration`: `60` seconds per window
|
|
132
|
-
* - `algorithm`: `'sliding'` (precise rolling window)
|
|
133
|
-
* - `namespace`: `'ratelimit'` key prefix
|
|
134
|
-
*
|
|
135
|
-
* **Example:**
|
|
136
|
-
* ```ts
|
|
137
|
-
* // Rate limit per route, per IP, 100 requests per 60 seconds (sliding window)
|
|
138
|
-
* const limiter = new RateLimiter(client, { limit: 100, duration: 60 });
|
|
139
|
-
*
|
|
140
|
-
* // Fixed window: 10 requests per 1 second
|
|
141
|
-
* const fixed = new RateLimiter(client, { limit: 10, duration: 1, algorithm: 'fixed' });
|
|
142
|
-
* ```
|
|
143
|
-
*
|
|
144
|
-
* **Parameters:**
|
|
145
|
-
* - `client` - The underlying {@link RedisClientWrapper}. All rate limit operations
|
|
146
|
-
* delegate to this client.
|
|
147
|
-
* - `options` - Default rate limit settings. Overridden per-call via the `consume`
|
|
148
|
-
* and `check` methods.
|
|
149
|
-
* - `logger` - Optional pino-compatible logger. Defaults to `console`.
|
|
150
|
-
*/
|
|
151
|
-
/**
|
|
152
|
-
* Builds the Redis key for a resource + identifier combination.
|
|
153
|
-
*
|
|
154
|
-
* @param resource - The rate-limited resource, e.g. a route `'/api/login'` or
|
|
155
|
-
* a resource name `'email:send'`.
|
|
156
|
-
* @param identifier - The caller identity, e.g. an IP, user id or API key.
|
|
157
|
-
* @param namespace - Key prefix (defaults to the limiter's namespace).
|
|
158
|
-
* @returns The full key, e.g. `'ratelimit:/api/login:ip-10.0.0.1'`.
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* ```ts
|
|
162
|
-
* limiter.makeKey('/api/login', 'ip-10.0.0.1');
|
|
163
|
-
* // 'ratelimit:/api/login:ip-10.0.0.1'
|
|
164
|
-
* ```
|
|
165
|
-
*/
|
|
166
|
-
/**
|
|
167
|
-
* Builds the Redis key for a resource + identifier combination.
|
|
168
|
-
*
|
|
169
|
-
* **Key Format:**
|
|
170
|
-
* The generated key follows the pattern: `${namespace}:${resource}:${identifier}`
|
|
171
|
-
* For example: `ratelimit:/api/login:ip-10.0.0.1`
|
|
172
|
-
*
|
|
173
|
-
* **Example:**
|
|
174
|
-
* ```ts
|
|
175
|
-
* const key = limiter.makeKey('/api/login', 'ip-10.0.0.1');
|
|
176
|
-
* // key === 'ratelimit:/api/login:ip-10.0.0.1'
|
|
177
|
-
* ```
|
|
178
|
-
*
|
|
179
|
-
* **Parameters:**
|
|
180
|
-
* - `resource` - The rate-limited resource, e.g. a route `'/api/login'` or
|
|
181
|
-
* a resource name `'email:send'`.
|
|
182
|
-
* - `identifier` - The caller identity, e.g. an IP, user id or API key.
|
|
183
|
-
* - `namespace` - Key prefix. Defaults to the limiter's configured namespace.
|
|
184
|
-
*
|
|
185
|
-
* @returns The full key, e.g. `'ratelimit:/api/login:ip-10.0.0.1'`.
|
|
186
|
-
*/
|
|
187
|
-
makeKey(resource: string, identifier: string, namespace?: string): string;
|
|
188
|
-
/**
|
|
189
|
-
* Consumes one unit of capacity for a resource + identifier and returns the
|
|
190
|
-
* resulting limit state.
|
|
191
|
-
*
|
|
192
|
-
* When the limit is reached the request is not recorded and `allowed` is
|
|
193
|
-
* `false` with `retryAfter` (seconds) and `resetAt` (epoch ms) hints.
|
|
194
|
-
* Fails open (allows the request) if Redis errors.
|
|
195
|
-
*
|
|
196
|
-
* @param resource - The rate-limited resource, e.g. a route `'/api/login'` or
|
|
197
|
-
* a resource name `'db:write'`.
|
|
198
|
-
* @param identifier - The caller identity, e.g. an IP, user id or API key.
|
|
199
|
-
* @param options - Per-call overrides for `limit`, `duration`, `algorithm`,
|
|
200
|
-
* and `namespace`.
|
|
201
|
-
* @returns The limit state: `allowed`, `limit`, `used`, `remaining`,
|
|
202
|
-
* `resetAt` (epoch ms), `retryAfter` (seconds).
|
|
203
|
-
*
|
|
204
|
-
* @example
|
|
205
|
-
* ```ts
|
|
206
|
-
* const result = await limiter.consume('/api/orders', 'user-7', { limit: 5, duration: 60 });
|
|
207
|
-
* if (!result.allowed) {
|
|
208
|
-
* res.setHeader('Retry-After', String(result.retryAfter));
|
|
209
|
-
* return res.status(429).json({ error: 'Too many requests' });
|
|
210
|
-
* }
|
|
211
|
-
* ```
|
|
212
|
-
*/
|
|
213
|
-
/**
|
|
214
|
-
* Consumes one unit of capacity for a resource + identifier and returns the
|
|
215
|
-
* resulting limit state.
|
|
216
|
-
*
|
|
217
|
-
* **Behavior:**
|
|
218
|
-
* - When the limit is reached, the request is not recorded and `allowed` is `false`
|
|
219
|
-
* with `retryAfter` (seconds) and `resetAt` (epoch ms) hints.
|
|
220
|
-
* - Fails open (allows the request) if Redis errors occur, so an outage cannot take
|
|
221
|
-
* down the whole app.
|
|
222
|
-
* - Two algorithm modes are available: `sliding` (default, precise rolling window)
|
|
223
|
-
* and `fixed` (simple counter-based).
|
|
224
|
-
*
|
|
225
|
-
* **Type Parameters:**
|
|
226
|
-
* - The return type is {@link RateLimitResult}.
|
|
227
|
-
*
|
|
228
|
-
* **Returns:**
|
|
229
|
-
* - A {@link RateLimitResult} object containing:
|
|
230
|
-
* - `allowed`: whether the request may proceed
|
|
231
|
-
* - `limit`: the configured max
|
|
232
|
-
* - `used`: requests in current window
|
|
233
|
-
* - `remaining`: left in the window
|
|
234
|
-
* - `resetAt`: epoch ms when window resets
|
|
235
|
-
* - `retryAfter`: seconds to wait (0 when allowed)
|
|
236
|
-
*
|
|
237
|
-
* **Example:**
|
|
238
|
-
* ```ts
|
|
239
|
-
* const result = await limiter.consume('/api/login', 'ip-10.0.0.1');
|
|
240
|
-
* if (!result.allowed) {
|
|
241
|
-
* // HTTP 429, set Retry-After: result.retryAfter
|
|
242
|
-
* res.setHeader('Retry-After', String(result.retryAfter));
|
|
243
|
-
* return res.status(429).json({ error: 'Too many requests' });
|
|
244
|
-
* }
|
|
245
|
-
* // allowed === true, request may proceed
|
|
246
|
-
* ```
|
|
247
|
-
*
|
|
248
|
-
* **Parameters:**
|
|
249
|
-
* - `resource` - The rate-limited resource, e.g. a route `'/api/login'` or
|
|
250
|
-
* a resource name `'email:send'`.
|
|
251
|
-
* - `identifier` - The caller identity, e.g. an IP, user id or API key.
|
|
252
|
-
* - `options` - Per-call overrides for `limit`, `duration`, `algorithm`, and `namespace`.
|
|
253
|
-
*
|
|
254
|
-
* @returns The limit state: `allowed`, `limit`, `used`, `remaining`,
|
|
255
|
-
* `resetAt` (epoch ms), `retryAfter` (seconds).
|
|
256
|
-
*/
|
|
257
|
-
consume(resource: string, identifier: string, options?: RateLimitOptions): Promise<RateLimitResult>;
|
|
258
|
-
/**
|
|
259
|
-
* Peeks at the current limit state without consuming capacity.
|
|
260
|
-
*
|
|
261
|
-
* Useful for pre-flight checks (e.g. showing "limit reached" in a UI before
|
|
262
|
-
* the actual request). Also fails open on Redis errors.
|
|
263
|
-
*
|
|
264
|
-
* @param resource - The rate-limited resource.
|
|
265
|
-
* @param identifier - The caller identity.
|
|
266
|
-
* @param options - Per-call overrides for `limit`, `duration`, `algorithm`,
|
|
267
|
-
* and `namespace`.
|
|
268
|
-
* @returns The current limit state; `used` is not incremented.
|
|
269
|
-
*
|
|
270
|
-
* @example
|
|
271
|
-
* ```ts
|
|
272
|
-
* const state = await limiter.check('/api/search', 'user-1');
|
|
273
|
-
* if (state.remaining === 0) {
|
|
274
|
-
* // disable the search button
|
|
275
|
-
* }
|
|
276
|
-
* ```
|
|
277
|
-
*/
|
|
278
|
-
/**
|
|
279
|
-
* Peeks at the current limit state without consuming capacity.
|
|
280
|
-
*
|
|
281
|
-
* **Behavior:**
|
|
282
|
-
* - Useful for pre-flight checks (e.g. showing "limit reached" in a UI before
|
|
283
|
-
* the actual request).
|
|
284
|
-
* - Does not increment the counter; only reads the current state.
|
|
285
|
-
* - Fails open (allows the request) if Redis errors occur.
|
|
286
|
-
*
|
|
287
|
-
* **Type Parameters:**
|
|
288
|
-
* - The return type is {@link RateLimitResult}.
|
|
289
|
-
*
|
|
290
|
-
* **Returns:**
|
|
291
|
-
* - A {@link RateLimitResult} object representing the current state.
|
|
292
|
-
* `used` is not incremented.
|
|
293
|
-
*
|
|
294
|
-
* **Example:**
|
|
295
|
-
* ```ts
|
|
296
|
-
* const state = await limiter.check('/api/search', 'user-1');
|
|
297
|
-
* if (state.remaining === 0) {
|
|
298
|
-
* // disable the search button
|
|
299
|
-
* }
|
|
300
|
-
* ```
|
|
301
|
-
*
|
|
302
|
-
* **Parameters:**
|
|
303
|
-
* - `resource` - The rate-limited resource.
|
|
304
|
-
* - `identifier` - The caller identity.
|
|
305
|
-
* - `options` - Per-call overrides for `limit`, `duration`, `algorithm`, and `namespace`.
|
|
306
|
-
*
|
|
307
|
-
* @returns The current limit state; `used` is not incremented.
|
|
308
|
-
*/
|
|
309
|
-
check(resource: string, identifier: string, options?: RateLimitOptions): Promise<RateLimitResult>;
|
|
310
|
-
/**
|
|
311
|
-
* Resets the counter for a resource + identifier, granting full capacity again.
|
|
312
|
-
*
|
|
313
|
-
* @param resource - The rate-limited resource.
|
|
314
|
-
* @param identifier - The caller identity.
|
|
315
|
-
* @param namespace - Key prefix (defaults to the limiter's namespace).
|
|
316
|
-
* @returns `true` if a counter existed and was removed.
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```ts
|
|
320
|
-
* // user upgraded to a premium plan, lift their limits
|
|
321
|
-
* await limiter.reset('/api/export', 'user-7');
|
|
322
|
-
* ```
|
|
323
|
-
*/
|
|
324
|
-
/**
|
|
325
|
-
* Resets the counter for a resource + identifier, granting full capacity again.
|
|
326
|
-
*
|
|
327
|
-
* **Behavior:**
|
|
328
|
-
* - Deletes the rate limit key from Redis, resetting the counter to zero.
|
|
329
|
-
* - After reset, the next request will be allowed (full capacity available).
|
|
330
|
-
*
|
|
331
|
-
* **Returns:**
|
|
332
|
-
* - `true` if a counter existed and was removed.
|
|
333
|
-
* - `false` if no counter existed (key already deleted).
|
|
334
|
-
*
|
|
335
|
-
* **Example:**
|
|
336
|
-
* ```ts
|
|
337
|
-
* // User upgraded to a premium plan, lift their limits
|
|
338
|
-
* await limiter.reset('/api/export', 'user-7');
|
|
339
|
-
* ```
|
|
340
|
-
*
|
|
341
|
-
* **Parameters:**
|
|
342
|
-
* - `resource` - The rate-limited resource.
|
|
343
|
-
* - `identifier` - The caller identity.
|
|
344
|
-
* - `namespace` - Key prefix. Defaults to the limiter's configured namespace.
|
|
345
|
-
*
|
|
346
|
-
* @returns `true` if a counter existed and was removed.
|
|
347
|
-
*/
|
|
348
|
-
reset(resource: string, identifier: string, namespace?: string): Promise<boolean>;
|
|
349
|
-
/**
|
|
350
|
-
* Consumes one unit of capacity using the fixed-window algorithm.
|
|
351
|
-
*
|
|
352
|
-
* **Behavior:**
|
|
353
|
-
* - Uses Redis `INCR` to increment a counter key.
|
|
354
|
-
* - If the counter was `1` (first request in the window), sets a TTL via `EXPIRE`.
|
|
355
|
-
* - The window resets at fixed boundaries determined by the TTL.
|
|
356
|
-
* - Returns `allowed: true` as long as `count <= limit`.
|
|
357
|
-
*
|
|
358
|
-
* **Returns:**
|
|
359
|
-
* - A {@link RateLimitResult} with the current window state.
|
|
360
|
-
*
|
|
361
|
-
* **Parameters:**
|
|
362
|
-
* - `key` - The Redis key for this resource + identifier combination.
|
|
363
|
-
* - `limit` - The maximum allowed requests within the window.
|
|
364
|
-
* - `duration` - The TTL in seconds for the key (also the window length).
|
|
365
|
-
*
|
|
366
|
-
* @internal
|
|
367
|
-
*/
|
|
368
|
-
private consumeFixed;
|
|
369
|
-
/**
|
|
370
|
-
* Consumes one unit of capacity using the sliding-window algorithm.
|
|
371
|
-
*
|
|
372
|
-
* **Behavior:**
|
|
373
|
-
* - Uses an atomic Lua script over a sorted set for a precise rolling window.
|
|
374
|
-
* - Old entries outside the window are purged before counting.
|
|
375
|
-
* - A unique member (timestamp + UUID) is added for each request.
|
|
376
|
-
* - The `PEXPIRE` command ensures the key expires after the window duration.
|
|
377
|
-
* - Returns `allowed: true` as long as the count of entries within the window is < limit.
|
|
378
|
-
*
|
|
379
|
-
* **The Lua script** (see {@link CONSUME_SCRIPT}) performs these operations atomically:
|
|
380
|
-
* 1. Remove entries with scores older than `now - window`
|
|
381
|
-
* 2. Count remaining entries (`ZCARD`)
|
|
382
|
-
* 3. If count >= limit, return `allowed: false` with `retryAfter`
|
|
383
|
-
* 4. Otherwise, add the new entry (`ZADD`) and return `allowed: true`
|
|
384
|
-
*
|
|
385
|
-
* **Returns:**
|
|
386
|
-
* - A {@link RateLimitResult} with the current window state.
|
|
387
|
-
*
|
|
388
|
-
* **Parameters:**
|
|
389
|
-
* - `key` - The Redis key for this resource + identifier combination.
|
|
390
|
-
* - `limit` - The maximum allowed requests within the window.
|
|
391
|
-
* - `duration` - The window length in seconds.
|
|
392
|
-
*
|
|
393
|
-
* @internal
|
|
394
|
-
*/
|
|
395
|
-
private consumeSliding;
|
|
396
|
-
/**
|
|
397
|
-
* Peeks at the current limit using the fixed-window algorithm.
|
|
398
|
-
*
|
|
399
|
-
* **Behavior:**
|
|
400
|
-
* - Reads the current counter value from Redis via `GET`.
|
|
401
|
-
* - If the key does not exist, `used` is `0`.
|
|
402
|
-
* - Returns `allowed: true` when `used < limit`.
|
|
403
|
-
*
|
|
404
|
-
* **Returns:**
|
|
405
|
-
* - A {@link RateLimitResult} with the current window state.
|
|
406
|
-
*
|
|
407
|
-
* **Parameters:**
|
|
408
|
-
* - `key` - The Redis key for this resource + identifier combination.
|
|
409
|
-
* - `limit` - The maximum allowed requests within the window.
|
|
410
|
-
* - `duration` - The TTL/window length in seconds.
|
|
411
|
-
*
|
|
412
|
-
* @internal
|
|
413
|
-
*/
|
|
414
|
-
private checkFixed;
|
|
415
|
-
/**
|
|
416
|
-
* Peeks at the current limit using the sliding-window algorithm.
|
|
417
|
-
*
|
|
418
|
-
* **Behavior:**
|
|
419
|
-
* - Uses an atomic Lua script (see {@link PEEK_SCRIPT}) to count entries within
|
|
420
|
-
* the rolling window without consuming capacity.
|
|
421
|
-
* - Old entries outside the window are purged before counting.
|
|
422
|
-
* - Returns `allowed: true` when the count of entries within the window is < limit.
|
|
423
|
-
*
|
|
424
|
-
* **The Lua script** (see {@link PEEK_SCRIPT}) performs:
|
|
425
|
-
* 1. Remove entries with scores older than `now - window`
|
|
426
|
-
* 2. Count remaining entries (`ZCARD`)
|
|
427
|
-
* 3. Return the count and optional `retryAfter`
|
|
428
|
-
*
|
|
429
|
-
* **Returns:**
|
|
430
|
-
* - A {@link RateLimitResult} with the current window state.
|
|
431
|
-
* `used` is the count of entries in the window; not incremented.
|
|
432
|
-
*
|
|
433
|
-
* **Parameters:**
|
|
434
|
-
* - `key` - The Redis key for this resource + identifier combination.
|
|
435
|
-
* - `limit` - The maximum allowed requests within the window.
|
|
436
|
-
* - `duration` - The window length in seconds.
|
|
437
|
-
*
|
|
438
|
-
* @internal
|
|
439
|
-
*/
|
|
440
|
-
private checkSliding;
|
|
441
|
-
}
|