ratelimit-flex 1.0.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +274 -0
  4. package/dist/cjs/index.d.ts +32 -0
  5. package/dist/cjs/index.d.ts.map +1 -0
  6. package/dist/cjs/index.js +73 -0
  7. package/dist/cjs/index.js.map +1 -0
  8. package/dist/cjs/middleware/express.d.ts +18 -0
  9. package/dist/cjs/middleware/express.d.ts.map +1 -0
  10. package/dist/cjs/middleware/express.js +61 -0
  11. package/dist/cjs/middleware/express.js.map +1 -0
  12. package/dist/cjs/middleware/fastify.d.ts +21 -0
  13. package/dist/cjs/middleware/fastify.d.ts.map +1 -0
  14. package/dist/cjs/middleware/fastify.js +66 -0
  15. package/dist/cjs/middleware/fastify.js.map +1 -0
  16. package/dist/cjs/middleware/index.d.ts +4 -0
  17. package/dist/cjs/middleware/index.d.ts.map +1 -0
  18. package/dist/cjs/middleware/index.js +9 -0
  19. package/dist/cjs/middleware/index.js.map +1 -0
  20. package/dist/cjs/middleware/merge-options.d.ts +16 -0
  21. package/dist/cjs/middleware/merge-options.d.ts.map +1 -0
  22. package/dist/cjs/middleware/merge-options.js +71 -0
  23. package/dist/cjs/middleware/merge-options.js.map +1 -0
  24. package/dist/cjs/package.json +1 -0
  25. package/dist/cjs/stores/index.d.ts +4 -0
  26. package/dist/cjs/stores/index.d.ts.map +1 -0
  27. package/dist/cjs/stores/index.js +11 -0
  28. package/dist/cjs/stores/index.js.map +1 -0
  29. package/dist/cjs/stores/memory-store.d.ts +74 -0
  30. package/dist/cjs/stores/memory-store.d.ts.map +1 -0
  31. package/dist/cjs/stores/memory-store.js +259 -0
  32. package/dist/cjs/stores/memory-store.js.map +1 -0
  33. package/dist/cjs/stores/redis-store.d.ts +113 -0
  34. package/dist/cjs/stores/redis-store.d.ts.map +1 -0
  35. package/dist/cjs/stores/redis-store.js +452 -0
  36. package/dist/cjs/stores/redis-store.js.map +1 -0
  37. package/dist/cjs/strategies/defaults.d.ts +28 -0
  38. package/dist/cjs/strategies/defaults.d.ts.map +1 -0
  39. package/dist/cjs/strategies/defaults.js +31 -0
  40. package/dist/cjs/strategies/defaults.js.map +1 -0
  41. package/dist/cjs/strategies/index.d.ts +4 -0
  42. package/dist/cjs/strategies/index.d.ts.map +1 -0
  43. package/dist/cjs/strategies/index.js +13 -0
  44. package/dist/cjs/strategies/index.js.map +1 -0
  45. package/dist/cjs/strategies/rate-limit-engine.d.ts +42 -0
  46. package/dist/cjs/strategies/rate-limit-engine.d.ts.map +1 -0
  47. package/dist/cjs/strategies/rate-limit-engine.js +128 -0
  48. package/dist/cjs/strategies/rate-limit-engine.js.map +1 -0
  49. package/dist/cjs/types/index.d.ts +93 -0
  50. package/dist/cjs/types/index.d.ts.map +1 -0
  51. package/dist/cjs/types/index.js +14 -0
  52. package/dist/cjs/types/index.js.map +1 -0
  53. package/dist/cjs/utils/index.d.ts +3 -0
  54. package/dist/cjs/utils/index.d.ts.map +1 -0
  55. package/dist/cjs/utils/index.js +4 -0
  56. package/dist/cjs/utils/index.js.map +1 -0
  57. package/dist/index.d.ts +32 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +43 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/middleware/express.d.ts +18 -0
  62. package/dist/middleware/express.d.ts.map +1 -0
  63. package/dist/middleware/express.js +58 -0
  64. package/dist/middleware/express.js.map +1 -0
  65. package/dist/middleware/fastify.d.ts +21 -0
  66. package/dist/middleware/fastify.d.ts.map +1 -0
  67. package/dist/middleware/fastify.js +60 -0
  68. package/dist/middleware/fastify.js.map +1 -0
  69. package/dist/middleware/index.d.ts +4 -0
  70. package/dist/middleware/index.d.ts.map +1 -0
  71. package/dist/middleware/index.js +4 -0
  72. package/dist/middleware/index.js.map +1 -0
  73. package/dist/middleware/merge-options.d.ts +16 -0
  74. package/dist/middleware/merge-options.d.ts.map +1 -0
  75. package/dist/middleware/merge-options.js +64 -0
  76. package/dist/middleware/merge-options.js.map +1 -0
  77. package/dist/stores/index.d.ts +4 -0
  78. package/dist/stores/index.d.ts.map +1 -0
  79. package/dist/stores/index.js +4 -0
  80. package/dist/stores/index.js.map +1 -0
  81. package/dist/stores/memory-store.d.ts +74 -0
  82. package/dist/stores/memory-store.d.ts.map +1 -0
  83. package/dist/stores/memory-store.js +255 -0
  84. package/dist/stores/memory-store.js.map +1 -0
  85. package/dist/stores/redis-store.d.ts +113 -0
  86. package/dist/stores/redis-store.d.ts.map +1 -0
  87. package/dist/stores/redis-store.js +413 -0
  88. package/dist/stores/redis-store.js.map +1 -0
  89. package/dist/strategies/defaults.d.ts +28 -0
  90. package/dist/strategies/defaults.d.ts.map +1 -0
  91. package/dist/strategies/defaults.js +28 -0
  92. package/dist/strategies/defaults.js.map +1 -0
  93. package/dist/strategies/index.d.ts +4 -0
  94. package/dist/strategies/index.d.ts.map +1 -0
  95. package/dist/strategies/index.js +4 -0
  96. package/dist/strategies/index.js.map +1 -0
  97. package/dist/strategies/rate-limit-engine.d.ts +42 -0
  98. package/dist/strategies/rate-limit-engine.d.ts.map +1 -0
  99. package/dist/strategies/rate-limit-engine.js +122 -0
  100. package/dist/strategies/rate-limit-engine.js.map +1 -0
  101. package/dist/types/index.d.ts +93 -0
  102. package/dist/types/index.d.ts.map +1 -0
  103. package/dist/types/index.js +11 -0
  104. package/dist/types/index.js.map +1 -0
  105. package/dist/utils/index.d.ts +3 -0
  106. package/dist/utils/index.d.ts.map +1 -0
  107. package/dist/utils/index.js +3 -0
  108. package/dist/utils/index.js.map +1 -0
  109. package/package.json +90 -0
@@ -0,0 +1,413 @@
1
+ import { RateLimitStrategy } from '../types/index.js';
2
+ const DEFAULT_PREFIX = 'rlf:';
3
+ /** Sliding window: ZSET prune + ZADD + ZCARD. KEYS[1]=zset, ARGV: now, windowMs, maxRequests, member */
4
+ const LUA_SLIDING_INCR = `
5
+ local zkey = KEYS[1]
6
+ local now = tonumber(ARGV[1])
7
+ local window_ms = tonumber(ARGV[2])
8
+ local max_requests = tonumber(ARGV[3])
9
+ local member = ARGV[4]
10
+
11
+ redis.call('ZREMRANGEBYSCORE', zkey, '-inf', now - window_ms)
12
+ redis.call('ZADD', zkey, now, member)
13
+ local count = tonumber(redis.call('ZCARD', zkey))
14
+ redis.call('PEXPIRE', zkey, window_ms)
15
+
16
+ local blocked = 0
17
+ if count > max_requests then blocked = 1 end
18
+
19
+ local oldest_score = now
20
+ if count > 0 then
21
+ local r = redis.call('ZRANGE', zkey, 0, 0, 'WITHSCORES')
22
+ if r[2] ~= nil then
23
+ oldest_score = tonumber(r[2])
24
+ end
25
+ end
26
+ local reset_at = oldest_score + window_ms
27
+
28
+ return { count, blocked, reset_at }
29
+ `;
30
+ const LUA_SLIDING_DECR = `
31
+ redis.call('ZPOPMAX', KEYS[1])
32
+ return 1
33
+ `;
34
+ /** Fixed window: atomic INCR + PEXPIRE on first hit. KEYS[1]=counter, ARGV: windowMs, maxRequests, now */
35
+ const LUA_FIXED_INCR = `
36
+ local k = KEYS[1]
37
+ local window_ms = tonumber(ARGV[1])
38
+ local max_requests = tonumber(ARGV[2])
39
+ local now = tonumber(ARGV[3])
40
+
41
+ local current = tonumber(redis.call('INCR', k))
42
+ if current == 1 then
43
+ redis.call('PEXPIRE', k, window_ms)
44
+ end
45
+
46
+ local pttl = tonumber(redis.call('PTTL', k))
47
+ if pttl < 0 then pttl = window_ms end
48
+ local reset_at = now + pttl
49
+
50
+ local blocked = 0
51
+ if current > max_requests then blocked = 1 end
52
+
53
+ return { current, blocked, reset_at }
54
+ `;
55
+ const LUA_FIXED_DECR = `
56
+ local k = KEYS[1]
57
+ local v = tonumber(redis.call('GET', k) or '0')
58
+ if v > 0 then
59
+ redis.call('DECR', k)
60
+ end
61
+ return v
62
+ `;
63
+ /** Token bucket: HSET tokens + last_refill. KEYS[1]=hash, ARGV: now, tpi, interval_ms, bucket_size */
64
+ const LUA_BUCKET_INCR = `
65
+ local key = KEYS[1]
66
+ local now = tonumber(ARGV[1])
67
+ local tokens_per_interval = tonumber(ARGV[2])
68
+ local interval_ms = tonumber(ARGV[3])
69
+ local bucket_size = tonumber(ARGV[4])
70
+
71
+ local tokens_s = redis.call('HGET', key, 'tokens')
72
+ local last_s = redis.call('HGET', key, 'last_refill')
73
+
74
+ local tokens
75
+ local last_refill
76
+
77
+ if tokens_s == false then
78
+ tokens = bucket_size
79
+ last_refill = now
80
+ else
81
+ tokens = tonumber(tokens_s)
82
+ last_refill = tonumber(last_s)
83
+ end
84
+
85
+ local elapsed = now - last_refill
86
+ local intervals = math.floor(elapsed / interval_ms)
87
+ if intervals > 0 then
88
+ tokens = math.min(bucket_size, tokens + intervals * tokens_per_interval)
89
+ last_refill = last_refill + intervals * interval_ms
90
+ end
91
+
92
+ if tokens >= 1 then
93
+ tokens = tokens - 1
94
+ redis.call('HSET', key, 'tokens', tostring(tokens), 'last_refill', tostring(last_refill))
95
+ redis.call('PEXPIRE', key, interval_ms * 10)
96
+ local remaining = tokens
97
+ local total_hits = bucket_size - remaining
98
+ local next_tick = last_refill + interval_ms
99
+ return { 1, remaining, total_hits, 0, next_tick }
100
+ end
101
+
102
+ redis.call('HSET', key, 'tokens', tostring(tokens), 'last_refill', tostring(last_refill))
103
+ redis.call('PEXPIRE', key, interval_ms * 10)
104
+ local next_refill = last_refill + interval_ms
105
+ return { 0, tokens, bucket_size, 1, next_refill }
106
+ `;
107
+ const LUA_BUCKET_DECR = `
108
+ local key = KEYS[1]
109
+ local bucket_size = tonumber(ARGV[1])
110
+ local tokens_s = redis.call('HGET', key, 'tokens')
111
+ local tokens
112
+ if tokens_s == false then
113
+ return 0
114
+ end
115
+ tokens = tonumber(tokens_s)
116
+ tokens = math.min(bucket_size, tokens + 1)
117
+ redis.call('HSET', key, 'tokens', tostring(tokens))
118
+ return 1
119
+ `;
120
+ const LUA_DEL = `
121
+ return redis.call('DEL', unpack(KEYS))
122
+ `;
123
+ /**
124
+ * Wrap an **ioredis** client instance to satisfy {@link RedisLikeClient} without adding a compile-time dependency.
125
+ */
126
+ export function adaptIoRedisClient(client) {
127
+ return {
128
+ get: (k) => client.get(k),
129
+ set: (k, v, ...rest) => client.set(k, v, ...rest),
130
+ eval: (script, numKeys, ...rest) => client.eval(script, numKeys, ...rest.map((a) => String(a))),
131
+ del: client.del?.bind(client),
132
+ quit: client.quit?.bind(client),
133
+ disconnect: client.disconnect ? async () => await client.disconnect() : undefined,
134
+ };
135
+ }
136
+ /**
137
+ * Wrap **node-redis** v4+ clients (`eval(script, { keys, arguments })`).
138
+ * Does not add a `redis` package dependency — pass your connected client instance.
139
+ */
140
+ export function adaptNodeRedisClient(client) {
141
+ return {
142
+ get: async (k) => (await client.get(k)) ?? null,
143
+ set: (k, v, ...rest) => client.set(k, v, ...rest),
144
+ eval: (script, numKeys, ...rest) => {
145
+ const keys = rest.slice(0, numKeys);
146
+ const args = rest.slice(numKeys);
147
+ return client.eval(script, { keys, arguments: args });
148
+ },
149
+ del: client.del?.bind(client),
150
+ quit: client.quit?.bind(client),
151
+ disconnect: client.disconnect ? async () => await client.disconnect() : undefined,
152
+ };
153
+ }
154
+ /**
155
+ * Redis-backed {@link RateLimitStore} using Lua for atomicity.
156
+ *
157
+ * Pass either `client` (recommended) or `url` (loads optional peer `ioredis` at runtime).
158
+ */
159
+ export class RedisStore {
160
+ constructor(options) {
161
+ this.client = null;
162
+ /** Connection created from `url` — closed on {@link RedisStore.shutdown}. */
163
+ this.ownedRedis = null;
164
+ if (options.url && options.client) {
165
+ throw new Error('RedisStore: pass either "url" or "client", not both');
166
+ }
167
+ if (!options.url && !options.client) {
168
+ throw new Error('RedisStore: pass "url" or "client"');
169
+ }
170
+ this.strategy = options.strategy;
171
+ this.keyPrefix = options.keyPrefix ?? DEFAULT_PREFIX;
172
+ this.onWarn =
173
+ options.onWarn ?? ((msg, err) => console.warn(`[ratelimit-flex] ${msg}`, err ?? ''));
174
+ if (options.strategy === RateLimitStrategy.TOKEN_BUCKET) {
175
+ this.windowMs = 0;
176
+ this.maxRequests = 0;
177
+ this.tokensPerInterval = options.tokensPerInterval;
178
+ this.refillIntervalMs = options.interval;
179
+ this.bucketSize = options.bucketSize;
180
+ }
181
+ else {
182
+ this.windowMs = options.windowMs;
183
+ this.maxRequests = options.maxRequests;
184
+ this.tokensPerInterval = 0;
185
+ this.refillIntervalMs = 0;
186
+ this.bucketSize = 0;
187
+ }
188
+ if (options.client) {
189
+ this.clientPromise = Promise.resolve(options.client);
190
+ }
191
+ else {
192
+ this.clientPromise = this.connectFromUrl(options.url);
193
+ }
194
+ }
195
+ async connectFromUrl(url) {
196
+ try {
197
+ // @ts-expect-error - ioredis is an optional peer dependency
198
+ const mod = (await import('ioredis'));
199
+ const Redis = mod.default;
200
+ const raw = new Redis(url);
201
+ this.ownedRedis = raw;
202
+ return adaptIoRedisClient(raw);
203
+ }
204
+ catch (err) {
205
+ this.onWarn('Failed to load optional peer "ioredis". Install it or pass a pre-configured "client".', err);
206
+ throw err;
207
+ }
208
+ }
209
+ warn(message, error) {
210
+ this.onWarn(message, error);
211
+ }
212
+ async getClient() {
213
+ if (this.client) {
214
+ return this.client;
215
+ }
216
+ const c = await this.clientPromise;
217
+ this.client = c;
218
+ return c;
219
+ }
220
+ redisKey(kind, key) {
221
+ return `${this.keyPrefix}${kind}:${key}`;
222
+ }
223
+ async evalScript(script, keys, args) {
224
+ try {
225
+ const r = await this.getClient();
226
+ const flat = [...keys.map(String), ...args.map(String)];
227
+ return await r.eval(script, keys.length, ...flat);
228
+ }
229
+ catch (err) {
230
+ this.warn('Redis EVAL failed', err);
231
+ return null;
232
+ }
233
+ }
234
+ async delKeys(...keys) {
235
+ if (keys.length === 0) {
236
+ return;
237
+ }
238
+ try {
239
+ const r = await this.getClient();
240
+ if (r.del) {
241
+ await r.del(...keys);
242
+ return;
243
+ }
244
+ await r.eval(LUA_DEL, keys.length, ...keys.map(String));
245
+ }
246
+ catch (err) {
247
+ this.warn('Redis DEL failed', err);
248
+ }
249
+ }
250
+ failOpenResult() {
251
+ const now = Date.now();
252
+ if (this.strategy === RateLimitStrategy.TOKEN_BUCKET) {
253
+ return {
254
+ totalHits: 0,
255
+ remaining: this.bucketSize,
256
+ resetTime: new Date(now + this.refillIntervalMs),
257
+ isBlocked: false,
258
+ };
259
+ }
260
+ return {
261
+ totalHits: 0,
262
+ remaining: this.maxRequests,
263
+ resetTime: new Date(now + this.windowMs),
264
+ isBlocked: false,
265
+ };
266
+ }
267
+ /** @inheritdoc */
268
+ async increment(key) {
269
+ switch (this.strategy) {
270
+ case RateLimitStrategy.SLIDING_WINDOW:
271
+ return this.incrSliding(key);
272
+ case RateLimitStrategy.FIXED_WINDOW:
273
+ return this.incrFixed(key);
274
+ case RateLimitStrategy.TOKEN_BUCKET:
275
+ return this.incrBucket(key);
276
+ default: {
277
+ const _ = this.strategy;
278
+ return Promise.reject(new Error(`Unsupported strategy: ${String(_)}`));
279
+ }
280
+ }
281
+ }
282
+ async incrSliding(key) {
283
+ const now = Date.now();
284
+ const member = `${now}:${Math.random().toString(36).slice(2)}`;
285
+ const rk = this.redisKey('sw', key);
286
+ const raw = await this.evalScript(LUA_SLIDING_INCR, [rk], [now, this.windowMs, this.maxRequests, member]);
287
+ if (raw === null || !Array.isArray(raw) || raw.length < 3) {
288
+ return this.failOpenResult();
289
+ }
290
+ const count = Number(raw[0]);
291
+ const blocked = Number(raw[1]) === 1;
292
+ const resetMs = Number(raw[2]);
293
+ if (Number.isNaN(count) || Number.isNaN(resetMs)) {
294
+ return this.failOpenResult();
295
+ }
296
+ const remaining = blocked ? 0 : Math.max(0, this.maxRequests - count);
297
+ return {
298
+ totalHits: count,
299
+ remaining,
300
+ resetTime: new Date(resetMs),
301
+ isBlocked: blocked,
302
+ };
303
+ }
304
+ async incrFixed(key) {
305
+ const now = Date.now();
306
+ const rk = this.redisKey('fw', key);
307
+ const raw = await this.evalScript(LUA_FIXED_INCR, [rk], [this.windowMs, this.maxRequests, now]);
308
+ if (raw === null || !Array.isArray(raw) || raw.length < 3) {
309
+ return this.failOpenResult();
310
+ }
311
+ const current = Number(raw[0]);
312
+ const blocked = Number(raw[1]) === 1;
313
+ const resetMs = Number(raw[2]);
314
+ if (Number.isNaN(current) || Number.isNaN(resetMs)) {
315
+ return this.failOpenResult();
316
+ }
317
+ const remaining = blocked ? 0 : Math.max(0, this.maxRequests - current);
318
+ return {
319
+ totalHits: current,
320
+ remaining,
321
+ resetTime: new Date(resetMs),
322
+ isBlocked: blocked,
323
+ };
324
+ }
325
+ async incrBucket(key) {
326
+ const now = Date.now();
327
+ const rk = this.redisKey('tb', key);
328
+ const raw = await this.evalScript(LUA_BUCKET_INCR, [rk], [now, this.tokensPerInterval, this.refillIntervalMs, this.bucketSize]);
329
+ if (raw === null || !Array.isArray(raw) || raw.length < 5) {
330
+ return this.failOpenResult();
331
+ }
332
+ const remaining = Number(raw[1]);
333
+ const totalHits = Number(raw[2]);
334
+ const blocked = Number(raw[3]) === 1;
335
+ const nextMs = Number(raw[4]);
336
+ if (Number.isNaN(remaining) || Number.isNaN(totalHits) || Number.isNaN(nextMs)) {
337
+ return this.failOpenResult();
338
+ }
339
+ return {
340
+ totalHits,
341
+ remaining,
342
+ resetTime: new Date(nextMs),
343
+ isBlocked: blocked,
344
+ };
345
+ }
346
+ /** @inheritdoc */
347
+ async decrement(key) {
348
+ try {
349
+ switch (this.strategy) {
350
+ case RateLimitStrategy.SLIDING_WINDOW: {
351
+ const rk = this.redisKey('sw', key);
352
+ await this.evalScript(LUA_SLIDING_DECR, [rk], []);
353
+ break;
354
+ }
355
+ case RateLimitStrategy.FIXED_WINDOW: {
356
+ const rk = this.redisKey('fw', key);
357
+ await this.evalScript(LUA_FIXED_DECR, [rk], []);
358
+ break;
359
+ }
360
+ case RateLimitStrategy.TOKEN_BUCKET: {
361
+ const rk = this.redisKey('tb', key);
362
+ await this.evalScript(LUA_BUCKET_DECR, [rk], [this.bucketSize]);
363
+ break;
364
+ }
365
+ default:
366
+ break;
367
+ }
368
+ }
369
+ catch (err) {
370
+ this.warn('Redis decrement failed', err);
371
+ }
372
+ }
373
+ /** @inheritdoc */
374
+ async reset(key) {
375
+ const keys = [];
376
+ switch (this.strategy) {
377
+ case RateLimitStrategy.SLIDING_WINDOW:
378
+ keys.push(this.redisKey('sw', key));
379
+ break;
380
+ case RateLimitStrategy.FIXED_WINDOW:
381
+ keys.push(this.redisKey('fw', key));
382
+ break;
383
+ case RateLimitStrategy.TOKEN_BUCKET:
384
+ keys.push(this.redisKey('tb', key));
385
+ break;
386
+ default:
387
+ break;
388
+ }
389
+ await this.delKeys(...keys);
390
+ }
391
+ /** @inheritdoc */
392
+ async shutdown() {
393
+ this.client = null;
394
+ const owned = this.ownedRedis;
395
+ this.ownedRedis = null;
396
+ if (!owned) {
397
+ return Promise.resolve();
398
+ }
399
+ try {
400
+ if (typeof owned.quit === 'function') {
401
+ await owned.quit();
402
+ }
403
+ else if (typeof owned.disconnect === 'function') {
404
+ await owned.disconnect();
405
+ }
406
+ }
407
+ catch (err) {
408
+ this.warn('Redis shutdown (quit/disconnect) failed', err);
409
+ }
410
+ return Promise.resolve();
411
+ }
412
+ }
413
+ //# sourceMappingURL=redis-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-store.js","sourceRoot":"","sources":["../../src/stores/redis-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { RateLimitStrategy } from '../types/index.js';
2
+ /**
3
+ * Sensible defaults for sliding-window rate limiting (no {@link RateLimitOptionsBase.store} — pass a store or use {@link createRateLimiter}).
4
+ */
5
+ export declare const slidingWindowDefaults: {
6
+ readonly strategy: RateLimitStrategy.SLIDING_WINDOW;
7
+ readonly windowMs: 60000;
8
+ readonly maxRequests: 100;
9
+ };
10
+ /**
11
+ * Sensible defaults for fixed-window rate limiting.
12
+ */
13
+ export declare const fixedWindowDefaults: {
14
+ readonly strategy: RateLimitStrategy.FIXED_WINDOW;
15
+ readonly windowMs: 60000;
16
+ readonly maxRequests: 100;
17
+ };
18
+ /**
19
+ * Sensible defaults for token-bucket rate limiting.
20
+ * Use {@link TokenBucketRateLimitOptions.bucketSize} for burst capacity (not `maxRequests`).
21
+ */
22
+ export declare const tokenBucketDefaults: {
23
+ readonly strategy: RateLimitStrategy.TOKEN_BUCKET;
24
+ readonly tokensPerInterval: 10;
25
+ readonly interval: 60000;
26
+ readonly bucketSize: 100;
27
+ };
28
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/strategies/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;CAIxB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;CAItB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { RateLimitStrategy } from '../types/index.js';
2
+ /**
3
+ * Sensible defaults for sliding-window rate limiting (no {@link RateLimitOptionsBase.store} — pass a store or use {@link createRateLimiter}).
4
+ */
5
+ export const slidingWindowDefaults = {
6
+ strategy: RateLimitStrategy.SLIDING_WINDOW,
7
+ windowMs: 60000,
8
+ maxRequests: 100,
9
+ };
10
+ /**
11
+ * Sensible defaults for fixed-window rate limiting.
12
+ */
13
+ export const fixedWindowDefaults = {
14
+ strategy: RateLimitStrategy.FIXED_WINDOW,
15
+ windowMs: 60000,
16
+ maxRequests: 100,
17
+ };
18
+ /**
19
+ * Sensible defaults for token-bucket rate limiting.
20
+ * Use {@link TokenBucketRateLimitOptions.bucketSize} for burst capacity (not `maxRequests`).
21
+ */
22
+ export const tokenBucketDefaults = {
23
+ strategy: RateLimitStrategy.TOKEN_BUCKET,
24
+ tokensPerInterval: 10,
25
+ interval: 60000,
26
+ bucketSize: 100,
27
+ };
28
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/strategies/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,QAAQ,EAAE,iBAAiB,CAAC,cAAc;IAC1C,QAAQ,EAAE,KAAM;IAChB,WAAW,EAAE,GAAG;CACR,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,QAAQ,EAAE,iBAAiB,CAAC,YAAY;IACxC,QAAQ,EAAE,KAAM;IAChB,WAAW,EAAE,GAAG;CACR,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,QAAQ,EAAE,iBAAiB,CAAC,YAAY;IACxC,iBAAiB,EAAE,EAAE;IACrB,QAAQ,EAAE,KAAM;IAChB,UAAU,EAAE,GAAG;CACP,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Rate limiting strategies (sliding window, token bucket, etc.) */
2
+ export { RateLimitEngine, createRateLimiter, defaultKeyGenerator, type RateLimitConsumeResult, type RateLimiterConfigInput, } from './rate-limit-engine.js';
3
+ export { fixedWindowDefaults, slidingWindowDefaults, tokenBucketDefaults } from './defaults.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/strategies/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Rate limiting strategies (sliding window, token bucket, etc.) */
2
+ export { RateLimitEngine, createRateLimiter, defaultKeyGenerator, } from './rate-limit-engine.js';
3
+ export { fixedWindowDefaults, slidingWindowDefaults, tokenBucketDefaults } from './defaults.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/strategies/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { RateLimitOptions, RateLimitResult, RateLimitStore, TokenBucketRateLimitOptions, WindowRateLimitOptions } from '../types/index.js';
2
+ /** Result of {@link RateLimitEngine.consume} including standard rate-limit headers. */
3
+ export interface RateLimitConsumeResult extends RateLimitResult {
4
+ headers: Record<string, string>;
5
+ }
6
+ /** Options for {@link createRateLimiter}: `store` is optional — a {@link MemoryStore} is created when omitted. */
7
+ export type RateLimiterConfigInput = (Omit<WindowRateLimitOptions, 'store'> & {
8
+ store?: RateLimitStore;
9
+ }) | (Omit<TokenBucketRateLimitOptions, 'store'> & {
10
+ store?: RateLimitStore;
11
+ });
12
+ /**
13
+ * Default key extractor: uses `req.ip`, then `socket.remoteAddress`, else `"unknown"`.
14
+ * Strings are returned as-is so you can pass a precomputed key.
15
+ */
16
+ export declare function defaultKeyGenerator(req: unknown): string;
17
+ /**
18
+ * Build a {@link RateLimitEngine} with optional in-memory store when `store` is omitted.
19
+ */
20
+ export declare function createRateLimiter(options: RateLimiterConfigInput): RateLimitEngine;
21
+ /**
22
+ * Orchestrates key extraction, store increments, header generation, and limit callbacks.
23
+ */
24
+ export declare class RateLimitEngine {
25
+ private readonly options;
26
+ constructor(options: RateLimitOptions);
27
+ /**
28
+ * Applies rate limiting for an incoming request-like value.
29
+ * Uses {@link RateLimitOptionsBase.keyGenerator} (or {@link defaultKeyGenerator}) to derive the storage key.
30
+ */
31
+ consume(req: unknown): Promise<RateLimitConsumeResult>;
32
+ /**
33
+ * Rate limit using a precomputed storage key (skips `keyGenerator`).
34
+ * Pass the same `req` for `onLimitReached` / `skip` callbacks when applicable.
35
+ */
36
+ consumeWithKey(key: string, req?: unknown): Promise<RateLimitConsumeResult>;
37
+ private getLimit;
38
+ private buildPassthroughResult;
39
+ private buildHeaders;
40
+ private composeHeaders;
41
+ }
42
+ //# sourceMappingURL=rate-limit-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-engine.d.ts","sourceRoot":"","sources":["../../src/strategies/rate-limit-engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAG3B,uFAAuF;AACvF,MAAM,WAAW,sBAAuB,SAAQ,eAAe;IAC7D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,kHAAkH;AAClH,MAAM,MAAM,sBAAsB,GAC9B,CAAC,IAAI,CAAC,sBAAsB,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,cAAc,CAAA;CAAE,CAAC,GACpE,CAAC,IAAI,CAAC,2BAA2B,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AAE9E;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAkBxD;AAuBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAElF;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;gBAE/B,OAAO,EAAE,gBAAgB;IAIrC;;;OAGG;IACG,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAK5D;;;OAGG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,OAAa,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAetF,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,cAAc;CAuBvB"}