@zeitar/throttle 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 (163) hide show
  1. package/LICENSE.md +24 -0
  2. package/README.md +204 -0
  3. package/dist/CompoundLimiter.d.ts +33 -0
  4. package/dist/CompoundLimiter.d.ts.map +1 -0
  5. package/dist/CompoundLimiter.js +62 -0
  6. package/dist/CompoundLimiter.js.map +1 -0
  7. package/dist/CompoundRateLimiterFactory.d.ts +19 -0
  8. package/dist/CompoundRateLimiterFactory.d.ts.map +1 -0
  9. package/dist/CompoundRateLimiterFactory.js +29 -0
  10. package/dist/CompoundRateLimiterFactory.js.map +1 -0
  11. package/dist/LimiterInterface.d.ts +32 -0
  12. package/dist/LimiterInterface.d.ts.map +1 -0
  13. package/dist/LimiterInterface.js +3 -0
  14. package/dist/LimiterInterface.js.map +1 -0
  15. package/dist/LimiterStateInterface.d.ts +16 -0
  16. package/dist/LimiterStateInterface.d.ts.map +1 -0
  17. package/dist/LimiterStateInterface.js +3 -0
  18. package/dist/LimiterStateInterface.js.map +1 -0
  19. package/dist/RateLimit.d.ts +43 -0
  20. package/dist/RateLimit.d.ts.map +1 -0
  21. package/dist/RateLimit.js +68 -0
  22. package/dist/RateLimit.js.map +1 -0
  23. package/dist/RateLimiterFactory.d.ts +83 -0
  24. package/dist/RateLimiterFactory.d.ts.map +1 -0
  25. package/dist/RateLimiterFactory.js +115 -0
  26. package/dist/RateLimiterFactory.js.map +1 -0
  27. package/dist/RateLimiterFactoryInterface.d.ts +17 -0
  28. package/dist/RateLimiterFactoryInterface.d.ts.map +1 -0
  29. package/dist/RateLimiterFactoryInterface.js +3 -0
  30. package/dist/RateLimiterFactoryInterface.js.map +1 -0
  31. package/dist/Reservation.d.ts +29 -0
  32. package/dist/Reservation.d.ts.map +1 -0
  33. package/dist/Reservation.js +44 -0
  34. package/dist/Reservation.js.map +1 -0
  35. package/dist/__tests__/CompoundLimiter.test.d.ts +2 -0
  36. package/dist/__tests__/CompoundLimiter.test.d.ts.map +1 -0
  37. package/dist/__tests__/CompoundLimiter.test.js +231 -0
  38. package/dist/__tests__/CompoundLimiter.test.js.map +1 -0
  39. package/dist/__tests__/CompoundRateLimiterFactory.test.d.ts +2 -0
  40. package/dist/__tests__/CompoundRateLimiterFactory.test.d.ts.map +1 -0
  41. package/dist/__tests__/CompoundRateLimiterFactory.test.js +213 -0
  42. package/dist/__tests__/CompoundRateLimiterFactory.test.js.map +1 -0
  43. package/dist/__tests__/RateLimit.test.d.ts +2 -0
  44. package/dist/__tests__/RateLimit.test.d.ts.map +1 -0
  45. package/dist/__tests__/RateLimit.test.js +108 -0
  46. package/dist/__tests__/RateLimit.test.js.map +1 -0
  47. package/dist/__tests__/RateLimiterFactory.test.d.ts +2 -0
  48. package/dist/__tests__/RateLimiterFactory.test.d.ts.map +1 -0
  49. package/dist/__tests__/RateLimiterFactory.test.js +323 -0
  50. package/dist/__tests__/RateLimiterFactory.test.js.map +1 -0
  51. package/dist/__tests__/Reservation.test.d.ts +2 -0
  52. package/dist/__tests__/Reservation.test.d.ts.map +1 -0
  53. package/dist/__tests__/Reservation.test.js +110 -0
  54. package/dist/__tests__/Reservation.test.js.map +1 -0
  55. package/dist/errors/InvalidIntervalError.d.ts +10 -0
  56. package/dist/errors/InvalidIntervalError.d.ts.map +1 -0
  57. package/dist/errors/InvalidIntervalError.js +18 -0
  58. package/dist/errors/InvalidIntervalError.js.map +1 -0
  59. package/dist/errors/MaxWaitDurationExceededError.d.ts +15 -0
  60. package/dist/errors/MaxWaitDurationExceededError.d.ts.map +1 -0
  61. package/dist/errors/MaxWaitDurationExceededError.js +24 -0
  62. package/dist/errors/MaxWaitDurationExceededError.js.map +1 -0
  63. package/dist/errors/RateLimitExceededError.d.ts +27 -0
  64. package/dist/errors/RateLimitExceededError.d.ts.map +1 -0
  65. package/dist/errors/RateLimitExceededError.js +42 -0
  66. package/dist/errors/RateLimitExceededError.js.map +1 -0
  67. package/dist/errors/ReserveNotSupportedError.d.ts +10 -0
  68. package/dist/errors/ReserveNotSupportedError.d.ts.map +1 -0
  69. package/dist/errors/ReserveNotSupportedError.js +18 -0
  70. package/dist/errors/ReserveNotSupportedError.js.map +1 -0
  71. package/dist/index.d.ts +35 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +58 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/policy/FixedWindowLimiter.d.ts +36 -0
  76. package/dist/policy/FixedWindowLimiter.d.ts.map +1 -0
  77. package/dist/policy/FixedWindowLimiter.js +105 -0
  78. package/dist/policy/FixedWindowLimiter.js.map +1 -0
  79. package/dist/policy/NoLimiter.d.ts +23 -0
  80. package/dist/policy/NoLimiter.d.ts.map +1 -0
  81. package/dist/policy/NoLimiter.js +34 -0
  82. package/dist/policy/NoLimiter.js.map +1 -0
  83. package/dist/policy/Rate.d.ts +69 -0
  84. package/dist/policy/Rate.d.ts.map +1 -0
  85. package/dist/policy/Rate.js +121 -0
  86. package/dist/policy/Rate.js.map +1 -0
  87. package/dist/policy/SlidingWindow.d.ts +74 -0
  88. package/dist/policy/SlidingWindow.d.ts.map +1 -0
  89. package/dist/policy/SlidingWindow.js +130 -0
  90. package/dist/policy/SlidingWindow.js.map +1 -0
  91. package/dist/policy/SlidingWindowLimiter.d.ts +41 -0
  92. package/dist/policy/SlidingWindowLimiter.d.ts.map +1 -0
  93. package/dist/policy/SlidingWindowLimiter.js +127 -0
  94. package/dist/policy/SlidingWindowLimiter.js.map +1 -0
  95. package/dist/policy/TokenBucket.d.ts +63 -0
  96. package/dist/policy/TokenBucket.d.ts.map +1 -0
  97. package/dist/policy/TokenBucket.js +92 -0
  98. package/dist/policy/TokenBucket.js.map +1 -0
  99. package/dist/policy/TokenBucketLimiter.d.ts +38 -0
  100. package/dist/policy/TokenBucketLimiter.d.ts.map +1 -0
  101. package/dist/policy/TokenBucketLimiter.js +114 -0
  102. package/dist/policy/TokenBucketLimiter.js.map +1 -0
  103. package/dist/policy/Window.d.ts +58 -0
  104. package/dist/policy/Window.d.ts.map +1 -0
  105. package/dist/policy/Window.js +105 -0
  106. package/dist/policy/Window.js.map +1 -0
  107. package/dist/policy/__tests__/FixedWindowLimiter.test.d.ts +2 -0
  108. package/dist/policy/__tests__/FixedWindowLimiter.test.d.ts.map +1 -0
  109. package/dist/policy/__tests__/FixedWindowLimiter.test.js +180 -0
  110. package/dist/policy/__tests__/FixedWindowLimiter.test.js.map +1 -0
  111. package/dist/policy/__tests__/NoLimiter.test.d.ts +2 -0
  112. package/dist/policy/__tests__/NoLimiter.test.d.ts.map +1 -0
  113. package/dist/policy/__tests__/NoLimiter.test.js +40 -0
  114. package/dist/policy/__tests__/NoLimiter.test.js.map +1 -0
  115. package/dist/policy/__tests__/Rate.test.d.ts +2 -0
  116. package/dist/policy/__tests__/Rate.test.d.ts.map +1 -0
  117. package/dist/policy/__tests__/Rate.test.js +162 -0
  118. package/dist/policy/__tests__/Rate.test.js.map +1 -0
  119. package/dist/policy/__tests__/SlidingWindow.test.d.ts +2 -0
  120. package/dist/policy/__tests__/SlidingWindow.test.d.ts.map +1 -0
  121. package/dist/policy/__tests__/SlidingWindow.test.js +257 -0
  122. package/dist/policy/__tests__/SlidingWindow.test.js.map +1 -0
  123. package/dist/policy/__tests__/SlidingWindowLimiter.test.d.ts +2 -0
  124. package/dist/policy/__tests__/SlidingWindowLimiter.test.d.ts.map +1 -0
  125. package/dist/policy/__tests__/SlidingWindowLimiter.test.js +201 -0
  126. package/dist/policy/__tests__/SlidingWindowLimiter.test.js.map +1 -0
  127. package/dist/policy/__tests__/TokenBucket.test.d.ts +2 -0
  128. package/dist/policy/__tests__/TokenBucket.test.d.ts.map +1 -0
  129. package/dist/policy/__tests__/TokenBucket.test.js +171 -0
  130. package/dist/policy/__tests__/TokenBucket.test.js.map +1 -0
  131. package/dist/policy/__tests__/TokenBucketLimiter.test.d.ts +2 -0
  132. package/dist/policy/__tests__/TokenBucketLimiter.test.d.ts.map +1 -0
  133. package/dist/policy/__tests__/TokenBucketLimiter.test.js +175 -0
  134. package/dist/policy/__tests__/TokenBucketLimiter.test.js.map +1 -0
  135. package/dist/policy/__tests__/Window.test.d.ts +2 -0
  136. package/dist/policy/__tests__/Window.test.d.ts.map +1 -0
  137. package/dist/policy/__tests__/Window.test.js +193 -0
  138. package/dist/policy/__tests__/Window.test.js.map +1 -0
  139. package/dist/storage/InMemoryStorage.d.ts +34 -0
  140. package/dist/storage/InMemoryStorage.d.ts.map +1 -0
  141. package/dist/storage/InMemoryStorage.js +62 -0
  142. package/dist/storage/InMemoryStorage.js.map +1 -0
  143. package/dist/storage/LockInterface.d.ts +41 -0
  144. package/dist/storage/LockInterface.d.ts.map +1 -0
  145. package/dist/storage/LockInterface.js +19 -0
  146. package/dist/storage/LockInterface.js.map +1 -0
  147. package/dist/storage/StorageInterface.d.ts +29 -0
  148. package/dist/storage/StorageInterface.d.ts.map +1 -0
  149. package/dist/storage/StorageInterface.js +3 -0
  150. package/dist/storage/StorageInterface.js.map +1 -0
  151. package/dist/storage/__tests__/InMemoryStorage.test.d.ts +2 -0
  152. package/dist/storage/__tests__/InMemoryStorage.test.d.ts.map +1 -0
  153. package/dist/storage/__tests__/InMemoryStorage.test.js +154 -0
  154. package/dist/storage/__tests__/InMemoryStorage.test.js.map +1 -0
  155. package/dist/util/TimeUtil.d.ts +35 -0
  156. package/dist/util/TimeUtil.d.ts.map +1 -0
  157. package/dist/util/TimeUtil.js +87 -0
  158. package/dist/util/TimeUtil.js.map +1 -0
  159. package/dist/util/__tests__/TimeUtil.test.d.ts +2 -0
  160. package/dist/util/__tests__/TimeUtil.test.d.ts.map +1 -0
  161. package/dist/util/__tests__/TimeUtil.test.js +132 -0
  162. package/dist/util/__tests__/TimeUtil.test.js.map +1 -0
  163. package/package.json +59 -0
package/LICENSE.md ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Khaled Zeitar
4
+
5
+ This library implements rate limiting algorithms with architecture inspired by
6
+ Symfony's Rate Limiter component.
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # @zeitar/throttle
2
+
3
+ A production-ready TypeScript rate limiting library with support for multiple algorithms.
4
+
5
+ > Architecture inspired by [Symfony's Rate Limiter component](https://symfony.com/doc/current/rate_limiter.html), implemented natively in TypeScript with async/await patterns for Node.js.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@zeitar/throttle.svg)](https://www.npmjs.com/package/@zeitar/throttle)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ## Features
11
+
12
+ - 🚀 **Multiple Algorithms**: Token Bucket, Fixed Window, Sliding Window, and No-Limit policies
13
+ - 📦 **TypeScript Native**: Full type safety with strict typing
14
+ - 🔒 **Production Ready**: Thread-safe with optional distributed locking support
15
+ - 🧩 **Composable**: Combine multiple limiters with CompoundLimiter
16
+ - 💾 **Pluggable Storage**: In-memory storage included, easily extend for Redis, etc.
17
+ - ⚡ **High Performance**: Efficient algorithms with minimal overhead (O(1) time complexity)
18
+ - 🎯 **Zero Dependencies**: Core library has no external dependencies
19
+ - 🔌 **Framework Agnostic**: Works with Express, Fastify, or any Node.js framework
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @zeitar/throttle
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { RateLimiterFactory, InMemoryStorage } from '@zeitar/throttle';
31
+
32
+ // Create a rate limiter factory
33
+ const factory = new RateLimiterFactory(
34
+ {
35
+ policy: 'token_bucket',
36
+ id: 'api',
37
+ limit: 100, // Burst size
38
+ rate: {
39
+ interval: '1 hour', // Refill interval
40
+ amount: 100 // Tokens per interval
41
+ }
42
+ },
43
+ new InMemoryStorage()
44
+ );
45
+
46
+ // Create a limiter for a specific user
47
+ const limiter = factory.create('user-123');
48
+
49
+ // Try to consume tokens
50
+ const result = await limiter.consume(5);
51
+
52
+ if (result.isAccepted()) {
53
+ console.log(`✓ Request accepted! ${result.getRemainingTokens()} tokens remaining`);
54
+ } else {
55
+ console.log(`✗ Rate limited. Retry after ${result.getRetryAfter()} seconds`);
56
+ }
57
+ ```
58
+
59
+ ## Express Middleware Example
60
+
61
+ ```typescript
62
+ import { RateLimiterFactory, InMemoryStorage } from '@zeitar/throttle';
63
+ import type { Request, Response, NextFunction } from 'express';
64
+
65
+ const factory = new RateLimiterFactory(
66
+ {
67
+ policy: 'token_bucket',
68
+ id: 'api',
69
+ limit: 100,
70
+ rate: { interval: '1 minute', amount: 100 }
71
+ },
72
+ new InMemoryStorage()
73
+ );
74
+
75
+ app.use(async (req: Request, res: Response, next: NextFunction) => {
76
+ const limiter = factory.create(req.ip);
77
+ const result = await limiter.consume();
78
+
79
+ res.setHeader('X-RateLimit-Remaining', result.getRemainingTokens().toString());
80
+
81
+ if (!result.isAccepted()) {
82
+ res.setHeader('Retry-After', result.getRetryAfter().toString());
83
+ return res.status(429).json({
84
+ error: 'Too many requests',
85
+ retryAfter: result.getRetryAfter()
86
+ });
87
+ }
88
+
89
+ next();
90
+ });
91
+ ```
92
+
93
+ ## Documentation
94
+
95
+ ### Getting Started
96
+ - **[Getting Started Guide](./docs/getting-started.md)** - Installation, basic usage, and testing
97
+ - **[Choosing an Algorithm](./docs/algorithms.md)** - Algorithm comparison and selection guide
98
+ - **[Framework Integration](./docs/framework-integration.md)** - Express, Fastify, NestJS, Koa, Hono examples
99
+
100
+ ### Core Concepts
101
+ - **[Common Patterns](./docs/common-patterns.md)** - User tiers, endpoint limits, global+per-user patterns
102
+ - **[Advanced Usage](./docs/advanced-usage.md)** - Reservation pattern, compound limiters, dynamic creation
103
+ - **[Custom Storage](./docs/custom-storage.md)** - Redis, PostgreSQL, DynamoDB implementations
104
+ - **[API Reference](./docs/api-reference.md)** - Complete API documentation
105
+
106
+ ### Help & Troubleshooting
107
+ - **[Troubleshooting](./docs/troubleshooting.md)** - Common issues and solutions
108
+
109
+ ## Algorithm Comparison
110
+
111
+ | Algorithm | Best For | Allows Bursts? | Precision |
112
+ |-----------|----------|----------------|-----------|
113
+ | **Token Bucket** ⭐ | Most APIs, microservices | ✅ Yes | Medium |
114
+ | **Fixed Window** | Daily quotas, analytics | ⚠️ At boundaries | Low |
115
+ | **Sliding Window** | High-security APIs, payments | ❌ No | High |
116
+ | **No Limit** | Testing, feature flags | ✅ Always | N/A |
117
+
118
+ **Not sure which to choose?** See the [Algorithm Guide](./docs/algorithms.md).
119
+
120
+ ## Key Features
121
+
122
+ ### Multiple Rate Limits (Compound Limiter)
123
+
124
+ ```typescript
125
+ import { CompoundRateLimiterFactory } from '@zeitar/throttle';
126
+
127
+ // Enforce BOTH limits simultaneously
128
+ const compound = new CompoundRateLimiterFactory([
129
+ perSecondFactory, // 10/second
130
+ perMinuteFactory // 100/minute
131
+ ]);
132
+
133
+ const limiter = compound.create('user-123');
134
+ ```
135
+
136
+ ### Reservation Pattern
137
+
138
+ ```typescript
139
+ // Reserve tokens and wait for availability
140
+ const reservation = await limiter.reserve(10, 5); // Wait max 5 seconds
141
+ await reservation.wait();
142
+ // Tokens are now reserved, proceed with operation
143
+ ```
144
+
145
+ ### Distributed Systems
146
+
147
+ ```typescript
148
+ // Use Redis for multi-server deployments
149
+ import { RedisStorage, RedisLock } from './your-impl';
150
+
151
+ const factory = new RateLimiterFactory(
152
+ config,
153
+ new RedisStorage(redisClient),
154
+ new RedisLock(redisClient)
155
+ );
156
+ ```
157
+
158
+ See [Custom Storage](./docs/custom-storage.md) for implementation.
159
+
160
+ ## Performance
161
+
162
+ - **All algorithms**: O(1) time complexity
163
+ - **Memory usage**: ~100 bytes per active limiter
164
+ - **Throughput**: Designed for high-concurrency scenarios
165
+ - **Storage**: Pluggable backend (in-memory, Redis, database)
166
+
167
+ ## Architecture
168
+
169
+ This library uses several design patterns for flexibility and maintainability:
170
+
171
+ - **Strategy Pattern**: Different algorithms implement `LimiterInterface`
172
+ - **Factory Pattern**: `RateLimiterFactory` creates configured limiters
173
+ - **Composite Pattern**: `CompoundLimiter` combines multiple limiters
174
+ - **Dependency Injection**: Storage and locking are pluggable
175
+
176
+ Inspired by [Symfony's Rate Limiter](https://github.com/symfony/rate-limiter) with full TypeScript support and async/await patterns.
177
+
178
+ ## Testing
179
+
180
+ ```typescript
181
+ import { NoLimiter, InMemoryStorage } from '@zeitar/throttle';
182
+
183
+ // Use NoLimiter for tests that shouldn't be rate limited
184
+ const limiter = new NoLimiter();
185
+
186
+ // Or clear InMemoryStorage between tests
187
+ const storage = new InMemoryStorage();
188
+ storage.clear();
189
+ ```
190
+
191
+ ## Contributing
192
+
193
+ Contributions welcome! Please open an issue or PR.
194
+
195
+ ## License
196
+
197
+ MIT © 2025 Khaled Zeitar
198
+
199
+ ## Credits & Acknowledgments
200
+
201
+ - **Implementation**: © 2025 Khaled Zeitar - Original TypeScript implementation
202
+ - **Architectural inspiration**: [Symfony Rate Limiter](https://github.com/symfony/rate-limiter) by Fabien Potencier and contributors
203
+
204
+ While the code is written from scratch in TypeScript, the design patterns, API structure, and architectural decisions are influenced by Symfony's proven approach to rate limiting.
@@ -0,0 +1,33 @@
1
+ import type { LimiterInterface } from './LimiterInterface';
2
+ import type { RateLimit } from './RateLimit';
3
+ import { Reservation } from './Reservation';
4
+ /**
5
+ * Compound rate limiter that combines multiple limiters.
6
+ *
7
+ * Uses AND logic: all limiters must accept for the request to be accepted.
8
+ * Returns the most restrictive result (lowest available tokens, longest retry time).
9
+ *
10
+ * Note: Does NOT support the reserve() pattern due to complexity of coordinating
11
+ * multiple reservations.
12
+ */
13
+ export declare class CompoundLimiter implements LimiterInterface {
14
+ private readonly limiters;
15
+ constructor(limiters: LimiterInterface[]);
16
+ /**
17
+ * Reserve is not supported by compound limiters.
18
+ *
19
+ * @throws {ReserveNotSupportedError} Always throws
20
+ */
21
+ reserve(_tokens?: number, _maxTime?: number | null): Promise<Reservation>;
22
+ /**
23
+ * Try to consume tokens from all limiters.
24
+ *
25
+ * Returns the most restrictive result if any limiter rejects.
26
+ */
27
+ consume(tokens?: number): Promise<RateLimit>;
28
+ /**
29
+ * Reset all limiters.
30
+ */
31
+ reset(): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=CompoundLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompoundLimiter.d.ts","sourceRoot":"","sources":["../src/CompoundLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C;;;;;;;;GAQG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,QAAQ,EAAE,gBAAgB,EAAE;IAOxC;;;;OAIG;IACG,OAAO,CAAC,OAAO,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAMxF;;;;OAIG;IACG,OAAO,CAAC,MAAM,GAAE,MAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IA4BrD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompoundLimiter = void 0;
4
+ const ReserveNotSupportedError_1 = require("./errors/ReserveNotSupportedError");
5
+ /**
6
+ * Compound rate limiter that combines multiple limiters.
7
+ *
8
+ * Uses AND logic: all limiters must accept for the request to be accepted.
9
+ * Returns the most restrictive result (lowest available tokens, longest retry time).
10
+ *
11
+ * Note: Does NOT support the reserve() pattern due to complexity of coordinating
12
+ * multiple reservations.
13
+ */
14
+ class CompoundLimiter {
15
+ constructor(limiters) {
16
+ if (limiters.length === 0) {
17
+ throw new Error('CompoundLimiter requires at least one limiter');
18
+ }
19
+ this.limiters = limiters;
20
+ }
21
+ /**
22
+ * Reserve is not supported by compound limiters.
23
+ *
24
+ * @throws {ReserveNotSupportedError} Always throws
25
+ */
26
+ async reserve(_tokens = 1, _maxTime = null) {
27
+ throw new ReserveNotSupportedError_1.ReserveNotSupportedError('CompoundLimiter does not support the reserve() method. Use consume() instead.');
28
+ }
29
+ /**
30
+ * Try to consume tokens from all limiters.
31
+ *
32
+ * Returns the most restrictive result if any limiter rejects.
33
+ */
34
+ async consume(tokens = 1) {
35
+ const results = await Promise.all(this.limiters.map(limiter => limiter.consume(tokens)));
36
+ // Find the most restrictive result
37
+ let mostRestrictive = results[0];
38
+ for (const result of results.slice(1)) {
39
+ // If current result is rejected and previous was accepted, or
40
+ // if both rejected but current has longer wait time, or
41
+ // if both accepted but current has fewer tokens
42
+ if ((!result.isAccepted() && mostRestrictive.isAccepted()) ||
43
+ (!result.isAccepted() &&
44
+ !mostRestrictive.isAccepted() &&
45
+ result.getRetryAfter() > mostRestrictive.getRetryAfter()) ||
46
+ (result.isAccepted() &&
47
+ mostRestrictive.isAccepted() &&
48
+ result.getRemainingTokens() < mostRestrictive.getRemainingTokens())) {
49
+ mostRestrictive = result;
50
+ }
51
+ }
52
+ return mostRestrictive;
53
+ }
54
+ /**
55
+ * Reset all limiters.
56
+ */
57
+ async reset() {
58
+ await Promise.all(this.limiters.map(limiter => limiter.reset()));
59
+ }
60
+ }
61
+ exports.CompoundLimiter = CompoundLimiter;
62
+ //# sourceMappingURL=CompoundLimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompoundLimiter.js","sourceRoot":"","sources":["../src/CompoundLimiter.ts"],"names":[],"mappings":";;;AAGA,gFAA6E;AAE7E;;;;;;;;GAQG;AACH,MAAa,eAAe;IAG1B,YAAY,QAA4B;QACtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,UAAkB,CAAC,EAAE,WAA0B,IAAI;QAC/D,MAAM,IAAI,mDAAwB,CAChC,+EAA+E,CAChF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,SAAiB,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CACtD,CAAC;QAEF,mCAAmC;QACnC,IAAI,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAEjC,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,8DAA8D;YAC9D,wDAAwD;YACxD,gDAAgD;YAChD,IACE,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,eAAe,CAAC,UAAU,EAAE,CAAC;gBACtD,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE;oBACnB,CAAC,eAAe,CAAC,UAAU,EAAE;oBAC7B,MAAM,CAAC,aAAa,EAAE,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC;gBAC3D,CAAC,MAAM,CAAC,UAAU,EAAE;oBAClB,eAAe,CAAC,UAAU,EAAE;oBAC5B,MAAM,CAAC,kBAAkB,EAAE,GAAG,eAAe,CAAC,kBAAkB,EAAE,CAAC,EACrE,CAAC;gBACD,eAAe,GAAG,MAAM,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,OAAO,eAAe,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;CACF;AA5DD,0CA4DC"}
@@ -0,0 +1,19 @@
1
+ import type { RateLimiterFactoryInterface } from './RateLimiterFactoryInterface';
2
+ import type { LimiterInterface } from './LimiterInterface';
3
+ /**
4
+ * Factory for creating compound rate limiters.
5
+ *
6
+ * Combines multiple factories to create a single limiter that enforces
7
+ * all policies simultaneously.
8
+ */
9
+ export declare class CompoundRateLimiterFactory implements RateLimiterFactoryInterface {
10
+ private readonly factories;
11
+ constructor(factories: RateLimiterFactoryInterface[]);
12
+ /**
13
+ * Create a compound rate limiter.
14
+ *
15
+ * @param key - Optional key passed to all underlying factories
16
+ */
17
+ create(key?: string | null): LimiterInterface;
18
+ }
19
+ //# sourceMappingURL=CompoundRateLimiterFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompoundRateLimiterFactory.d.ts","sourceRoot":"","sources":["../src/CompoundRateLimiterFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D;;;;;GAKG;AACH,qBAAa,0BAA2B,YAAW,2BAA2B;IAC5E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;gBAE9C,SAAS,EAAE,2BAA2B,EAAE;IAOpD;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB;CAI9C"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompoundRateLimiterFactory = void 0;
4
+ const CompoundLimiter_1 = require("./CompoundLimiter");
5
+ /**
6
+ * Factory for creating compound rate limiters.
7
+ *
8
+ * Combines multiple factories to create a single limiter that enforces
9
+ * all policies simultaneously.
10
+ */
11
+ class CompoundRateLimiterFactory {
12
+ constructor(factories) {
13
+ if (factories.length === 0) {
14
+ throw new Error('CompoundRateLimiterFactory requires at least one factory');
15
+ }
16
+ this.factories = factories;
17
+ }
18
+ /**
19
+ * Create a compound rate limiter.
20
+ *
21
+ * @param key - Optional key passed to all underlying factories
22
+ */
23
+ create(key) {
24
+ const limiters = this.factories.map(factory => factory.create(key));
25
+ return new CompoundLimiter_1.CompoundLimiter(limiters);
26
+ }
27
+ }
28
+ exports.CompoundRateLimiterFactory = CompoundRateLimiterFactory;
29
+ //# sourceMappingURL=CompoundRateLimiterFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompoundRateLimiterFactory.js","sourceRoot":"","sources":["../src/CompoundRateLimiterFactory.ts"],"names":[],"mappings":";;;AAEA,uDAAoD;AAEpD;;;;;GAKG;AACH,MAAa,0BAA0B;IAGrC,YAAY,SAAwC;QAClD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,GAAmB;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACpE,OAAO,IAAI,iCAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;CACF;AAnBD,gEAmBC"}
@@ -0,0 +1,32 @@
1
+ import type { RateLimit } from './RateLimit';
2
+ import type { Reservation } from './Reservation';
3
+ /**
4
+ * Main contract for all rate limiters.
5
+ *
6
+ * Provides two patterns for rate limiting:
7
+ * - reserve(): Reserve tokens and wait if necessary
8
+ * - consume(): Immediately try to consume tokens
9
+ */
10
+ export interface LimiterInterface {
11
+ /**
12
+ * Reserve tokens with optional maximum wait time.
13
+ *
14
+ * @param tokens - Number of tokens to reserve
15
+ * @param maxTime - Maximum time to wait (in seconds), or null for no limit
16
+ * @returns A Reservation object
17
+ * @throws {MaxWaitDurationExceededError} If wait time exceeds maxTime
18
+ */
19
+ reserve(tokens: number, maxTime?: number | null): Promise<Reservation>;
20
+ /**
21
+ * Try to consume tokens immediately.
22
+ *
23
+ * @param tokens - Number of tokens to consume
24
+ * @returns A RateLimit object indicating success or failure
25
+ */
26
+ consume(tokens: number): Promise<RateLimit>;
27
+ /**
28
+ * Reset the rate limiter state.
29
+ */
30
+ reset(): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=LimiterInterface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimiterInterface.d.ts","sourceRoot":"","sources":["../src/LimiterInterface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEvE;;;;;OAKG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAE5C;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=LimiterInterface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimiterInterface.js","sourceRoot":"","sources":["../src/LimiterInterface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Interface for serializable rate limiter state objects.
3
+ *
4
+ * State objects must be JSON-serializable and provide their own expiration time.
5
+ */
6
+ export interface LimiterStateInterface {
7
+ /**
8
+ * Get the unique identifier for this state object.
9
+ */
10
+ getId(): string;
11
+ /**
12
+ * Get the expiration time (in seconds since epoch) or null if no expiration.
13
+ */
14
+ getExpirationTime(): number | null;
15
+ }
16
+ //# sourceMappingURL=LimiterStateInterface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimiterStateInterface.d.ts","sourceRoot":"","sources":["../src/LimiterStateInterface.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,KAAK,IAAI,MAAM,CAAC;IAEhB;;OAEG;IACH,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAAC;CACpC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=LimiterStateInterface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimiterStateInterface.js","sourceRoot":"","sources":["../src/LimiterStateInterface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Result object from a rate limiting operation.
3
+ *
4
+ * Contains information about whether the request was accepted, how many tokens
5
+ * are remaining, and when the client should retry if rejected.
6
+ */
7
+ export declare class RateLimit {
8
+ private readonly availableTokens;
9
+ private readonly retryAfter;
10
+ private readonly accepted;
11
+ private readonly limit;
12
+ constructor(availableTokens: number, retryAfter: Date, accepted: boolean, limit: number);
13
+ /**
14
+ * Check if the request was accepted.
15
+ */
16
+ isAccepted(): boolean;
17
+ /**
18
+ * Ensure the request was accepted, throw an exception otherwise.
19
+ *
20
+ * @throws {RateLimitExceededError} If the request was not accepted
21
+ */
22
+ ensureAccepted(): this;
23
+ /**
24
+ * Get the date/time when the client should retry.
25
+ */
26
+ getRetryAfter(): Date;
27
+ /**
28
+ * Get the number of remaining tokens.
29
+ */
30
+ getRemainingTokens(): number;
31
+ /**
32
+ * Get the rate limit maximum.
33
+ */
34
+ getLimit(): number;
35
+ /**
36
+ * Wait until the retry time (blocking operation).
37
+ *
38
+ * Note: This uses a blocking setTimeout. Consider using async/await patterns
39
+ * in production code instead.
40
+ */
41
+ wait(): Promise<void>;
42
+ }
43
+ //# sourceMappingURL=RateLimit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RateLimit.d.ts","sourceRoot":"","sources":["../src/RateLimit.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAO;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAG7B,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,IAAI,EAChB,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM;IAQf;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;;;OAIG;IACH,cAAc,IAAI,IAAI;IAOtB;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ5B"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RateLimit = void 0;
4
+ const RateLimitExceededError_1 = require("./errors/RateLimitExceededError");
5
+ /**
6
+ * Result object from a rate limiting operation.
7
+ *
8
+ * Contains information about whether the request was accepted, how many tokens
9
+ * are remaining, and when the client should retry if rejected.
10
+ */
11
+ class RateLimit {
12
+ constructor(availableTokens, retryAfter, accepted, limit) {
13
+ this.availableTokens = availableTokens;
14
+ this.retryAfter = retryAfter;
15
+ this.accepted = accepted;
16
+ this.limit = limit;
17
+ }
18
+ /**
19
+ * Check if the request was accepted.
20
+ */
21
+ isAccepted() {
22
+ return this.accepted;
23
+ }
24
+ /**
25
+ * Ensure the request was accepted, throw an exception otherwise.
26
+ *
27
+ * @throws {RateLimitExceededError} If the request was not accepted
28
+ */
29
+ ensureAccepted() {
30
+ if (!this.accepted) {
31
+ throw new RateLimitExceededError_1.RateLimitExceededError('Rate limit exceeded', this);
32
+ }
33
+ return this;
34
+ }
35
+ /**
36
+ * Get the date/time when the client should retry.
37
+ */
38
+ getRetryAfter() {
39
+ return this.retryAfter;
40
+ }
41
+ /**
42
+ * Get the number of remaining tokens.
43
+ */
44
+ getRemainingTokens() {
45
+ return this.availableTokens;
46
+ }
47
+ /**
48
+ * Get the rate limit maximum.
49
+ */
50
+ getLimit() {
51
+ return this.limit;
52
+ }
53
+ /**
54
+ * Wait until the retry time (blocking operation).
55
+ *
56
+ * Note: This uses a blocking setTimeout. Consider using async/await patterns
57
+ * in production code instead.
58
+ */
59
+ async wait() {
60
+ const now = Date.now();
61
+ const waitMs = this.retryAfter.getTime() - now;
62
+ if (waitMs > 0) {
63
+ await new Promise(resolve => setTimeout(resolve, waitMs));
64
+ }
65
+ }
66
+ }
67
+ exports.RateLimit = RateLimit;
68
+ //# sourceMappingURL=RateLimit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RateLimit.js","sourceRoot":"","sources":["../src/RateLimit.ts"],"names":[],"mappings":";;;AAAA,4EAAyE;AAEzE;;;;;GAKG;AACH,MAAa,SAAS;IAMpB,YACE,eAAuB,EACvB,UAAgB,EAChB,QAAiB,EACjB,KAAa;QAEb,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,+CAAsB,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC;QAE/C,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACf,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;CACF;AAxED,8BAwEC"}
@@ -0,0 +1,83 @@
1
+ import type { RateLimiterFactoryInterface } from './RateLimiterFactoryInterface';
2
+ import type { LimiterInterface } from './LimiterInterface';
3
+ import type { StorageInterface } from './storage/StorageInterface';
4
+ import type { LockInterface } from './storage/LockInterface';
5
+ /**
6
+ * Configuration for token bucket policy.
7
+ */
8
+ export interface TokenBucketConfig {
9
+ policy: 'token_bucket';
10
+ id: string;
11
+ limit: number;
12
+ rate: {
13
+ interval: string;
14
+ amount: number;
15
+ };
16
+ }
17
+ /**
18
+ * Configuration for fixed window policy.
19
+ */
20
+ export interface FixedWindowConfig {
21
+ policy: 'fixed_window';
22
+ id: string;
23
+ limit: number;
24
+ interval: string;
25
+ }
26
+ /**
27
+ * Configuration for sliding window policy.
28
+ */
29
+ export interface SlidingWindowConfig {
30
+ policy: 'sliding_window';
31
+ id: string;
32
+ limit: number;
33
+ interval: string;
34
+ }
35
+ /**
36
+ * Configuration for no-limit policy.
37
+ */
38
+ export interface NoLimitConfig {
39
+ policy: 'no_limit';
40
+ id: string;
41
+ }
42
+ /**
43
+ * Union type of all possible rate limiter configurations.
44
+ */
45
+ export type RateLimiterConfig = TokenBucketConfig | FixedWindowConfig | SlidingWindowConfig | NoLimitConfig;
46
+ /**
47
+ * Factory for creating rate limiter instances based on configuration.
48
+ *
49
+ * Supports multiple rate limiting algorithms:
50
+ * - token_bucket: Token bucket with configurable burst and refill rate
51
+ * - fixed_window: Fixed time windows with hit counting
52
+ * - sliding_window: Sliding window with weighted previous window
53
+ * - no_limit: No rate limiting (always accepts)
54
+ */
55
+ export declare class RateLimiterFactory implements RateLimiterFactoryInterface {
56
+ private readonly config;
57
+ private readonly storage;
58
+ private readonly lock?;
59
+ constructor(config: RateLimiterConfig, storage: StorageInterface, lock?: LockInterface);
60
+ /**
61
+ * Create a rate limiter instance.
62
+ *
63
+ * @param key - Optional key to distinguish between different limiters (e.g., user ID)
64
+ */
65
+ create(key?: string | null): LimiterInterface;
66
+ /**
67
+ * Validate and normalize configuration.
68
+ */
69
+ private validateConfig;
70
+ /**
71
+ * Create a token bucket limiter.
72
+ */
73
+ private createTokenBucketLimiter;
74
+ /**
75
+ * Create a fixed window limiter.
76
+ */
77
+ private createFixedWindowLimiter;
78
+ /**
79
+ * Create a sliding window limiter.
80
+ */
81
+ private createSlidingWindowLimiter;
82
+ }
83
+ //# sourceMappingURL=RateLimiterFactory.d.ts.map