@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.
- package/LICENSE.md +24 -0
- package/README.md +204 -0
- package/dist/CompoundLimiter.d.ts +33 -0
- package/dist/CompoundLimiter.d.ts.map +1 -0
- package/dist/CompoundLimiter.js +62 -0
- package/dist/CompoundLimiter.js.map +1 -0
- package/dist/CompoundRateLimiterFactory.d.ts +19 -0
- package/dist/CompoundRateLimiterFactory.d.ts.map +1 -0
- package/dist/CompoundRateLimiterFactory.js +29 -0
- package/dist/CompoundRateLimiterFactory.js.map +1 -0
- package/dist/LimiterInterface.d.ts +32 -0
- package/dist/LimiterInterface.d.ts.map +1 -0
- package/dist/LimiterInterface.js +3 -0
- package/dist/LimiterInterface.js.map +1 -0
- package/dist/LimiterStateInterface.d.ts +16 -0
- package/dist/LimiterStateInterface.d.ts.map +1 -0
- package/dist/LimiterStateInterface.js +3 -0
- package/dist/LimiterStateInterface.js.map +1 -0
- package/dist/RateLimit.d.ts +43 -0
- package/dist/RateLimit.d.ts.map +1 -0
- package/dist/RateLimit.js +68 -0
- package/dist/RateLimit.js.map +1 -0
- package/dist/RateLimiterFactory.d.ts +83 -0
- package/dist/RateLimiterFactory.d.ts.map +1 -0
- package/dist/RateLimiterFactory.js +115 -0
- package/dist/RateLimiterFactory.js.map +1 -0
- package/dist/RateLimiterFactoryInterface.d.ts +17 -0
- package/dist/RateLimiterFactoryInterface.d.ts.map +1 -0
- package/dist/RateLimiterFactoryInterface.js +3 -0
- package/dist/RateLimiterFactoryInterface.js.map +1 -0
- package/dist/Reservation.d.ts +29 -0
- package/dist/Reservation.d.ts.map +1 -0
- package/dist/Reservation.js +44 -0
- package/dist/Reservation.js.map +1 -0
- package/dist/__tests__/CompoundLimiter.test.d.ts +2 -0
- package/dist/__tests__/CompoundLimiter.test.d.ts.map +1 -0
- package/dist/__tests__/CompoundLimiter.test.js +231 -0
- package/dist/__tests__/CompoundLimiter.test.js.map +1 -0
- package/dist/__tests__/CompoundRateLimiterFactory.test.d.ts +2 -0
- package/dist/__tests__/CompoundRateLimiterFactory.test.d.ts.map +1 -0
- package/dist/__tests__/CompoundRateLimiterFactory.test.js +213 -0
- package/dist/__tests__/CompoundRateLimiterFactory.test.js.map +1 -0
- package/dist/__tests__/RateLimit.test.d.ts +2 -0
- package/dist/__tests__/RateLimit.test.d.ts.map +1 -0
- package/dist/__tests__/RateLimit.test.js +108 -0
- package/dist/__tests__/RateLimit.test.js.map +1 -0
- package/dist/__tests__/RateLimiterFactory.test.d.ts +2 -0
- package/dist/__tests__/RateLimiterFactory.test.d.ts.map +1 -0
- package/dist/__tests__/RateLimiterFactory.test.js +323 -0
- package/dist/__tests__/RateLimiterFactory.test.js.map +1 -0
- package/dist/__tests__/Reservation.test.d.ts +2 -0
- package/dist/__tests__/Reservation.test.d.ts.map +1 -0
- package/dist/__tests__/Reservation.test.js +110 -0
- package/dist/__tests__/Reservation.test.js.map +1 -0
- package/dist/errors/InvalidIntervalError.d.ts +10 -0
- package/dist/errors/InvalidIntervalError.d.ts.map +1 -0
- package/dist/errors/InvalidIntervalError.js +18 -0
- package/dist/errors/InvalidIntervalError.js.map +1 -0
- package/dist/errors/MaxWaitDurationExceededError.d.ts +15 -0
- package/dist/errors/MaxWaitDurationExceededError.d.ts.map +1 -0
- package/dist/errors/MaxWaitDurationExceededError.js +24 -0
- package/dist/errors/MaxWaitDurationExceededError.js.map +1 -0
- package/dist/errors/RateLimitExceededError.d.ts +27 -0
- package/dist/errors/RateLimitExceededError.d.ts.map +1 -0
- package/dist/errors/RateLimitExceededError.js +42 -0
- package/dist/errors/RateLimitExceededError.js.map +1 -0
- package/dist/errors/ReserveNotSupportedError.d.ts +10 -0
- package/dist/errors/ReserveNotSupportedError.d.ts.map +1 -0
- package/dist/errors/ReserveNotSupportedError.js +18 -0
- package/dist/errors/ReserveNotSupportedError.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/FixedWindowLimiter.d.ts +36 -0
- package/dist/policy/FixedWindowLimiter.d.ts.map +1 -0
- package/dist/policy/FixedWindowLimiter.js +105 -0
- package/dist/policy/FixedWindowLimiter.js.map +1 -0
- package/dist/policy/NoLimiter.d.ts +23 -0
- package/dist/policy/NoLimiter.d.ts.map +1 -0
- package/dist/policy/NoLimiter.js +34 -0
- package/dist/policy/NoLimiter.js.map +1 -0
- package/dist/policy/Rate.d.ts +69 -0
- package/dist/policy/Rate.d.ts.map +1 -0
- package/dist/policy/Rate.js +121 -0
- package/dist/policy/Rate.js.map +1 -0
- package/dist/policy/SlidingWindow.d.ts +74 -0
- package/dist/policy/SlidingWindow.d.ts.map +1 -0
- package/dist/policy/SlidingWindow.js +130 -0
- package/dist/policy/SlidingWindow.js.map +1 -0
- package/dist/policy/SlidingWindowLimiter.d.ts +41 -0
- package/dist/policy/SlidingWindowLimiter.d.ts.map +1 -0
- package/dist/policy/SlidingWindowLimiter.js +127 -0
- package/dist/policy/SlidingWindowLimiter.js.map +1 -0
- package/dist/policy/TokenBucket.d.ts +63 -0
- package/dist/policy/TokenBucket.d.ts.map +1 -0
- package/dist/policy/TokenBucket.js +92 -0
- package/dist/policy/TokenBucket.js.map +1 -0
- package/dist/policy/TokenBucketLimiter.d.ts +38 -0
- package/dist/policy/TokenBucketLimiter.d.ts.map +1 -0
- package/dist/policy/TokenBucketLimiter.js +114 -0
- package/dist/policy/TokenBucketLimiter.js.map +1 -0
- package/dist/policy/Window.d.ts +58 -0
- package/dist/policy/Window.d.ts.map +1 -0
- package/dist/policy/Window.js +105 -0
- package/dist/policy/Window.js.map +1 -0
- package/dist/policy/__tests__/FixedWindowLimiter.test.d.ts +2 -0
- package/dist/policy/__tests__/FixedWindowLimiter.test.d.ts.map +1 -0
- package/dist/policy/__tests__/FixedWindowLimiter.test.js +180 -0
- package/dist/policy/__tests__/FixedWindowLimiter.test.js.map +1 -0
- package/dist/policy/__tests__/NoLimiter.test.d.ts +2 -0
- package/dist/policy/__tests__/NoLimiter.test.d.ts.map +1 -0
- package/dist/policy/__tests__/NoLimiter.test.js +40 -0
- package/dist/policy/__tests__/NoLimiter.test.js.map +1 -0
- package/dist/policy/__tests__/Rate.test.d.ts +2 -0
- package/dist/policy/__tests__/Rate.test.d.ts.map +1 -0
- package/dist/policy/__tests__/Rate.test.js +162 -0
- package/dist/policy/__tests__/Rate.test.js.map +1 -0
- package/dist/policy/__tests__/SlidingWindow.test.d.ts +2 -0
- package/dist/policy/__tests__/SlidingWindow.test.d.ts.map +1 -0
- package/dist/policy/__tests__/SlidingWindow.test.js +257 -0
- package/dist/policy/__tests__/SlidingWindow.test.js.map +1 -0
- package/dist/policy/__tests__/SlidingWindowLimiter.test.d.ts +2 -0
- package/dist/policy/__tests__/SlidingWindowLimiter.test.d.ts.map +1 -0
- package/dist/policy/__tests__/SlidingWindowLimiter.test.js +201 -0
- package/dist/policy/__tests__/SlidingWindowLimiter.test.js.map +1 -0
- package/dist/policy/__tests__/TokenBucket.test.d.ts +2 -0
- package/dist/policy/__tests__/TokenBucket.test.d.ts.map +1 -0
- package/dist/policy/__tests__/TokenBucket.test.js +171 -0
- package/dist/policy/__tests__/TokenBucket.test.js.map +1 -0
- package/dist/policy/__tests__/TokenBucketLimiter.test.d.ts +2 -0
- package/dist/policy/__tests__/TokenBucketLimiter.test.d.ts.map +1 -0
- package/dist/policy/__tests__/TokenBucketLimiter.test.js +175 -0
- package/dist/policy/__tests__/TokenBucketLimiter.test.js.map +1 -0
- package/dist/policy/__tests__/Window.test.d.ts +2 -0
- package/dist/policy/__tests__/Window.test.d.ts.map +1 -0
- package/dist/policy/__tests__/Window.test.js +193 -0
- package/dist/policy/__tests__/Window.test.js.map +1 -0
- package/dist/storage/InMemoryStorage.d.ts +34 -0
- package/dist/storage/InMemoryStorage.d.ts.map +1 -0
- package/dist/storage/InMemoryStorage.js +62 -0
- package/dist/storage/InMemoryStorage.js.map +1 -0
- package/dist/storage/LockInterface.d.ts +41 -0
- package/dist/storage/LockInterface.d.ts.map +1 -0
- package/dist/storage/LockInterface.js +19 -0
- package/dist/storage/LockInterface.js.map +1 -0
- package/dist/storage/StorageInterface.d.ts +29 -0
- package/dist/storage/StorageInterface.d.ts.map +1 -0
- package/dist/storage/StorageInterface.js +3 -0
- package/dist/storage/StorageInterface.js.map +1 -0
- package/dist/storage/__tests__/InMemoryStorage.test.d.ts +2 -0
- package/dist/storage/__tests__/InMemoryStorage.test.d.ts.map +1 -0
- package/dist/storage/__tests__/InMemoryStorage.test.js +154 -0
- package/dist/storage/__tests__/InMemoryStorage.test.js.map +1 -0
- package/dist/util/TimeUtil.d.ts +35 -0
- package/dist/util/TimeUtil.d.ts.map +1 -0
- package/dist/util/TimeUtil.js +87 -0
- package/dist/util/TimeUtil.js.map +1 -0
- package/dist/util/__tests__/TimeUtil.test.d.ts +2 -0
- package/dist/util/__tests__/TimeUtil.test.d.ts.map +1 -0
- package/dist/util/__tests__/TimeUtil.test.js +132 -0
- package/dist/util/__tests__/TimeUtil.test.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const RateLimiterFactory_1 = require("../RateLimiterFactory");
|
|
4
|
+
const InMemoryStorage_1 = require("../storage/InMemoryStorage");
|
|
5
|
+
const TokenBucketLimiter_1 = require("../policy/TokenBucketLimiter");
|
|
6
|
+
const FixedWindowLimiter_1 = require("../policy/FixedWindowLimiter");
|
|
7
|
+
const SlidingWindowLimiter_1 = require("../policy/SlidingWindowLimiter");
|
|
8
|
+
const NoLimiter_1 = require("../policy/NoLimiter");
|
|
9
|
+
describe('RateLimiterFactory', () => {
|
|
10
|
+
let storage;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
storage = new InMemoryStorage_1.InMemoryStorage();
|
|
13
|
+
});
|
|
14
|
+
describe('constructor validation', () => {
|
|
15
|
+
it('should throw error when id is missing', () => {
|
|
16
|
+
const config = {
|
|
17
|
+
policy: 'token_bucket',
|
|
18
|
+
limit: 10,
|
|
19
|
+
rate: { interval: '1 second', amount: 1 },
|
|
20
|
+
};
|
|
21
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('Configuration must include an "id" field');
|
|
22
|
+
});
|
|
23
|
+
it('should throw error when policy is missing', () => {
|
|
24
|
+
const config = {
|
|
25
|
+
id: 'test',
|
|
26
|
+
limit: 10,
|
|
27
|
+
};
|
|
28
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('Configuration must include a "policy" field');
|
|
29
|
+
});
|
|
30
|
+
it('should throw error for unknown policy', () => {
|
|
31
|
+
const config = {
|
|
32
|
+
id: 'test',
|
|
33
|
+
policy: 'unknown_policy',
|
|
34
|
+
limit: 10,
|
|
35
|
+
};
|
|
36
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('Unknown policy');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('token bucket policy', () => {
|
|
40
|
+
it('should create TokenBucketLimiter', () => {
|
|
41
|
+
const config = {
|
|
42
|
+
policy: 'token_bucket',
|
|
43
|
+
id: 'test',
|
|
44
|
+
limit: 10,
|
|
45
|
+
rate: { interval: '1 second', amount: 1 },
|
|
46
|
+
};
|
|
47
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
48
|
+
const limiter = factory.create();
|
|
49
|
+
expect(limiter).toBeInstanceOf(TokenBucketLimiter_1.TokenBucketLimiter);
|
|
50
|
+
});
|
|
51
|
+
it('should validate required fields', () => {
|
|
52
|
+
const config = {
|
|
53
|
+
policy: 'token_bucket',
|
|
54
|
+
id: 'test',
|
|
55
|
+
};
|
|
56
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('Token bucket requires a positive "limit"');
|
|
57
|
+
});
|
|
58
|
+
it('should validate positive limit', () => {
|
|
59
|
+
const config = {
|
|
60
|
+
policy: 'token_bucket',
|
|
61
|
+
id: 'test',
|
|
62
|
+
limit: 0,
|
|
63
|
+
rate: { interval: '1 second', amount: 1 },
|
|
64
|
+
};
|
|
65
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('Token bucket requires a positive "limit"');
|
|
66
|
+
});
|
|
67
|
+
it('should validate rate configuration', () => {
|
|
68
|
+
const config = {
|
|
69
|
+
policy: 'token_bucket',
|
|
70
|
+
id: 'test',
|
|
71
|
+
limit: 10,
|
|
72
|
+
};
|
|
73
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('Token bucket requires a "rate" object');
|
|
74
|
+
});
|
|
75
|
+
it('should parse interval string correctly', () => {
|
|
76
|
+
const config = {
|
|
77
|
+
policy: 'token_bucket',
|
|
78
|
+
id: 'test',
|
|
79
|
+
limit: 10,
|
|
80
|
+
rate: { interval: '1 minute', amount: 100 },
|
|
81
|
+
};
|
|
82
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
83
|
+
const limiter = factory.create();
|
|
84
|
+
expect(limiter).toBeInstanceOf(TokenBucketLimiter_1.TokenBucketLimiter);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe('fixed window policy', () => {
|
|
88
|
+
it('should create FixedWindowLimiter', () => {
|
|
89
|
+
const config = {
|
|
90
|
+
policy: 'fixed_window',
|
|
91
|
+
id: 'test',
|
|
92
|
+
limit: 10,
|
|
93
|
+
interval: '60 seconds',
|
|
94
|
+
};
|
|
95
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
96
|
+
const limiter = factory.create();
|
|
97
|
+
expect(limiter).toBeInstanceOf(FixedWindowLimiter_1.FixedWindowLimiter);
|
|
98
|
+
});
|
|
99
|
+
it('should validate required fields', () => {
|
|
100
|
+
const config = {
|
|
101
|
+
policy: 'fixed_window',
|
|
102
|
+
id: 'test',
|
|
103
|
+
};
|
|
104
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('fixed_window requires a positive "limit"');
|
|
105
|
+
});
|
|
106
|
+
it('should validate interval field', () => {
|
|
107
|
+
const config = {
|
|
108
|
+
policy: 'fixed_window',
|
|
109
|
+
id: 'test',
|
|
110
|
+
limit: 10,
|
|
111
|
+
};
|
|
112
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('fixed_window requires an "interval"');
|
|
113
|
+
});
|
|
114
|
+
it('should parse interval string correctly', () => {
|
|
115
|
+
const config = {
|
|
116
|
+
policy: 'fixed_window',
|
|
117
|
+
id: 'test',
|
|
118
|
+
limit: 100,
|
|
119
|
+
interval: '1 hour',
|
|
120
|
+
};
|
|
121
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
122
|
+
const limiter = factory.create();
|
|
123
|
+
expect(limiter).toBeInstanceOf(FixedWindowLimiter_1.FixedWindowLimiter);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe('sliding window policy', () => {
|
|
127
|
+
it('should create SlidingWindowLimiter', () => {
|
|
128
|
+
const config = {
|
|
129
|
+
policy: 'sliding_window',
|
|
130
|
+
id: 'test',
|
|
131
|
+
limit: 10,
|
|
132
|
+
interval: '60 seconds',
|
|
133
|
+
};
|
|
134
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
135
|
+
const limiter = factory.create();
|
|
136
|
+
expect(limiter).toBeInstanceOf(SlidingWindowLimiter_1.SlidingWindowLimiter);
|
|
137
|
+
});
|
|
138
|
+
it('should validate required fields', () => {
|
|
139
|
+
const config = {
|
|
140
|
+
policy: 'sliding_window',
|
|
141
|
+
id: 'test',
|
|
142
|
+
};
|
|
143
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('sliding_window requires a positive "limit"');
|
|
144
|
+
});
|
|
145
|
+
it('should validate interval field', () => {
|
|
146
|
+
const config = {
|
|
147
|
+
policy: 'sliding_window',
|
|
148
|
+
id: 'test',
|
|
149
|
+
limit: 10,
|
|
150
|
+
};
|
|
151
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).toThrow('sliding_window requires an "interval"');
|
|
152
|
+
});
|
|
153
|
+
it('should parse interval string correctly', () => {
|
|
154
|
+
const config = {
|
|
155
|
+
policy: 'sliding_window',
|
|
156
|
+
id: 'test',
|
|
157
|
+
limit: 1000,
|
|
158
|
+
interval: '1 day',
|
|
159
|
+
};
|
|
160
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
161
|
+
const limiter = factory.create();
|
|
162
|
+
expect(limiter).toBeInstanceOf(SlidingWindowLimiter_1.SlidingWindowLimiter);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe('no limit policy', () => {
|
|
166
|
+
it('should create NoLimiter', () => {
|
|
167
|
+
const config = {
|
|
168
|
+
policy: 'no_limit',
|
|
169
|
+
id: 'test',
|
|
170
|
+
};
|
|
171
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
172
|
+
const limiter = factory.create();
|
|
173
|
+
expect(limiter).toBeInstanceOf(NoLimiter_1.NoLimiter);
|
|
174
|
+
});
|
|
175
|
+
it('should not require additional fields', () => {
|
|
176
|
+
const config = {
|
|
177
|
+
policy: 'no_limit',
|
|
178
|
+
id: 'test',
|
|
179
|
+
};
|
|
180
|
+
expect(() => new RateLimiterFactory_1.RateLimiterFactory(config, storage)).not.toThrow();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('create with key', () => {
|
|
184
|
+
it('should append key to limiter id', async () => {
|
|
185
|
+
const config = {
|
|
186
|
+
policy: 'fixed_window',
|
|
187
|
+
id: 'api',
|
|
188
|
+
limit: 10,
|
|
189
|
+
interval: '60 seconds',
|
|
190
|
+
};
|
|
191
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
192
|
+
const limiter1 = factory.create('user1');
|
|
193
|
+
const limiter2 = factory.create('user2');
|
|
194
|
+
// Consume from limiter1 shouldn't affect limiter2
|
|
195
|
+
await limiter1.consume(10);
|
|
196
|
+
const result1 = await limiter1.consume(1);
|
|
197
|
+
const result2 = await limiter2.consume(1);
|
|
198
|
+
expect(result1.isAccepted()).toBe(false);
|
|
199
|
+
expect(result2.isAccepted()).toBe(true);
|
|
200
|
+
});
|
|
201
|
+
it('should use base id when key is null', async () => {
|
|
202
|
+
const config = {
|
|
203
|
+
policy: 'fixed_window',
|
|
204
|
+
id: 'test',
|
|
205
|
+
limit: 10,
|
|
206
|
+
interval: '60 seconds',
|
|
207
|
+
};
|
|
208
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
209
|
+
const limiter1 = factory.create(null);
|
|
210
|
+
const limiter2 = factory.create();
|
|
211
|
+
// Should share the same state
|
|
212
|
+
await limiter1.consume(5);
|
|
213
|
+
const result = await limiter2.consume(1);
|
|
214
|
+
expect(result.getRemainingTokens()).toBe(4);
|
|
215
|
+
});
|
|
216
|
+
it('should use base id when key is undefined', async () => {
|
|
217
|
+
const config = {
|
|
218
|
+
policy: 'fixed_window',
|
|
219
|
+
id: 'test',
|
|
220
|
+
limit: 10,
|
|
221
|
+
interval: '60 seconds',
|
|
222
|
+
};
|
|
223
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
224
|
+
const limiter1 = factory.create(undefined);
|
|
225
|
+
const limiter2 = factory.create();
|
|
226
|
+
// Should share the same state
|
|
227
|
+
await limiter1.consume(7);
|
|
228
|
+
const result = await limiter2.consume(1);
|
|
229
|
+
expect(result.getRemainingTokens()).toBe(2);
|
|
230
|
+
});
|
|
231
|
+
it('should handle empty string key', async () => {
|
|
232
|
+
const config = {
|
|
233
|
+
policy: 'fixed_window',
|
|
234
|
+
id: 'test',
|
|
235
|
+
limit: 10,
|
|
236
|
+
interval: '60 seconds',
|
|
237
|
+
};
|
|
238
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
239
|
+
const limiter = factory.create('');
|
|
240
|
+
const result = await limiter.consume(5);
|
|
241
|
+
expect(result.isAccepted()).toBe(true);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
describe('multiple limiters from same factory', () => {
|
|
245
|
+
it('should create independent limiters with different keys', async () => {
|
|
246
|
+
const config = {
|
|
247
|
+
policy: 'token_bucket',
|
|
248
|
+
id: 'api',
|
|
249
|
+
limit: 5,
|
|
250
|
+
rate: { interval: '1 second', amount: 1 },
|
|
251
|
+
};
|
|
252
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
253
|
+
const limiter1 = factory.create('user1');
|
|
254
|
+
const limiter2 = factory.create('user2');
|
|
255
|
+
const limiter3 = factory.create('user3');
|
|
256
|
+
await limiter1.consume(5);
|
|
257
|
+
await limiter2.consume(3);
|
|
258
|
+
const r1 = await limiter1.consume(1);
|
|
259
|
+
const r2 = await limiter2.consume(1);
|
|
260
|
+
const r3 = await limiter3.consume(1);
|
|
261
|
+
expect(r1.isAccepted()).toBe(false);
|
|
262
|
+
expect(r2.isAccepted()).toBe(true);
|
|
263
|
+
expect(r3.isAccepted()).toBe(true);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
describe('complex interval strings', () => {
|
|
267
|
+
it('should handle various interval formats', () => {
|
|
268
|
+
const configs = [
|
|
269
|
+
{ interval: '1 second' },
|
|
270
|
+
{ interval: '30 seconds' },
|
|
271
|
+
{ interval: '1 minute' },
|
|
272
|
+
{ interval: '5 minutes' },
|
|
273
|
+
{ interval: '1 hour' },
|
|
274
|
+
{ interval: '24 hours' },
|
|
275
|
+
{ interval: '1 day' },
|
|
276
|
+
{ interval: '1 week' },
|
|
277
|
+
];
|
|
278
|
+
configs.forEach(({ interval }) => {
|
|
279
|
+
const config = {
|
|
280
|
+
policy: 'fixed_window',
|
|
281
|
+
id: 'test',
|
|
282
|
+
limit: 10,
|
|
283
|
+
interval,
|
|
284
|
+
};
|
|
285
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
286
|
+
const limiter = factory.create();
|
|
287
|
+
expect(limiter).toBeInstanceOf(FixedWindowLimiter_1.FixedWindowLimiter);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
describe('storage and lock', () => {
|
|
292
|
+
it('should use provided storage', async () => {
|
|
293
|
+
const config = {
|
|
294
|
+
policy: 'fixed_window',
|
|
295
|
+
id: 'test',
|
|
296
|
+
limit: 10,
|
|
297
|
+
interval: '60 seconds',
|
|
298
|
+
};
|
|
299
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage);
|
|
300
|
+
const limiter = factory.create();
|
|
301
|
+
await limiter.consume(5);
|
|
302
|
+
// Verify storage was used
|
|
303
|
+
expect(storage.size()).toBeGreaterThan(0);
|
|
304
|
+
});
|
|
305
|
+
it('should pass lock to limiters', () => {
|
|
306
|
+
const mockLock = {
|
|
307
|
+
acquire: jest.fn(async () => true),
|
|
308
|
+
release: jest.fn(async () => { }),
|
|
309
|
+
withLock: jest.fn(async (id, fn) => fn()),
|
|
310
|
+
};
|
|
311
|
+
const config = {
|
|
312
|
+
policy: 'token_bucket',
|
|
313
|
+
id: 'test',
|
|
314
|
+
limit: 10,
|
|
315
|
+
rate: { interval: '1 second', amount: 1 },
|
|
316
|
+
};
|
|
317
|
+
const factory = new RateLimiterFactory_1.RateLimiterFactory(config, storage, mockLock);
|
|
318
|
+
const limiter = factory.create();
|
|
319
|
+
expect(limiter).toBeInstanceOf(TokenBucketLimiter_1.TokenBucketLimiter);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
//# sourceMappingURL=RateLimiterFactory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterFactory.test.js","sourceRoot":"","sources":["../../src/__tests__/RateLimiterFactory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Reservation.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/Reservation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const Reservation_1 = require("../Reservation");
|
|
4
|
+
const RateLimit_1 = require("../RateLimit");
|
|
5
|
+
describe('Reservation', () => {
|
|
6
|
+
let rateLimit;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
const retryAfter = new Date(Date.now() + 5000);
|
|
9
|
+
rateLimit = new RateLimit_1.RateLimit(5, retryAfter, true, 10);
|
|
10
|
+
});
|
|
11
|
+
describe('constructor', () => {
|
|
12
|
+
it('should create a reservation with correct values', () => {
|
|
13
|
+
const timeToAct = Date.now() + 1000;
|
|
14
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
15
|
+
expect(reservation.getTimeToAct()).toBe(timeToAct);
|
|
16
|
+
expect(reservation.getRateLimit()).toBe(rateLimit);
|
|
17
|
+
});
|
|
18
|
+
it('should handle past time to act', () => {
|
|
19
|
+
const timeToAct = Date.now() - 5000;
|
|
20
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
21
|
+
expect(reservation.getTimeToAct()).toBe(timeToAct);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('getTimeToAct', () => {
|
|
25
|
+
it('should return the time to act in milliseconds', () => {
|
|
26
|
+
const timeToAct = Date.now() + 2000;
|
|
27
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
28
|
+
expect(reservation.getTimeToAct()).toBe(timeToAct);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('getWaitDuration', () => {
|
|
32
|
+
it('should return positive duration when time to act is in future', () => {
|
|
33
|
+
const timeToAct = Date.now() + 5000;
|
|
34
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
35
|
+
const waitDuration = reservation.getWaitDuration();
|
|
36
|
+
expect(waitDuration).toBeGreaterThan(4000);
|
|
37
|
+
expect(waitDuration).toBeLessThan(6000);
|
|
38
|
+
});
|
|
39
|
+
it('should return 0 when time to act is in past', () => {
|
|
40
|
+
const timeToAct = Date.now() - 1000;
|
|
41
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
42
|
+
expect(reservation.getWaitDuration()).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
it('should return ~0 when time to act is now', () => {
|
|
45
|
+
const timeToAct = Date.now();
|
|
46
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
47
|
+
const waitDuration = reservation.getWaitDuration();
|
|
48
|
+
expect(waitDuration).toBeGreaterThanOrEqual(0);
|
|
49
|
+
expect(waitDuration).toBeLessThan(100);
|
|
50
|
+
});
|
|
51
|
+
it('should decrease over time', async () => {
|
|
52
|
+
const timeToAct = Date.now() + 1000;
|
|
53
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
54
|
+
const duration1 = reservation.getWaitDuration();
|
|
55
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
56
|
+
const duration2 = reservation.getWaitDuration();
|
|
57
|
+
expect(duration2).toBeLessThan(duration1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('getRateLimit', () => {
|
|
61
|
+
it('should return the associated RateLimit object', () => {
|
|
62
|
+
const reservation = new Reservation_1.Reservation(Date.now(), rateLimit);
|
|
63
|
+
expect(reservation.getRateLimit()).toBe(rateLimit);
|
|
64
|
+
});
|
|
65
|
+
it('should allow accessing RateLimit properties', () => {
|
|
66
|
+
const reservation = new Reservation_1.Reservation(Date.now(), rateLimit);
|
|
67
|
+
expect(reservation.getRateLimit().getRemainingTokens()).toBe(5);
|
|
68
|
+
expect(reservation.getRateLimit().getLimit()).toBe(10);
|
|
69
|
+
expect(reservation.getRateLimit().isAccepted()).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('wait', () => {
|
|
73
|
+
it('should resolve immediately when time to act is in past', async () => {
|
|
74
|
+
const timeToAct = Date.now() - 1000;
|
|
75
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
76
|
+
const start = Date.now();
|
|
77
|
+
await reservation.wait();
|
|
78
|
+
const elapsed = Date.now() - start;
|
|
79
|
+
expect(elapsed).toBeLessThan(100);
|
|
80
|
+
});
|
|
81
|
+
it('should wait until time to act', async () => {
|
|
82
|
+
const timeToAct = Date.now() + 100;
|
|
83
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
84
|
+
const start = Date.now();
|
|
85
|
+
await reservation.wait();
|
|
86
|
+
const elapsed = Date.now() - start;
|
|
87
|
+
expect(elapsed).toBeGreaterThanOrEqual(90);
|
|
88
|
+
expect(elapsed).toBeLessThan(200);
|
|
89
|
+
});
|
|
90
|
+
it('should work when time to act is now', async () => {
|
|
91
|
+
const timeToAct = Date.now();
|
|
92
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
93
|
+
const start = Date.now();
|
|
94
|
+
await reservation.wait();
|
|
95
|
+
const elapsed = Date.now() - start;
|
|
96
|
+
expect(elapsed).toBeLessThan(100);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('usage patterns', () => {
|
|
100
|
+
it('should support check-then-wait pattern', async () => {
|
|
101
|
+
const timeToAct = Date.now() + 50;
|
|
102
|
+
const reservation = new Reservation_1.Reservation(timeToAct, rateLimit);
|
|
103
|
+
if (reservation.getWaitDuration() > 0) {
|
|
104
|
+
await reservation.wait();
|
|
105
|
+
}
|
|
106
|
+
expect(Date.now()).toBeGreaterThanOrEqual(timeToAct - 10);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=Reservation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Reservation.test.js","sourceRoot":"","sources":["../../src/__tests__/Reservation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when an invalid interval is provided to a rate limiter.
|
|
3
|
+
*
|
|
4
|
+
* An interval is considered invalid if it's less than 1 second or otherwise
|
|
5
|
+
* doesn't meet the requirements of the rate limiting policy.
|
|
6
|
+
*/
|
|
7
|
+
export declare class InvalidIntervalError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=InvalidIntervalError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvalidIntervalError.d.ts","sourceRoot":"","sources":["../../src/errors/InvalidIntervalError.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAK5B"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidIntervalError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when an invalid interval is provided to a rate limiter.
|
|
6
|
+
*
|
|
7
|
+
* An interval is considered invalid if it's less than 1 second or otherwise
|
|
8
|
+
* doesn't meet the requirements of the rate limiting policy.
|
|
9
|
+
*/
|
|
10
|
+
class InvalidIntervalError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'InvalidIntervalError';
|
|
14
|
+
Object.setPrototypeOf(this, InvalidIntervalError.prototype);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.InvalidIntervalError = InvalidIntervalError;
|
|
18
|
+
//# sourceMappingURL=InvalidIntervalError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvalidIntervalError.js","sourceRoot":"","sources":["../../src/errors/InvalidIntervalError.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,MAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC9D,CAAC;CACF;AAND,oDAMC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RateLimit } from '../RateLimit';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a reservation would require waiting longer than the maximum allowed time.
|
|
4
|
+
*
|
|
5
|
+
* This exception is thrown by reserve() when the wait duration exceeds the maxTime parameter.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MaxWaitDurationExceededError extends Error {
|
|
8
|
+
private readonly rateLimit;
|
|
9
|
+
constructor(message: string, rateLimit: RateLimit);
|
|
10
|
+
/**
|
|
11
|
+
* Get the associated RateLimit object.
|
|
12
|
+
*/
|
|
13
|
+
getRateLimit(): RateLimit;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=MaxWaitDurationExceededError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MaxWaitDurationExceededError.d.ts","sourceRoot":"","sources":["../../src/errors/MaxWaitDurationExceededError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAOjD;;OAEG;IACH,YAAY,IAAI,SAAS;CAG1B"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MaxWaitDurationExceededError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when a reservation would require waiting longer than the maximum allowed time.
|
|
6
|
+
*
|
|
7
|
+
* This exception is thrown by reserve() when the wait duration exceeds the maxTime parameter.
|
|
8
|
+
*/
|
|
9
|
+
class MaxWaitDurationExceededError extends Error {
|
|
10
|
+
constructor(message, rateLimit) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'MaxWaitDurationExceededError';
|
|
13
|
+
this.rateLimit = rateLimit;
|
|
14
|
+
Object.setPrototypeOf(this, MaxWaitDurationExceededError.prototype);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the associated RateLimit object.
|
|
18
|
+
*/
|
|
19
|
+
getRateLimit() {
|
|
20
|
+
return this.rateLimit;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.MaxWaitDurationExceededError = MaxWaitDurationExceededError;
|
|
24
|
+
//# sourceMappingURL=MaxWaitDurationExceededError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MaxWaitDurationExceededError.js","sourceRoot":"","sources":["../../src/errors/MaxWaitDurationExceededError.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACH,MAAa,4BAA6B,SAAQ,KAAK;IAGrD,YAAY,OAAe,EAAE,SAAoB;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,4BAA4B,CAAC,SAAS,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AAhBD,oEAgBC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RateLimit } from '../RateLimit';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a rate limit is exceeded and the request cannot be fulfilled.
|
|
4
|
+
*
|
|
5
|
+
* Contains the RateLimit object with details about when to retry and remaining tokens.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RateLimitExceededError extends Error {
|
|
8
|
+
private readonly rateLimit;
|
|
9
|
+
constructor(message: string, rateLimit: RateLimit);
|
|
10
|
+
/**
|
|
11
|
+
* Get the associated RateLimit object.
|
|
12
|
+
*/
|
|
13
|
+
getRateLimit(): RateLimit;
|
|
14
|
+
/**
|
|
15
|
+
* Convenience method to get the retry time.
|
|
16
|
+
*/
|
|
17
|
+
getRetryAfter(): Date;
|
|
18
|
+
/**
|
|
19
|
+
* Convenience method to get remaining tokens.
|
|
20
|
+
*/
|
|
21
|
+
getRemainingTokens(): number;
|
|
22
|
+
/**
|
|
23
|
+
* Convenience method to get the rate limit.
|
|
24
|
+
*/
|
|
25
|
+
getLimit(): number;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=RateLimitExceededError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitExceededError.d.ts","sourceRoot":"","sources":["../../src/errors/RateLimitExceededError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAOjD;;OAEG;IACH,YAAY,IAAI,SAAS;IAIzB;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,QAAQ,IAAI,MAAM;CAGnB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RateLimitExceededError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when a rate limit is exceeded and the request cannot be fulfilled.
|
|
6
|
+
*
|
|
7
|
+
* Contains the RateLimit object with details about when to retry and remaining tokens.
|
|
8
|
+
*/
|
|
9
|
+
class RateLimitExceededError extends Error {
|
|
10
|
+
constructor(message, rateLimit) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'RateLimitExceededError';
|
|
13
|
+
this.rateLimit = rateLimit;
|
|
14
|
+
Object.setPrototypeOf(this, RateLimitExceededError.prototype);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the associated RateLimit object.
|
|
18
|
+
*/
|
|
19
|
+
getRateLimit() {
|
|
20
|
+
return this.rateLimit;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convenience method to get the retry time.
|
|
24
|
+
*/
|
|
25
|
+
getRetryAfter() {
|
|
26
|
+
return this.rateLimit.getRetryAfter();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Convenience method to get remaining tokens.
|
|
30
|
+
*/
|
|
31
|
+
getRemainingTokens() {
|
|
32
|
+
return this.rateLimit.getRemainingTokens();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Convenience method to get the rate limit.
|
|
36
|
+
*/
|
|
37
|
+
getLimit() {
|
|
38
|
+
return this.rateLimit.getLimit();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.RateLimitExceededError = RateLimitExceededError;
|
|
42
|
+
//# sourceMappingURL=RateLimitExceededError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitExceededError.js","sourceRoot":"","sources":["../../src/errors/RateLimitExceededError.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACH,MAAa,sBAAuB,SAAQ,KAAK;IAG/C,YAAY,OAAe,EAAE,SAAoB;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;IACnC,CAAC;CACF;AArCD,wDAqCC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when reserve() is called on a limiter that doesn't support reservations.
|
|
3
|
+
*
|
|
4
|
+
* Some limiters (like CompoundLimiter) don't support the reserve pattern and will
|
|
5
|
+
* throw this exception if reserve() is called.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ReserveNotSupportedError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=ReserveNotSupportedError.d.ts.map
|