@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 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterFactory.d.ts","sourceRoot":"","sources":["../src/RateLimiterFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAS7D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,gBAAgB,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,aAAa,CAAC;AAElB;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,YAAW,2BAA2B;IACpE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAgB;gBAGpC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,gBAAgB,EACzB,IAAI,CAAC,EAAE,aAAa;IAOtB;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB;IAuB7C;;OAEG;IACH,OAAO,CAAC,cAAc;IA2CtB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAUhC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAqBhC;;OAEG;IACH,OAAO,CAAC,0BAA0B;CAoBnC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RateLimiterFactory = void 0;
|
|
4
|
+
const TokenBucketLimiter_1 = require("./policy/TokenBucketLimiter");
|
|
5
|
+
const FixedWindowLimiter_1 = require("./policy/FixedWindowLimiter");
|
|
6
|
+
const SlidingWindowLimiter_1 = require("./policy/SlidingWindowLimiter");
|
|
7
|
+
const NoLimiter_1 = require("./policy/NoLimiter");
|
|
8
|
+
const Rate_1 = require("./policy/Rate");
|
|
9
|
+
const TimeUtil_1 = require("./util/TimeUtil");
|
|
10
|
+
const InvalidIntervalError_1 = require("./errors/InvalidIntervalError");
|
|
11
|
+
/**
|
|
12
|
+
* Factory for creating rate limiter instances based on configuration.
|
|
13
|
+
*
|
|
14
|
+
* Supports multiple rate limiting algorithms:
|
|
15
|
+
* - token_bucket: Token bucket with configurable burst and refill rate
|
|
16
|
+
* - fixed_window: Fixed time windows with hit counting
|
|
17
|
+
* - sliding_window: Sliding window with weighted previous window
|
|
18
|
+
* - no_limit: No rate limiting (always accepts)
|
|
19
|
+
*/
|
|
20
|
+
class RateLimiterFactory {
|
|
21
|
+
constructor(config, storage, lock) {
|
|
22
|
+
this.config = this.validateConfig(config);
|
|
23
|
+
this.storage = storage;
|
|
24
|
+
this.lock = lock;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a rate limiter instance.
|
|
28
|
+
*
|
|
29
|
+
* @param key - Optional key to distinguish between different limiters (e.g., user ID)
|
|
30
|
+
*/
|
|
31
|
+
create(key) {
|
|
32
|
+
const id = key ? `${this.config.id}:${key}` : this.config.id;
|
|
33
|
+
switch (this.config.policy) {
|
|
34
|
+
case 'token_bucket':
|
|
35
|
+
return this.createTokenBucketLimiter(id, this.config);
|
|
36
|
+
case 'fixed_window':
|
|
37
|
+
return this.createFixedWindowLimiter(id, this.config);
|
|
38
|
+
case 'sliding_window':
|
|
39
|
+
return this.createSlidingWindowLimiter(id, this.config);
|
|
40
|
+
case 'no_limit':
|
|
41
|
+
return new NoLimiter_1.NoLimiter();
|
|
42
|
+
default:
|
|
43
|
+
// TypeScript exhaustiveness check
|
|
44
|
+
const _exhaustive = this.config;
|
|
45
|
+
throw new Error(`Unknown policy: ${_exhaustive.policy}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validate and normalize configuration.
|
|
50
|
+
*/
|
|
51
|
+
validateConfig(config) {
|
|
52
|
+
if (!config.id) {
|
|
53
|
+
throw new Error('Configuration must include an "id" field');
|
|
54
|
+
}
|
|
55
|
+
if (!config.policy) {
|
|
56
|
+
throw new Error('Configuration must include a "policy" field');
|
|
57
|
+
}
|
|
58
|
+
// Validate policy-specific requirements
|
|
59
|
+
switch (config.policy) {
|
|
60
|
+
case 'token_bucket':
|
|
61
|
+
if (!config.limit || config.limit < 1) {
|
|
62
|
+
throw new Error('Token bucket requires a positive "limit" (burst size)');
|
|
63
|
+
}
|
|
64
|
+
if (!config.rate || !config.rate.interval || !config.rate.amount) {
|
|
65
|
+
throw new Error('Token bucket requires a "rate" object with "interval" and "amount"');
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case 'fixed_window':
|
|
69
|
+
case 'sliding_window':
|
|
70
|
+
if (!config.limit || config.limit < 1) {
|
|
71
|
+
throw new Error(`${config.policy} requires a positive "limit"`);
|
|
72
|
+
}
|
|
73
|
+
if (!config.interval) {
|
|
74
|
+
throw new Error(`${config.policy} requires an "interval"`);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
case 'no_limit':
|
|
78
|
+
// No additional validation needed
|
|
79
|
+
break;
|
|
80
|
+
default:
|
|
81
|
+
throw new Error(`Unknown policy: ${config.policy}`);
|
|
82
|
+
}
|
|
83
|
+
return config;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create a token bucket limiter.
|
|
87
|
+
*/
|
|
88
|
+
createTokenBucketLimiter(id, config) {
|
|
89
|
+
const intervalInSeconds = TimeUtil_1.TimeUtil.durationToSeconds(config.rate.interval);
|
|
90
|
+
const rate = new Rate_1.Rate(intervalInSeconds, config.rate.amount);
|
|
91
|
+
return new TokenBucketLimiter_1.TokenBucketLimiter(id, config.limit, rate, this.storage, this.lock);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Create a fixed window limiter.
|
|
95
|
+
*/
|
|
96
|
+
createFixedWindowLimiter(id, config) {
|
|
97
|
+
const intervalInSeconds = TimeUtil_1.TimeUtil.durationToSeconds(config.interval);
|
|
98
|
+
if (intervalInSeconds < 1) {
|
|
99
|
+
throw new InvalidIntervalError_1.InvalidIntervalError(`Interval must be at least 1 second, got ${intervalInSeconds}`);
|
|
100
|
+
}
|
|
101
|
+
return new FixedWindowLimiter_1.FixedWindowLimiter(id, config.limit, intervalInSeconds, this.storage, this.lock);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Create a sliding window limiter.
|
|
105
|
+
*/
|
|
106
|
+
createSlidingWindowLimiter(id, config) {
|
|
107
|
+
const intervalInSeconds = TimeUtil_1.TimeUtil.durationToSeconds(config.interval);
|
|
108
|
+
if (intervalInSeconds < 1) {
|
|
109
|
+
throw new InvalidIntervalError_1.InvalidIntervalError(`Interval must be at least 1 second, got ${intervalInSeconds}`);
|
|
110
|
+
}
|
|
111
|
+
return new SlidingWindowLimiter_1.SlidingWindowLimiter(id, config.limit, intervalInSeconds, this.storage, this.lock);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.RateLimiterFactory = RateLimiterFactory;
|
|
115
|
+
//# sourceMappingURL=RateLimiterFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterFactory.js","sourceRoot":"","sources":["../src/RateLimiterFactory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LimiterInterface } from './LimiterInterface';
|
|
2
|
+
/**
|
|
3
|
+
* Factory interface for creating rate limiter instances.
|
|
4
|
+
*
|
|
5
|
+
* Factories are responsible for creating configured limiters with optional keys
|
|
6
|
+
* for multi-tenant or per-resource rate limiting.
|
|
7
|
+
*/
|
|
8
|
+
export interface RateLimiterFactoryInterface {
|
|
9
|
+
/**
|
|
10
|
+
* Create a rate limiter instance.
|
|
11
|
+
*
|
|
12
|
+
* @param key - Optional key to distinguish between different limiters (e.g., user ID, API key)
|
|
13
|
+
* @returns A configured LimiterInterface instance
|
|
14
|
+
*/
|
|
15
|
+
create(key?: string | null): LimiterInterface;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=RateLimiterFactoryInterface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterFactoryInterface.d.ts","sourceRoot":"","sources":["../src/RateLimiterFactoryInterface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,gBAAgB,CAAC;CAC/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterFactoryInterface.js","sourceRoot":"","sources":["../src/RateLimiterFactoryInterface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RateLimit } from './RateLimit';
|
|
2
|
+
/**
|
|
3
|
+
* Represents a token reservation from a rate limiter.
|
|
4
|
+
*
|
|
5
|
+
* A reservation indicates when tokens will be available and allows waiting
|
|
6
|
+
* until that time.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Reservation {
|
|
9
|
+
private readonly timeToAct;
|
|
10
|
+
private readonly rateLimit;
|
|
11
|
+
constructor(timeToAct: number, rateLimit: RateLimit);
|
|
12
|
+
/**
|
|
13
|
+
* Get the timestamp (in milliseconds) when the action can be performed.
|
|
14
|
+
*/
|
|
15
|
+
getTimeToAct(): number;
|
|
16
|
+
/**
|
|
17
|
+
* Get the duration to wait (in milliseconds) before the action can be performed.
|
|
18
|
+
*/
|
|
19
|
+
getWaitDuration(): number;
|
|
20
|
+
/**
|
|
21
|
+
* Get the associated RateLimit object.
|
|
22
|
+
*/
|
|
23
|
+
getRateLimit(): RateLimit;
|
|
24
|
+
/**
|
|
25
|
+
* Wait until the reservation time (async operation).
|
|
26
|
+
*/
|
|
27
|
+
wait(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=Reservation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Reservation.d.ts","sourceRoot":"","sources":["../src/Reservation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAKnD;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,YAAY,IAAI,SAAS;IAIzB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Reservation = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Represents a token reservation from a rate limiter.
|
|
6
|
+
*
|
|
7
|
+
* A reservation indicates when tokens will be available and allows waiting
|
|
8
|
+
* until that time.
|
|
9
|
+
*/
|
|
10
|
+
class Reservation {
|
|
11
|
+
constructor(timeToAct, rateLimit) {
|
|
12
|
+
this.timeToAct = timeToAct;
|
|
13
|
+
this.rateLimit = rateLimit;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the timestamp (in milliseconds) when the action can be performed.
|
|
17
|
+
*/
|
|
18
|
+
getTimeToAct() {
|
|
19
|
+
return this.timeToAct;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get the duration to wait (in milliseconds) before the action can be performed.
|
|
23
|
+
*/
|
|
24
|
+
getWaitDuration() {
|
|
25
|
+
return Math.max(0, this.timeToAct - Date.now());
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the associated RateLimit object.
|
|
29
|
+
*/
|
|
30
|
+
getRateLimit() {
|
|
31
|
+
return this.rateLimit;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Wait until the reservation time (async operation).
|
|
35
|
+
*/
|
|
36
|
+
async wait() {
|
|
37
|
+
const waitMs = this.getWaitDuration();
|
|
38
|
+
if (waitMs > 0) {
|
|
39
|
+
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.Reservation = Reservation;
|
|
44
|
+
//# sourceMappingURL=Reservation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Reservation.js","sourceRoot":"","sources":["../src/Reservation.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,MAAa,WAAW;IAItB,YAAY,SAAiB,EAAE,SAAoB;QACjD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACtC,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;AAvCD,kCAuCC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompoundLimiter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/CompoundLimiter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const CompoundLimiter_1 = require("../CompoundLimiter");
|
|
4
|
+
const NoLimiter_1 = require("../policy/NoLimiter");
|
|
5
|
+
const FixedWindowLimiter_1 = require("../policy/FixedWindowLimiter");
|
|
6
|
+
const TokenBucketLimiter_1 = require("../policy/TokenBucketLimiter");
|
|
7
|
+
const InMemoryStorage_1 = require("../storage/InMemoryStorage");
|
|
8
|
+
const Rate_1 = require("../policy/Rate");
|
|
9
|
+
const ReserveNotSupportedError_1 = require("../errors/ReserveNotSupportedError");
|
|
10
|
+
describe('CompoundLimiter', () => {
|
|
11
|
+
describe('constructor', () => {
|
|
12
|
+
it('should create a compound limiter with multiple limiters', () => {
|
|
13
|
+
const limiters = [new NoLimiter_1.NoLimiter(), new NoLimiter_1.NoLimiter()];
|
|
14
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
15
|
+
expect(compound).toBeInstanceOf(CompoundLimiter_1.CompoundLimiter);
|
|
16
|
+
});
|
|
17
|
+
it('should throw error when no limiters provided', () => {
|
|
18
|
+
expect(() => new CompoundLimiter_1.CompoundLimiter([])).toThrow('CompoundLimiter requires at least one limiter');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('reserve', () => {
|
|
22
|
+
it('should always throw ReserveNotSupportedError with descriptive message', async () => {
|
|
23
|
+
const compound = new CompoundLimiter_1.CompoundLimiter([new NoLimiter_1.NoLimiter()]);
|
|
24
|
+
await expect(compound.reserve(1)).rejects.toThrow(ReserveNotSupportedError_1.ReserveNotSupportedError);
|
|
25
|
+
await expect(compound.reserve(1)).rejects.toThrow('CompoundLimiter does not support the reserve() method');
|
|
26
|
+
await expect(compound.reserve(1, 10)).rejects.toThrow(ReserveNotSupportedError_1.ReserveNotSupportedError);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('consume', () => {
|
|
30
|
+
it('should accept when all limiters accept', async () => {
|
|
31
|
+
const compound = new CompoundLimiter_1.CompoundLimiter([
|
|
32
|
+
new NoLimiter_1.NoLimiter(),
|
|
33
|
+
new NoLimiter_1.NoLimiter(),
|
|
34
|
+
]);
|
|
35
|
+
const result = await compound.consume(5);
|
|
36
|
+
expect(result.isAccepted()).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('should reject when any limiter rejects', async () => {
|
|
39
|
+
const storage = new InMemoryStorage_1.InMemoryStorage();
|
|
40
|
+
const limiters = [
|
|
41
|
+
new NoLimiter_1.NoLimiter(),
|
|
42
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test', 5, 60, storage),
|
|
43
|
+
];
|
|
44
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
45
|
+
// Exhaust the fixed window limiter
|
|
46
|
+
await limiters[1].consume(5);
|
|
47
|
+
const result = await compound.consume(1);
|
|
48
|
+
expect(result.isAccepted()).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
it('should return most restrictive result when all accept', async () => {
|
|
51
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
52
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
53
|
+
const limiters = [
|
|
54
|
+
new TokenBucketLimiter_1.TokenBucketLimiter('test1', 10, Rate_1.Rate.perSecond(1), storage1),
|
|
55
|
+
new TokenBucketLimiter_1.TokenBucketLimiter('test2', 20, Rate_1.Rate.perSecond(1), storage2),
|
|
56
|
+
];
|
|
57
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
58
|
+
await limiters[0].consume(5); // 5 remaining
|
|
59
|
+
await limiters[1].consume(10); // 10 remaining
|
|
60
|
+
const result = await compound.consume(1);
|
|
61
|
+
expect(result.isAccepted()).toBe(true);
|
|
62
|
+
expect(result.getRemainingTokens()).toBe(4); // Most restrictive (fewer tokens)
|
|
63
|
+
});
|
|
64
|
+
it('should return longest retry time when all reject', async () => {
|
|
65
|
+
jest.useFakeTimers();
|
|
66
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
67
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
68
|
+
const limiters = [
|
|
69
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test1', 5, 60, storage1),
|
|
70
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test2', 5, 120, storage2),
|
|
71
|
+
];
|
|
72
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
73
|
+
// Exhaust both limiters
|
|
74
|
+
await limiters[0].consume(5);
|
|
75
|
+
await limiters[1].consume(5);
|
|
76
|
+
const result = await compound.consume(1);
|
|
77
|
+
expect(result.isAccepted()).toBe(false);
|
|
78
|
+
// Should return the limiter with longer retry time (120s window)
|
|
79
|
+
const retryAfter = result.getRetryAfter();
|
|
80
|
+
expect(retryAfter.getTime()).toBeGreaterThan(Date.now());
|
|
81
|
+
jest.useRealTimers();
|
|
82
|
+
});
|
|
83
|
+
it('should prefer rejected over accepted', async () => {
|
|
84
|
+
const storage = new InMemoryStorage_1.InMemoryStorage();
|
|
85
|
+
const limiters = [
|
|
86
|
+
new NoLimiter_1.NoLimiter(),
|
|
87
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test', 5, 60, storage),
|
|
88
|
+
];
|
|
89
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
90
|
+
await limiters[1].consume(5);
|
|
91
|
+
const result = await compound.consume(1);
|
|
92
|
+
expect(result.isAccepted()).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
it('should handle default token parameter', async () => {
|
|
95
|
+
const compound = new CompoundLimiter_1.CompoundLimiter([new NoLimiter_1.NoLimiter()]);
|
|
96
|
+
const result = await compound.consume(); // Default 1 token
|
|
97
|
+
expect(result.isAccepted()).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
it('should evaluate all limiters', async () => {
|
|
100
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
101
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
102
|
+
const storage3 = new InMemoryStorage_1.InMemoryStorage();
|
|
103
|
+
const limiters = [
|
|
104
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test1', 10, 60, storage1),
|
|
105
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test2', 10, 60, storage2),
|
|
106
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test3', 10, 60, storage3),
|
|
107
|
+
];
|
|
108
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
109
|
+
const result = await compound.consume(5);
|
|
110
|
+
expect(result.isAccepted()).toBe(true);
|
|
111
|
+
// Verify all limiters were updated
|
|
112
|
+
const r1 = await limiters[0].consume(1);
|
|
113
|
+
const r2 = await limiters[1].consume(1);
|
|
114
|
+
const r3 = await limiters[2].consume(1);
|
|
115
|
+
expect(r1.getRemainingTokens()).toBe(4); // 10 - 5 - 1
|
|
116
|
+
expect(r2.getRemainingTokens()).toBe(4);
|
|
117
|
+
expect(r3.getRemainingTokens()).toBe(4);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('reset', () => {
|
|
121
|
+
it('should reset all limiters', async () => {
|
|
122
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
123
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
124
|
+
const limiters = [
|
|
125
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test1', 10, 60, storage1),
|
|
126
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test2', 10, 60, storage2),
|
|
127
|
+
];
|
|
128
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
129
|
+
await compound.consume(5);
|
|
130
|
+
await compound.reset();
|
|
131
|
+
const result = await compound.consume(1);
|
|
132
|
+
expect(result.isAccepted()).toBe(true);
|
|
133
|
+
expect(result.getRemainingTokens()).toBe(9);
|
|
134
|
+
});
|
|
135
|
+
it('should handle reset with single limiter', async () => {
|
|
136
|
+
const storage = new InMemoryStorage_1.InMemoryStorage();
|
|
137
|
+
const compound = new CompoundLimiter_1.CompoundLimiter([
|
|
138
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage),
|
|
139
|
+
]);
|
|
140
|
+
await compound.consume(10);
|
|
141
|
+
await compound.reset();
|
|
142
|
+
const result = await compound.consume(5);
|
|
143
|
+
expect(result.isAccepted()).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('complex scenarios', () => {
|
|
147
|
+
it('should enforce multiple rate limits simultaneously', async () => {
|
|
148
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
149
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
150
|
+
// Per-second and per-minute limits
|
|
151
|
+
const limiters = [
|
|
152
|
+
new TokenBucketLimiter_1.TokenBucketLimiter('per-second', 5, Rate_1.Rate.perSecond(5), storage1),
|
|
153
|
+
new TokenBucketLimiter_1.TokenBucketLimiter('per-minute', 50, Rate_1.Rate.perMinute(50), storage2),
|
|
154
|
+
];
|
|
155
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
156
|
+
// Should be limited by per-second limit
|
|
157
|
+
for (let i = 0; i < 5; i++) {
|
|
158
|
+
const result = await compound.consume(1);
|
|
159
|
+
expect(result.isAccepted()).toBe(true);
|
|
160
|
+
}
|
|
161
|
+
const result = await compound.consume(1);
|
|
162
|
+
expect(result.isAccepted()).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
it('should handle mix of limiter types', async () => {
|
|
165
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
166
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
167
|
+
const limiters = [
|
|
168
|
+
new NoLimiter_1.NoLimiter(),
|
|
169
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('fixed', 10, 60, storage1),
|
|
170
|
+
new TokenBucketLimiter_1.TokenBucketLimiter('token', 15, Rate_1.Rate.perSecond(1), storage2),
|
|
171
|
+
];
|
|
172
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
173
|
+
const result = await compound.consume(5);
|
|
174
|
+
expect(result.isAccepted()).toBe(true);
|
|
175
|
+
expect(result.getRemainingTokens()).toBe(5); // Limited by FixedWindowLimiter
|
|
176
|
+
});
|
|
177
|
+
it('should handle progressive consumption', async () => {
|
|
178
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
179
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
180
|
+
const limiters = [
|
|
181
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test1', 10, 60, storage1),
|
|
182
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test2', 20, 60, storage2),
|
|
183
|
+
];
|
|
184
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
185
|
+
// Consume progressively
|
|
186
|
+
const results = [];
|
|
187
|
+
for (let i = 0; i < 15; i++) {
|
|
188
|
+
results.push(await compound.consume(1));
|
|
189
|
+
}
|
|
190
|
+
const accepted = results.filter(r => r.isAccepted()).length;
|
|
191
|
+
const rejected = results.filter(r => !r.isAccepted()).length;
|
|
192
|
+
expect(accepted).toBe(10); // Limited by first limiter
|
|
193
|
+
expect(rejected).toBe(5);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('edge cases', () => {
|
|
197
|
+
it('should handle single limiter compound', async () => {
|
|
198
|
+
const storage = new InMemoryStorage_1.InMemoryStorage();
|
|
199
|
+
const compound = new CompoundLimiter_1.CompoundLimiter([
|
|
200
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage),
|
|
201
|
+
]);
|
|
202
|
+
const result = await compound.consume(5);
|
|
203
|
+
expect(result.isAccepted()).toBe(true);
|
|
204
|
+
expect(result.getRemainingTokens()).toBe(5);
|
|
205
|
+
});
|
|
206
|
+
it('should handle many limiters', async () => {
|
|
207
|
+
const limiters = Array(10).fill(null).map(() => new NoLimiter_1.NoLimiter());
|
|
208
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
209
|
+
const result = await compound.consume(100);
|
|
210
|
+
expect(result.isAccepted()).toBe(true);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
describe('AND logic', () => {
|
|
214
|
+
it('should require all limiters to accept', async () => {
|
|
215
|
+
const storage1 = new InMemoryStorage_1.InMemoryStorage();
|
|
216
|
+
const storage2 = new InMemoryStorage_1.InMemoryStorage();
|
|
217
|
+
const storage3 = new InMemoryStorage_1.InMemoryStorage();
|
|
218
|
+
const limiters = [
|
|
219
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test1', 10, 60, storage1),
|
|
220
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test2', 10, 60, storage2),
|
|
221
|
+
new FixedWindowLimiter_1.FixedWindowLimiter('test3', 10, 60, storage3),
|
|
222
|
+
];
|
|
223
|
+
const compound = new CompoundLimiter_1.CompoundLimiter(limiters);
|
|
224
|
+
// Exhaust just one limiter
|
|
225
|
+
await limiters[1].consume(10);
|
|
226
|
+
const result = await compound.consume(1);
|
|
227
|
+
expect(result.isAccepted()).toBe(false);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
//# sourceMappingURL=CompoundLimiter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompoundLimiter.test.js","sourceRoot":"","sources":["../../src/__tests__/CompoundLimiter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompoundRateLimiterFactory.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/CompoundRateLimiterFactory.test.ts"],"names":[],"mappings":""}
|