@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,58 @@
|
|
|
1
|
+
import type { LimiterStateInterface } from '../LimiterStateInterface';
|
|
2
|
+
/**
|
|
3
|
+
* Serializable state for FixedWindowLimiter.
|
|
4
|
+
*
|
|
5
|
+
* Tracks hit count within a fixed time window.
|
|
6
|
+
*/
|
|
7
|
+
export declare class Window implements LimiterStateInterface {
|
|
8
|
+
private readonly id;
|
|
9
|
+
private hitCount;
|
|
10
|
+
private readonly intervalInSeconds;
|
|
11
|
+
private readonly maxSize;
|
|
12
|
+
private timer;
|
|
13
|
+
constructor(id: string, intervalInSeconds: number, maxSize: number, hitCount?: number, timer?: number);
|
|
14
|
+
getId(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Get the expiration time in seconds since epoch.
|
|
17
|
+
*/
|
|
18
|
+
getExpirationTime(): number;
|
|
19
|
+
/**
|
|
20
|
+
* Add hits to the window.
|
|
21
|
+
*/
|
|
22
|
+
add(hits: number, now?: number): void;
|
|
23
|
+
/**
|
|
24
|
+
* Get the current hit count.
|
|
25
|
+
*/
|
|
26
|
+
getHitCount(): number;
|
|
27
|
+
/**
|
|
28
|
+
* Get the window timer (start of current window).
|
|
29
|
+
*/
|
|
30
|
+
getTimer(): number;
|
|
31
|
+
/**
|
|
32
|
+
* Get the interval in seconds.
|
|
33
|
+
*/
|
|
34
|
+
getInterval(): number;
|
|
35
|
+
/**
|
|
36
|
+
* Get available tokens at a given time.
|
|
37
|
+
*/
|
|
38
|
+
getAvailableTokens(now?: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Calculate time needed for N tokens to become available.
|
|
41
|
+
*/
|
|
42
|
+
calculateTimeForTokens(tokens: number, now?: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Convert to JSON for serialization.
|
|
45
|
+
*/
|
|
46
|
+
toJSON(): Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Create from JSON.
|
|
49
|
+
*/
|
|
50
|
+
static fromJSON(data: {
|
|
51
|
+
id: string;
|
|
52
|
+
hitCount: number;
|
|
53
|
+
intervalInSeconds: number;
|
|
54
|
+
maxSize: number;
|
|
55
|
+
timer: number;
|
|
56
|
+
}): Window;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=Window.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Window.d.ts","sourceRoot":"","sources":["../../src/policy/Window.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGtE;;;;GAIG;AACH,qBAAa,MAAO,YAAW,qBAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,KAAK,CAAS;gBAGpB,EAAE,EAAE,MAAM,EACV,iBAAiB,EAAE,MAAM,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM;IAShB,KAAK,IAAI,MAAM;IAIf;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAgBrC;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIlB;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,kBAAkB,CAAC,GAAG,GAAE,MAAuB,GAAG,MAAM;IASxD;;OAEG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAuB,GAAG,MAAM;IAY5E;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUjC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;QACpB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,MAAM;CASX"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Window = void 0;
|
|
4
|
+
const TimeUtil_1 = require("../util/TimeUtil");
|
|
5
|
+
/**
|
|
6
|
+
* Serializable state for FixedWindowLimiter.
|
|
7
|
+
*
|
|
8
|
+
* Tracks hit count within a fixed time window.
|
|
9
|
+
*/
|
|
10
|
+
class Window {
|
|
11
|
+
constructor(id, intervalInSeconds, maxSize, hitCount, timer) {
|
|
12
|
+
this.id = id;
|
|
13
|
+
this.intervalInSeconds = intervalInSeconds;
|
|
14
|
+
this.maxSize = maxSize;
|
|
15
|
+
this.hitCount = hitCount ?? 0;
|
|
16
|
+
this.timer = timer ?? TimeUtil_1.TimeUtil.now();
|
|
17
|
+
}
|
|
18
|
+
getId() {
|
|
19
|
+
return this.id;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get the expiration time in seconds since epoch.
|
|
23
|
+
*/
|
|
24
|
+
getExpirationTime() {
|
|
25
|
+
return Math.ceil(this.timer + this.intervalInSeconds);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Add hits to the window.
|
|
29
|
+
*/
|
|
30
|
+
add(hits, now) {
|
|
31
|
+
if (now === undefined) {
|
|
32
|
+
now = TimeUtil_1.TimeUtil.now();
|
|
33
|
+
}
|
|
34
|
+
// Check if we've moved to a new window
|
|
35
|
+
if (now >= this.timer + this.intervalInSeconds) {
|
|
36
|
+
// New window - reset
|
|
37
|
+
this.hitCount = hits;
|
|
38
|
+
this.timer = Math.floor(now / this.intervalInSeconds) * this.intervalInSeconds;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Same window - increment
|
|
42
|
+
this.hitCount += hits;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the current hit count.
|
|
47
|
+
*/
|
|
48
|
+
getHitCount() {
|
|
49
|
+
return this.hitCount;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the window timer (start of current window).
|
|
53
|
+
*/
|
|
54
|
+
getTimer() {
|
|
55
|
+
return this.timer;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the interval in seconds.
|
|
59
|
+
*/
|
|
60
|
+
getInterval() {
|
|
61
|
+
return this.intervalInSeconds;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get available tokens at a given time.
|
|
65
|
+
*/
|
|
66
|
+
getAvailableTokens(now = TimeUtil_1.TimeUtil.now()) {
|
|
67
|
+
// Check if we're in a new window
|
|
68
|
+
if (now >= this.timer + this.intervalInSeconds) {
|
|
69
|
+
return this.maxSize; // New window, all tokens available
|
|
70
|
+
}
|
|
71
|
+
return Math.max(0, this.maxSize - this.hitCount);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Calculate time needed for N tokens to become available.
|
|
75
|
+
*/
|
|
76
|
+
calculateTimeForTokens(tokens, now = TimeUtil_1.TimeUtil.now()) {
|
|
77
|
+
const available = this.getAvailableTokens(now);
|
|
78
|
+
if (available >= tokens) {
|
|
79
|
+
return 0; // Already available
|
|
80
|
+
}
|
|
81
|
+
// Need to wait for next window
|
|
82
|
+
const windowEnd = this.timer + this.intervalInSeconds;
|
|
83
|
+
return windowEnd - now;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Convert to JSON for serialization.
|
|
87
|
+
*/
|
|
88
|
+
toJSON() {
|
|
89
|
+
return {
|
|
90
|
+
id: this.id,
|
|
91
|
+
hitCount: this.hitCount,
|
|
92
|
+
intervalInSeconds: this.intervalInSeconds,
|
|
93
|
+
maxSize: this.maxSize,
|
|
94
|
+
timer: this.timer,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Create from JSON.
|
|
99
|
+
*/
|
|
100
|
+
static fromJSON(data) {
|
|
101
|
+
return new Window(data.id, data.intervalInSeconds, data.maxSize, data.hitCount, data.timer);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.Window = Window;
|
|
105
|
+
//# sourceMappingURL=Window.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Window.js","sourceRoot":"","sources":["../../src/policy/Window.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindowLimiter.test.d.ts","sourceRoot":"","sources":["../../../src/policy/__tests__/FixedWindowLimiter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const FixedWindowLimiter_1 = require("../FixedWindowLimiter");
|
|
4
|
+
const InMemoryStorage_1 = require("../../storage/InMemoryStorage");
|
|
5
|
+
const MaxWaitDurationExceededError_1 = require("../../errors/MaxWaitDurationExceededError");
|
|
6
|
+
describe('FixedWindowLimiter', () => {
|
|
7
|
+
let storage;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
storage = new InMemoryStorage_1.InMemoryStorage();
|
|
10
|
+
});
|
|
11
|
+
describe('consume', () => {
|
|
12
|
+
it('should accept requests within limit', async () => {
|
|
13
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
14
|
+
const result = await limiter.consume(5);
|
|
15
|
+
expect(result.isAccepted()).toBe(true);
|
|
16
|
+
expect(result.getRemainingTokens()).toBe(5);
|
|
17
|
+
expect(result.getLimit()).toBe(10);
|
|
18
|
+
});
|
|
19
|
+
it('should reject requests when limit exceeded', async () => {
|
|
20
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
21
|
+
await limiter.consume(10);
|
|
22
|
+
const result = await limiter.consume(1);
|
|
23
|
+
expect(result.isAccepted()).toBe(false);
|
|
24
|
+
expect(result.getRemainingTokens()).toBe(0);
|
|
25
|
+
});
|
|
26
|
+
it('should track hits within window', async () => {
|
|
27
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
28
|
+
const r1 = await limiter.consume(3);
|
|
29
|
+
const r2 = await limiter.consume(2);
|
|
30
|
+
const r3 = await limiter.consume(4);
|
|
31
|
+
expect(r1.getRemainingTokens()).toBe(7);
|
|
32
|
+
expect(r2.getRemainingTokens()).toBe(5);
|
|
33
|
+
expect(r3.getRemainingTokens()).toBe(1);
|
|
34
|
+
});
|
|
35
|
+
it('should reset in new window', async () => {
|
|
36
|
+
jest.useFakeTimers();
|
|
37
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
38
|
+
await limiter.consume(10);
|
|
39
|
+
// Move to new window (60+ seconds later)
|
|
40
|
+
jest.advanceTimersByTime(61000);
|
|
41
|
+
const result = await limiter.consume(5);
|
|
42
|
+
expect(result.isAccepted()).toBe(true);
|
|
43
|
+
expect(result.getRemainingTokens()).toBe(5);
|
|
44
|
+
jest.useRealTimers();
|
|
45
|
+
});
|
|
46
|
+
it('should provide retry time when rate limited', async () => {
|
|
47
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
48
|
+
await limiter.consume(10);
|
|
49
|
+
const result = await limiter.consume(1);
|
|
50
|
+
expect(result.isAccepted()).toBe(false);
|
|
51
|
+
expect(result.getRetryAfter().getTime()).toBeGreaterThan(Date.now());
|
|
52
|
+
});
|
|
53
|
+
it('should align windows to interval boundaries', async () => {
|
|
54
|
+
jest.useFakeTimers();
|
|
55
|
+
const startTime = 1000000;
|
|
56
|
+
jest.setSystemTime(startTime);
|
|
57
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
58
|
+
await limiter.consume(8);
|
|
59
|
+
const r1 = await limiter.consume(1);
|
|
60
|
+
expect(r1.getRemainingTokens()).toBe(1);
|
|
61
|
+
// Move to next window (60+ seconds later)
|
|
62
|
+
jest.setSystemTime(startTime + 61000);
|
|
63
|
+
const r2 = await limiter.consume(5);
|
|
64
|
+
expect(r2.getRemainingTokens()).toBe(5);
|
|
65
|
+
jest.useRealTimers();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('reserve', () => {
|
|
69
|
+
it('should reserve tokens when available', async () => {
|
|
70
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
71
|
+
const reservation = await limiter.reserve(5);
|
|
72
|
+
expect(reservation.getWaitDuration()).toBe(0);
|
|
73
|
+
expect(reservation.getRateLimit().isAccepted()).toBe(true);
|
|
74
|
+
expect(reservation.getRateLimit().getRemainingTokens()).toBe(5);
|
|
75
|
+
});
|
|
76
|
+
it('should calculate wait time for next window', async () => {
|
|
77
|
+
jest.useFakeTimers();
|
|
78
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
79
|
+
await limiter.consume(10);
|
|
80
|
+
const reservation = await limiter.reserve(5);
|
|
81
|
+
expect(reservation.getWaitDuration()).toBeGreaterThan(0);
|
|
82
|
+
expect(reservation.getRateLimit().isAccepted()).toBe(true);
|
|
83
|
+
jest.useRealTimers();
|
|
84
|
+
});
|
|
85
|
+
it('should throw error when exceeding maxTime', async () => {
|
|
86
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
87
|
+
await limiter.consume(10);
|
|
88
|
+
await expect(limiter.reserve(5, 1)).rejects.toThrow(MaxWaitDurationExceededError_1.MaxWaitDurationExceededError);
|
|
89
|
+
});
|
|
90
|
+
it('should throw error when requesting more than limit', async () => {
|
|
91
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
92
|
+
await expect(limiter.reserve(15)).rejects.toThrow('Cannot reserve 15 tokens, limit is 10');
|
|
93
|
+
});
|
|
94
|
+
it('should reserve immediately in new window', async () => {
|
|
95
|
+
jest.useFakeTimers();
|
|
96
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
97
|
+
await limiter.consume(10);
|
|
98
|
+
jest.advanceTimersByTime(61000);
|
|
99
|
+
const reservation = await limiter.reserve(5);
|
|
100
|
+
expect(reservation.getWaitDuration()).toBe(0);
|
|
101
|
+
jest.useRealTimers();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('reset', () => {
|
|
105
|
+
it('should reset the limiter state', async () => {
|
|
106
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
107
|
+
await limiter.consume(10);
|
|
108
|
+
await limiter.reset();
|
|
109
|
+
const result = await limiter.consume(10);
|
|
110
|
+
expect(result.isAccepted()).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
it('should start fresh after reset', async () => {
|
|
113
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
114
|
+
await limiter.consume(5);
|
|
115
|
+
await limiter.reset();
|
|
116
|
+
const result = await limiter.consume(1);
|
|
117
|
+
expect(result.getRemainingTokens()).toBe(9);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('multiple limiters', () => {
|
|
121
|
+
it('should maintain separate state for different IDs', async () => {
|
|
122
|
+
const limiter1 = new FixedWindowLimiter_1.FixedWindowLimiter('user1', 10, 60, storage);
|
|
123
|
+
const limiter2 = new FixedWindowLimiter_1.FixedWindowLimiter('user2', 10, 60, storage);
|
|
124
|
+
await limiter1.consume(8);
|
|
125
|
+
await limiter2.consume(3);
|
|
126
|
+
const r1 = await limiter1.consume(1);
|
|
127
|
+
const r2 = await limiter2.consume(1);
|
|
128
|
+
expect(r1.getRemainingTokens()).toBe(1);
|
|
129
|
+
expect(r2.getRemainingTokens()).toBe(6);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe('window boundaries', () => {
|
|
133
|
+
it('should allow bursts at window boundaries', async () => {
|
|
134
|
+
jest.useFakeTimers();
|
|
135
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
136
|
+
// Consume all in current window
|
|
137
|
+
await limiter.consume(10);
|
|
138
|
+
// Still in same window - should be rejected
|
|
139
|
+
const r1 = await limiter.consume(1);
|
|
140
|
+
expect(r1.isAccepted()).toBe(false);
|
|
141
|
+
// Move to next window (60+ seconds)
|
|
142
|
+
jest.advanceTimersByTime(61000);
|
|
143
|
+
const r2 = await limiter.consume(10);
|
|
144
|
+
expect(r2.isAccepted()).toBe(true);
|
|
145
|
+
jest.useRealTimers();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('edge cases', () => {
|
|
149
|
+
it('should handle limit of 1', async () => {
|
|
150
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 1, 60, storage);
|
|
151
|
+
const r1 = await limiter.consume(1);
|
|
152
|
+
const r2 = await limiter.consume(1);
|
|
153
|
+
expect(r1.isAccepted()).toBe(true);
|
|
154
|
+
expect(r2.isAccepted()).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
it('should handle interval of 1 second', async () => {
|
|
157
|
+
jest.useFakeTimers();
|
|
158
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 1, storage);
|
|
159
|
+
await limiter.consume(10);
|
|
160
|
+
jest.advanceTimersByTime(1000);
|
|
161
|
+
const result = await limiter.consume(5);
|
|
162
|
+
expect(result.isAccepted()).toBe(true);
|
|
163
|
+
jest.useRealTimers();
|
|
164
|
+
});
|
|
165
|
+
it('should handle default parameters', async () => {
|
|
166
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 10, 60, storage);
|
|
167
|
+
const result = await limiter.consume(); // Default 1 token
|
|
168
|
+
expect(result.isAccepted()).toBe(true);
|
|
169
|
+
expect(result.getRemainingTokens()).toBe(9);
|
|
170
|
+
});
|
|
171
|
+
it('should handle very large intervals', async () => {
|
|
172
|
+
const limiter = new FixedWindowLimiter_1.FixedWindowLimiter('test', 1000, 86400, storage); // 1 day
|
|
173
|
+
await limiter.consume(500);
|
|
174
|
+
const result = await limiter.consume(400);
|
|
175
|
+
expect(result.isAccepted()).toBe(true);
|
|
176
|
+
expect(result.getRemainingTokens()).toBe(100);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=FixedWindowLimiter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindowLimiter.test.js","sourceRoot":"","sources":["../../../src/policy/__tests__/FixedWindowLimiter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoLimiter.test.d.ts","sourceRoot":"","sources":["../../../src/policy/__tests__/NoLimiter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const NoLimiter_1 = require("../NoLimiter");
|
|
4
|
+
describe('NoLimiter', () => {
|
|
5
|
+
let limiter;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
limiter = new NoLimiter_1.NoLimiter();
|
|
8
|
+
});
|
|
9
|
+
describe('reserve', () => {
|
|
10
|
+
it('should always return an immediate reservation with maximum tokens', async () => {
|
|
11
|
+
const reservation = await limiter.reserve(100);
|
|
12
|
+
expect(reservation.getWaitDuration()).toBe(0);
|
|
13
|
+
expect(reservation.getRateLimit().isAccepted()).toBe(true);
|
|
14
|
+
expect(reservation.getRateLimit().getRemainingTokens()).toBe(Number.MAX_SAFE_INTEGER);
|
|
15
|
+
expect(reservation.getRateLimit().getLimit()).toBe(Number.MAX_SAFE_INTEGER);
|
|
16
|
+
});
|
|
17
|
+
it('should ignore maxTime parameter', async () => {
|
|
18
|
+
const reservation = await limiter.reserve(100, 0);
|
|
19
|
+
expect(reservation.getRateLimit().isAccepted()).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('consume', () => {
|
|
23
|
+
it('should always accept consumption with maximum tokens', async () => {
|
|
24
|
+
const rateLimit = await limiter.consume(100);
|
|
25
|
+
expect(rateLimit.isAccepted()).toBe(true);
|
|
26
|
+
expect(rateLimit.getRemainingTokens()).toBe(Number.MAX_SAFE_INTEGER);
|
|
27
|
+
expect(rateLimit.getLimit()).toBe(Number.MAX_SAFE_INTEGER);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('reset', () => {
|
|
31
|
+
it('should not affect future requests', async () => {
|
|
32
|
+
const before = await limiter.consume(100);
|
|
33
|
+
await limiter.reset();
|
|
34
|
+
const after = await limiter.consume(100);
|
|
35
|
+
expect(before.isAccepted()).toBe(true);
|
|
36
|
+
expect(after.isAccepted()).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=NoLimiter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoLimiter.test.js","sourceRoot":"","sources":["../../../src/policy/__tests__/NoLimiter.test.ts"],"names":[],"mappings":";;AAAA,4CAAyC;AAEzC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAI,OAAkB,CAAC;IAEvB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,IAAI,qBAAS,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAE/C,MAAM,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3D,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YACtF,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAElD,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;YACpE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YACrE,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAEzC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Rate.test.d.ts","sourceRoot":"","sources":["../../../src/policy/__tests__/Rate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const Rate_1 = require("../Rate");
|
|
4
|
+
const InvalidIntervalError_1 = require("../../errors/InvalidIntervalError");
|
|
5
|
+
describe('Rate', () => {
|
|
6
|
+
describe('constructor', () => {
|
|
7
|
+
it('should create a rate with valid parameters', () => {
|
|
8
|
+
const rate = new Rate_1.Rate(60, 10);
|
|
9
|
+
expect(rate.getInterval()).toBe(60);
|
|
10
|
+
expect(rate.getAmount()).toBe(10);
|
|
11
|
+
});
|
|
12
|
+
it('should throw error for interval less than 1', () => {
|
|
13
|
+
expect(() => new Rate_1.Rate(0, 10)).toThrow(InvalidIntervalError_1.InvalidIntervalError);
|
|
14
|
+
expect(() => new Rate_1.Rate(-1, 10)).toThrow(InvalidIntervalError_1.InvalidIntervalError);
|
|
15
|
+
expect(() => new Rate_1.Rate(0.5, 10)).toThrow(InvalidIntervalError_1.InvalidIntervalError);
|
|
16
|
+
});
|
|
17
|
+
it('should throw error for amount less than 1', () => {
|
|
18
|
+
expect(() => new Rate_1.Rate(60, 0)).toThrow(InvalidIntervalError_1.InvalidIntervalError);
|
|
19
|
+
expect(() => new Rate_1.Rate(60, -1)).toThrow(InvalidIntervalError_1.InvalidIntervalError);
|
|
20
|
+
expect(() => new Rate_1.Rate(60, 0.5)).toThrow(InvalidIntervalError_1.InvalidIntervalError);
|
|
21
|
+
});
|
|
22
|
+
it('should accept minimum valid values', () => {
|
|
23
|
+
const rate = new Rate_1.Rate(1, 1);
|
|
24
|
+
expect(rate.getInterval()).toBe(1);
|
|
25
|
+
expect(rate.getAmount()).toBe(1);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('static factory methods', () => {
|
|
29
|
+
it('should create rates with correct intervals and amounts', () => {
|
|
30
|
+
const testCases = [
|
|
31
|
+
{ method: () => Rate_1.Rate.perSecond(5), expectedInterval: 1, expectedAmount: 5 },
|
|
32
|
+
{ method: () => Rate_1.Rate.perMinute(100), expectedInterval: 60, expectedAmount: 100 },
|
|
33
|
+
{ method: () => Rate_1.Rate.perHour(1000), expectedInterval: 3600, expectedAmount: 1000 },
|
|
34
|
+
{ method: () => Rate_1.Rate.perDay(10000), expectedInterval: 86400, expectedAmount: 10000 },
|
|
35
|
+
{ method: () => Rate_1.Rate.perWeek(50000), expectedInterval: 604800, expectedAmount: 50000 },
|
|
36
|
+
{ method: () => Rate_1.Rate.perMonth(100000), expectedInterval: 2592000, expectedAmount: 100000 },
|
|
37
|
+
{ method: () => Rate_1.Rate.perYear(1000000), expectedInterval: 31536000, expectedAmount: 1000000 },
|
|
38
|
+
];
|
|
39
|
+
testCases.forEach(({ method, expectedInterval, expectedAmount }) => {
|
|
40
|
+
const rate = method();
|
|
41
|
+
expect(rate.getInterval()).toBe(expectedInterval);
|
|
42
|
+
expect(rate.getAmount()).toBe(expectedAmount);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('fromString', () => {
|
|
47
|
+
it('should parse valid rate strings', () => {
|
|
48
|
+
const rate1 = Rate_1.Rate.fromString('60 seconds-100');
|
|
49
|
+
expect(rate1.getInterval()).toBe(60);
|
|
50
|
+
expect(rate1.getAmount()).toBe(100);
|
|
51
|
+
const rate2 = Rate_1.Rate.fromString('1 hour-1000');
|
|
52
|
+
expect(rate2.getInterval()).toBe(3600);
|
|
53
|
+
expect(rate2.getAmount()).toBe(1000);
|
|
54
|
+
});
|
|
55
|
+
it('should handle whitespace in rate strings', () => {
|
|
56
|
+
const rate = Rate_1.Rate.fromString(' 1 minute - 50 ');
|
|
57
|
+
expect(rate.getInterval()).toBe(60);
|
|
58
|
+
expect(rate.getAmount()).toBe(50);
|
|
59
|
+
});
|
|
60
|
+
it('should throw error for invalid format', () => {
|
|
61
|
+
expect(() => Rate_1.Rate.fromString('invalid')).toThrow('Invalid rate format');
|
|
62
|
+
expect(() => Rate_1.Rate.fromString('60')).toThrow('Invalid rate format');
|
|
63
|
+
expect(() => Rate_1.Rate.fromString('60-100-200')).toThrow('Invalid rate format');
|
|
64
|
+
});
|
|
65
|
+
it('should throw error for invalid amount', () => {
|
|
66
|
+
expect(() => Rate_1.Rate.fromString('60 seconds-abc')).toThrow('Invalid amount in rate string');
|
|
67
|
+
expect(() => Rate_1.Rate.fromString('60 seconds-')).toThrow('Invalid amount in rate string');
|
|
68
|
+
});
|
|
69
|
+
it('should throw error for invalid duration', () => {
|
|
70
|
+
expect(() => Rate_1.Rate.fromString('invalid duration-100')).toThrow();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('calculateTimeForTokens', () => {
|
|
74
|
+
it('should calculate time for single token', () => {
|
|
75
|
+
const rate = new Rate_1.Rate(60, 10); // 10 tokens per 60 seconds
|
|
76
|
+
const time = rate.calculateTimeForTokens(1);
|
|
77
|
+
expect(time).toBe(6); // 60 / 10 = 6 seconds per token
|
|
78
|
+
});
|
|
79
|
+
it('should calculate time for multiple tokens', () => {
|
|
80
|
+
const rate = new Rate_1.Rate(60, 10); // 10 tokens per 60 seconds
|
|
81
|
+
const time = rate.calculateTimeForTokens(5);
|
|
82
|
+
expect(time).toBe(30); // 5 tokens * 6 seconds = 30 seconds
|
|
83
|
+
});
|
|
84
|
+
it('should round up to nearest second', () => {
|
|
85
|
+
const rate = new Rate_1.Rate(10, 3); // 3 tokens per 10 seconds
|
|
86
|
+
const time = rate.calculateTimeForTokens(1);
|
|
87
|
+
expect(time).toBe(4); // ceil(10 / 3) = 4
|
|
88
|
+
});
|
|
89
|
+
it('should handle exact multiples', () => {
|
|
90
|
+
const rate = new Rate_1.Rate(100, 5); // 5 tokens per 100 seconds
|
|
91
|
+
const time = rate.calculateTimeForTokens(2);
|
|
92
|
+
expect(time).toBe(40); // 2 * 20 = 40
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('calculateNextTokenAvailability', () => {
|
|
96
|
+
it('should calculate next token availability from now', () => {
|
|
97
|
+
const rate = Rate_1.Rate.perSecond(2); // 2 tokens per second, so 0.5 seconds per token
|
|
98
|
+
const nextAvailable = rate.calculateNextTokenAvailability();
|
|
99
|
+
const expectedTime = Date.now() + 500; // 0.5 seconds from now
|
|
100
|
+
expect(nextAvailable.getTime()).toBeGreaterThanOrEqual(expectedTime - 10);
|
|
101
|
+
expect(nextAvailable.getTime()).toBeLessThanOrEqual(expectedTime + 10);
|
|
102
|
+
});
|
|
103
|
+
it('should calculate next token availability from specific time', () => {
|
|
104
|
+
const rate = Rate_1.Rate.perSecond(4); // 4 tokens per second, so 0.25 seconds per token
|
|
105
|
+
const now = 1000; // 1000 seconds since epoch
|
|
106
|
+
const nextAvailable = rate.calculateNextTokenAvailability(now);
|
|
107
|
+
expect(nextAvailable.getTime()).toBe(1000250); // (1000 + 0.25) * 1000
|
|
108
|
+
});
|
|
109
|
+
it('should handle slow rates', () => {
|
|
110
|
+
const rate = Rate_1.Rate.perMinute(1); // 1 token per minute
|
|
111
|
+
const now = 1000;
|
|
112
|
+
const nextAvailable = rate.calculateNextTokenAvailability(now);
|
|
113
|
+
expect(nextAvailable.getTime()).toBe(1060000); // (1000 + 60) * 1000
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('calculateNewTokensDuringInterval', () => {
|
|
117
|
+
it('should calculate tokens for exact interval', () => {
|
|
118
|
+
const rate = new Rate_1.Rate(60, 10); // 10 tokens per 60 seconds
|
|
119
|
+
const tokens = rate.calculateNewTokensDuringInterval(60);
|
|
120
|
+
expect(tokens).toBe(10);
|
|
121
|
+
});
|
|
122
|
+
it('should calculate tokens for partial interval', () => {
|
|
123
|
+
const rate = new Rate_1.Rate(60, 10); // 10 tokens per 60 seconds
|
|
124
|
+
const tokens = rate.calculateNewTokensDuringInterval(30);
|
|
125
|
+
expect(tokens).toBe(5); // Half the interval = half the tokens
|
|
126
|
+
});
|
|
127
|
+
it('should calculate tokens for multiple intervals', () => {
|
|
128
|
+
const rate = new Rate_1.Rate(60, 10);
|
|
129
|
+
const tokens = rate.calculateNewTokensDuringInterval(180);
|
|
130
|
+
expect(tokens).toBe(30); // 3 intervals * 10 tokens
|
|
131
|
+
});
|
|
132
|
+
it('should floor fractional tokens', () => {
|
|
133
|
+
const rate = new Rate_1.Rate(10, 3); // 3 tokens per 10 seconds
|
|
134
|
+
const tokens = rate.calculateNewTokensDuringInterval(5);
|
|
135
|
+
expect(tokens).toBe(1); // floor(5 * 3 / 10) = floor(1.5) = 1
|
|
136
|
+
});
|
|
137
|
+
it('should return 0 for very short durations', () => {
|
|
138
|
+
const rate = new Rate_1.Rate(60, 10);
|
|
139
|
+
const tokens = rate.calculateNewTokensDuringInterval(1);
|
|
140
|
+
expect(tokens).toBe(0); // floor(1 * 10 / 60) = 0
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('getRefillInterval', () => {
|
|
144
|
+
it('should calculate refill interval (time per token)', () => {
|
|
145
|
+
const rate = new Rate_1.Rate(60, 10); // 10 tokens per 60 seconds
|
|
146
|
+
expect(rate.getRefillInterval()).toBe(6); // 60 / 10 = 6 seconds per token
|
|
147
|
+
});
|
|
148
|
+
it('should handle fast rates', () => {
|
|
149
|
+
const rate = Rate_1.Rate.perSecond(100); // 100 tokens per second
|
|
150
|
+
expect(rate.getRefillInterval()).toBe(0.01); // 1 / 100 = 0.01 seconds per token
|
|
151
|
+
});
|
|
152
|
+
it('should handle slow rates', () => {
|
|
153
|
+
const rate = Rate_1.Rate.perHour(1); // 1 token per hour
|
|
154
|
+
expect(rate.getRefillInterval()).toBe(3600); // 3600 / 1 = 3600 seconds per token
|
|
155
|
+
});
|
|
156
|
+
it('should handle 1:1 rate', () => {
|
|
157
|
+
const rate = new Rate_1.Rate(1, 1);
|
|
158
|
+
expect(rate.getRefillInterval()).toBe(1);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=Rate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Rate.test.js","sourceRoot":"","sources":["../../../src/policy/__tests__/Rate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlidingWindow.test.d.ts","sourceRoot":"","sources":["../../../src/policy/__tests__/SlidingWindow.test.ts"],"names":[],"mappings":""}
|