@stimulcross/rate-limiter 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/lib/core/cancellable.d.ts +5 -0
  2. package/lib/core/cancellable.js +1 -0
  3. package/lib/core/clock.d.ts +10 -0
  4. package/lib/core/clock.js +1 -0
  5. package/lib/core/decision.d.ts +23 -0
  6. package/lib/core/decision.js +1 -0
  7. package/lib/core/rate-limit-policy.d.ts +14 -0
  8. package/lib/core/rate-limit-policy.js +1 -0
  9. package/lib/core/rate-limiter-status.d.ts +14 -0
  10. package/lib/core/rate-limiter-status.js +1 -0
  11. package/lib/core/rate-limiter.d.ts +34 -0
  12. package/lib/core/rate-limiter.js +1 -0
  13. package/lib/core/state-storage.d.ts +46 -0
  14. package/lib/core/state-storage.js +1 -0
  15. package/lib/enums/rate-limit-error-code.d.ts +26 -0
  16. package/lib/enums/rate-limit-error-code.js +1 -0
  17. package/lib/errors/custom.error.d.ts +6 -0
  18. package/lib/errors/custom.error.js +1 -0
  19. package/lib/errors/invalid-cost.error.d.ts +16 -0
  20. package/lib/errors/invalid-cost.error.js +1 -0
  21. package/lib/errors/rate-limit.error.d.ts +37 -0
  22. package/lib/errors/rate-limit.error.js +1 -0
  23. package/lib/errors/rate-limiter-destroyed.error.d.ts +7 -0
  24. package/lib/errors/rate-limiter-destroyed.error.js +1 -0
  25. package/lib/index.d.ts +12 -0
  26. package/lib/index.js +1 -0
  27. package/lib/interfaces/rate-limiter-options.d.ts +76 -0
  28. package/lib/interfaces/rate-limiter-options.js +1 -0
  29. package/lib/interfaces/rate-limiter-queue-options.d.ts +42 -0
  30. package/lib/interfaces/rate-limiter-queue-options.js +1 -0
  31. package/lib/interfaces/rate-limiter-run-options.d.ts +52 -0
  32. package/lib/interfaces/rate-limiter-run-options.js +1 -0
  33. package/lib/limiters/abstract-rate-limiter.d.ts +44 -0
  34. package/lib/limiters/abstract-rate-limiter.js +1 -0
  35. package/lib/limiters/composite.policy.d.ts +15 -0
  36. package/lib/limiters/composite.policy.js +1 -0
  37. package/lib/limiters/fixed-window/fixed-window.limiter.d.ts +33 -0
  38. package/lib/limiters/fixed-window/fixed-window.limiter.js +1 -0
  39. package/lib/limiters/fixed-window/fixed-window.options.d.ts +27 -0
  40. package/lib/limiters/fixed-window/fixed-window.options.js +1 -0
  41. package/lib/limiters/fixed-window/fixed-window.policy.d.ts +19 -0
  42. package/lib/limiters/fixed-window/fixed-window.policy.js +1 -0
  43. package/lib/limiters/fixed-window/fixed-window.state.d.ts +11 -0
  44. package/lib/limiters/fixed-window/fixed-window.state.js +1 -0
  45. package/lib/limiters/fixed-window/fixed-window.status.d.ts +39 -0
  46. package/lib/limiters/fixed-window/fixed-window.status.js +1 -0
  47. package/lib/limiters/fixed-window/index.d.ts +5 -0
  48. package/lib/limiters/fixed-window/index.js +1 -0
  49. package/lib/limiters/generic-cell/generic-cell.limiter.d.ts +30 -0
  50. package/lib/limiters/generic-cell/generic-cell.limiter.js +1 -0
  51. package/lib/limiters/generic-cell/generic-cell.options.d.ts +22 -0
  52. package/lib/limiters/generic-cell/generic-cell.options.js +1 -0
  53. package/lib/limiters/generic-cell/generic-cell.policy.d.ts +18 -0
  54. package/lib/limiters/generic-cell/generic-cell.policy.js +1 -0
  55. package/lib/limiters/generic-cell/generic-cell.state.d.ts +9 -0
  56. package/lib/limiters/generic-cell/generic-cell.state.js +1 -0
  57. package/lib/limiters/generic-cell/generic-cell.status.d.ts +49 -0
  58. package/lib/limiters/generic-cell/generic-cell.status.js +1 -0
  59. package/lib/limiters/generic-cell/index.d.ts +5 -0
  60. package/lib/limiters/generic-cell/index.js +1 -0
  61. package/lib/limiters/http-response-based/http-limit-info.extractor.d.ts +16 -0
  62. package/lib/limiters/http-response-based/http-limit-info.extractor.js +1 -0
  63. package/lib/limiters/http-response-based/http-limit.info.d.ts +39 -0
  64. package/lib/limiters/http-response-based/http-limit.info.js +1 -0
  65. package/lib/limiters/http-response-based/http-response-based-limiter.options.d.ts +17 -0
  66. package/lib/limiters/http-response-based/http-response-based-limiter.options.js +1 -0
  67. package/lib/limiters/http-response-based/http-response-based-limiter.state.d.ts +14 -0
  68. package/lib/limiters/http-response-based/http-response-based-limiter.state.js +1 -0
  69. package/lib/limiters/http-response-based/http-response-based-limiter.status.d.ts +70 -0
  70. package/lib/limiters/http-response-based/http-response-based-limiter.status.js +1 -0
  71. package/lib/limiters/http-response-based/http-response-based.limiter.d.ts +56 -0
  72. package/lib/limiters/http-response-based/http-response-based.limiter.js +13 -6
  73. package/lib/limiters/http-response-based/index.d.ts +7 -0
  74. package/lib/limiters/http-response-based/index.js +1 -0
  75. package/lib/limiters/leaky-bucket/index.d.ts +5 -0
  76. package/lib/limiters/leaky-bucket/index.js +1 -0
  77. package/lib/limiters/leaky-bucket/leaky-bucket.limiter.d.ts +30 -0
  78. package/lib/limiters/leaky-bucket/leaky-bucket.limiter.js +1 -0
  79. package/lib/limiters/leaky-bucket/leaky-bucket.options.d.ts +22 -0
  80. package/lib/limiters/leaky-bucket/leaky-bucket.options.js +1 -0
  81. package/lib/limiters/leaky-bucket/leaky-bucket.policy.d.ts +19 -0
  82. package/lib/limiters/leaky-bucket/leaky-bucket.policy.js +1 -0
  83. package/lib/limiters/leaky-bucket/leaky-bucket.state.d.ts +10 -0
  84. package/lib/limiters/leaky-bucket/leaky-bucket.state.js +1 -0
  85. package/lib/limiters/leaky-bucket/leaky-bucket.status.d.ts +31 -0
  86. package/lib/limiters/leaky-bucket/leaky-bucket.status.js +1 -0
  87. package/lib/limiters/sliding-window-counter/index.d.ts +5 -0
  88. package/lib/limiters/sliding-window-counter/index.js +1 -0
  89. package/lib/limiters/sliding-window-counter/sliding-window-counter.limiter.d.ts +28 -0
  90. package/lib/limiters/sliding-window-counter/sliding-window-counter.limiter.js +1 -0
  91. package/lib/limiters/sliding-window-counter/sliding-window-counter.options.d.ts +16 -0
  92. package/lib/limiters/sliding-window-counter/sliding-window-counter.options.js +1 -0
  93. package/lib/limiters/sliding-window-counter/sliding-window-counter.policy.d.ts +18 -0
  94. package/lib/limiters/sliding-window-counter/sliding-window-counter.policy.js +1 -0
  95. package/lib/limiters/sliding-window-counter/sliding-window-counter.state.d.ts +11 -0
  96. package/lib/limiters/sliding-window-counter/sliding-window-counter.state.js +1 -0
  97. package/lib/limiters/sliding-window-counter/sliding-window-counter.status.d.ts +45 -0
  98. package/lib/limiters/sliding-window-counter/sliding-window-counter.status.js +1 -0
  99. package/lib/limiters/sliding-window-log/index.d.ts +5 -0
  100. package/lib/limiters/sliding-window-log/index.js +1 -0
  101. package/lib/limiters/sliding-window-log/sliding-window-log.limiter.d.ts +27 -0
  102. package/lib/limiters/sliding-window-log/sliding-window-log.limiter.js +1 -0
  103. package/lib/limiters/sliding-window-log/sliding-window-log.options.d.ts +16 -0
  104. package/lib/limiters/sliding-window-log/sliding-window-log.options.js +1 -0
  105. package/lib/limiters/sliding-window-log/sliding-window-log.policy.d.ts +18 -0
  106. package/lib/limiters/sliding-window-log/sliding-window-log.policy.js +1 -0
  107. package/lib/limiters/sliding-window-log/sliding-window-log.state.d.ts +18 -0
  108. package/lib/limiters/sliding-window-log/sliding-window-log.state.js +1 -0
  109. package/lib/limiters/sliding-window-log/sliding-window-log.status.d.ts +39 -0
  110. package/lib/limiters/sliding-window-log/sliding-window-log.status.js +1 -0
  111. package/lib/limiters/token-bucket/index.d.ts +5 -0
  112. package/lib/limiters/token-bucket/index.js +1 -0
  113. package/lib/limiters/token-bucket/token-bucket.limiter.d.ts +30 -0
  114. package/lib/limiters/token-bucket/token-bucket.limiter.js +1 -0
  115. package/lib/limiters/token-bucket/token-bucket.options.d.ts +16 -0
  116. package/lib/limiters/token-bucket/token-bucket.options.js +1 -0
  117. package/lib/limiters/token-bucket/token-bucket.policy.d.ts +19 -0
  118. package/lib/limiters/token-bucket/token-bucket.policy.js +1 -0
  119. package/lib/limiters/token-bucket/token-bucket.state.d.ts +11 -0
  120. package/lib/limiters/token-bucket/token-bucket.state.js +1 -0
  121. package/lib/limiters/token-bucket/token-bucket.status.d.ts +31 -0
  122. package/lib/limiters/token-bucket/token-bucket.status.js +1 -0
  123. package/lib/runtime/default-clock.d.ts +4 -0
  124. package/lib/runtime/default-clock.js +1 -0
  125. package/lib/runtime/execution-tickets.d.ts +12 -0
  126. package/lib/runtime/execution-tickets.js +1 -0
  127. package/lib/runtime/in-memory-state-store.d.ts +19 -0
  128. package/lib/runtime/in-memory-state-store.js +1 -0
  129. package/lib/runtime/rate-limiter.executor.d.ts +47 -0
  130. package/lib/runtime/rate-limiter.executor.js +1 -0
  131. package/lib/runtime/semaphore.d.ts +9 -0
  132. package/lib/runtime/semaphore.js +1 -0
  133. package/lib/runtime/task.d.ts +41 -0
  134. package/lib/runtime/task.js +1 -0
  135. package/lib/types/limit-behavior.d.ts +9 -0
  136. package/lib/types/limit-behavior.js +1 -0
  137. package/lib/utils/generate-random-string.d.ts +3 -0
  138. package/lib/utils/generate-random-string.js +1 -0
  139. package/lib/utils/promise-with-resolvers.d.ts +9 -0
  140. package/lib/utils/promise-with-resolvers.js +1 -0
  141. package/lib/utils/sanitize-error.d.ts +3 -0
  142. package/lib/utils/sanitize-error.js +1 -0
  143. package/lib/utils/sanitize-priority.d.ts +4 -0
  144. package/lib/utils/sanitize-priority.js +1 -0
  145. package/lib/utils/validate-cost.d.ts +3 -0
  146. package/lib/utils/validate-cost.js +1 -0
  147. package/package.json +3 -2
@@ -0,0 +1,27 @@
1
+ import { type FixedWindowState } from './fixed-window.state.js';
2
+ import { type RateLimiterOptions } from '../../interfaces/rate-limiter-options.js';
3
+ /**
4
+ * Fixed Window limit options.
5
+ */
6
+ export interface FixedWindowLimitOptions {
7
+ /**
8
+ * Maximum number of requests allowed within the time window.
9
+ */
10
+ limit: number;
11
+ /**
12
+ * Duration of the time window in milliseconds.
13
+ */
14
+ windowMs: number;
15
+ }
16
+ /**
17
+ * Options for the Fixed Window rate limiter.
18
+ */
19
+ export interface FixedWindowOptions extends RateLimiterOptions<FixedWindowState[]> {
20
+ /**
21
+ * Options time window.
22
+ *
23
+ * Can be a single object or an array of objects for composite time windows.
24
+ */
25
+ limitOptions: FixedWindowLimitOptions | FixedWindowLimitOptions[];
26
+ }
27
+ //# sourceMappingURL=fixed-window.options.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=fixed-window.options.js.map
@@ -0,0 +1,19 @@
1
+ import { type FixedWindowState } from './fixed-window.state.js';
2
+ import { type FixedWindowStatus } from './fixed-window.status.js';
3
+ import { type RateLimitPolicy, type RateLimitPolicyResult } from '../../core/rate-limit-policy.js';
4
+ /** @internal */
5
+ export declare class FixedWindowPolicy implements RateLimitPolicy<FixedWindowState, FixedWindowStatus> {
6
+ private readonly _limit;
7
+ private readonly _windowMs;
8
+ private readonly _maxReserved;
9
+ constructor(_limit: number, _windowMs: number, _maxReserved?: number);
10
+ get limit(): number;
11
+ get windowMs(): number;
12
+ getInitialState(): FixedWindowState;
13
+ getStatus(state: FixedWindowState, now: number): FixedWindowStatus;
14
+ evaluate(state: FixedWindowState, now: number, cost: number, shouldReserve?: boolean): RateLimitPolicyResult<FixedWindowState>;
15
+ revert(state: FixedWindowState, cost: number, now: number): FixedWindowState;
16
+ private _deny;
17
+ private _syncState;
18
+ }
19
+ //# sourceMappingURL=fixed-window.policy.d.ts.map
@@ -118,3 +118,4 @@ export class FixedWindowPolicy {
118
118
  return { windowStart: currentWindowStart, used, reserved };
119
119
  }
120
120
  }
121
+ //# sourceMappingURL=fixed-window.policy.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Fixed Window rate limiter state.
3
+ *
4
+ * When using a distributed state store, make sure it properly serializes and deserializes the state.
5
+ */
6
+ export interface FixedWindowState {
7
+ windowStart: number;
8
+ used: number;
9
+ reserved: number;
10
+ }
11
+ //# sourceMappingURL=fixed-window.state.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=fixed-window.state.js.map
@@ -0,0 +1,39 @@
1
+ import { type RateLimiterStatus } from '../../core/rate-limiter-status.js';
2
+ /**
3
+ * The status of the Fixed Window Limiter.
4
+ */
5
+ export interface FixedWindowStatus extends RateLimiterStatus {
6
+ /**
7
+ * The start of the current window.
8
+ */
9
+ readonly windowStart: number;
10
+ /**
11
+ * The end of the current window.
12
+ */
13
+ readonly windowEnd: number;
14
+ /**
15
+ * The maximum number of tokens can be used in the window.
16
+ */
17
+ readonly limit: number;
18
+ /**
19
+ * The number of tokens that have been used in the current window.
20
+ */
21
+ readonly used: number;
22
+ /**
23
+ * The number of tokens that are reserved for future windows.
24
+ */
25
+ readonly reserved: number;
26
+ /**
27
+ * The number of tokens that can be used in the current window.
28
+ */
29
+ readonly remaining: number;
30
+ /**
31
+ * The timestamp (in milliseconds) when the next token will be available for use.
32
+ */
33
+ readonly nextAvailableAt: number;
34
+ /**
35
+ * The timestamp (in milliseconds) when the limit will be reset (all tokens will be available for use again).
36
+ */
37
+ readonly resetAt: number;
38
+ }
39
+ //# sourceMappingURL=fixed-window.status.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=fixed-window.status.js.map
@@ -0,0 +1,5 @@
1
+ export type { FixedWindowState } from './fixed-window.state.js';
2
+ export type { FixedWindowStatus } from './fixed-window.status.js';
3
+ export type { FixedWindowLimitOptions, FixedWindowOptions } from './fixed-window.options.js';
4
+ export { FixedWindowLimiter } from './fixed-window.limiter.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1,2 @@
1
1
  export { FixedWindowLimiter } from './fixed-window.limiter.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,30 @@
1
+ import { GenericCellPolicy } from './generic-cell.policy.js';
2
+ import { AbstractRateLimiter, type ExecutionContext } from '../abstract-rate-limiter.js';
3
+ import { type GenericCellOptions } from './generic-cell.options.js';
4
+ import { type GenericCellState } from './generic-cell.state.js';
5
+ import { type GenericCellStatus } from './generic-cell.status.js';
6
+ /**
7
+ * Generic Cell (GCRA) rate limiter.
8
+ *
9
+ * Designed primarily for client-side use to respect third-party limits or protect resources.
10
+ * While this can be used as a server-side limiter with custom distributed storage
11
+ * (e.g., Redis), it is best-effort and not recommended due to high network round-trip latency.
12
+ *
13
+ * Key features:
14
+ * - **Queueing & overflow** - optionally enqueues excess requests up to a maximum allowed overflow capacity
15
+ * - **Concurrency** - limits how many requests can be executed simultaneously
16
+ * - **Priority** - supports task priorities (with fairness and custom policy) to execute critical requests first
17
+ * - **Cancellation** - supports `AbortSignal` to safely remove pending requests from the queue
18
+ * - **Expiration** - automatically drops queued requests that wait longer than the allowed `maxWaitMs`
19
+ * - **Auto-rollback** - reverts spent quota if an enqueued task is canceled or expired
20
+ */
21
+ export declare class GenericCellLimiter extends AbstractRateLimiter<GenericCellState, GenericCellStatus> {
22
+ private readonly _defaultLimitBehaviour;
23
+ private readonly _defaultMaxWaitMs;
24
+ protected readonly _policy: GenericCellPolicy;
25
+ constructor(options: GenericCellOptions);
26
+ protected _runInternal<T>(fn: () => T | Promise<T>, ctx: ExecutionContext): Promise<T>;
27
+ protected _getDebugStateString(state: GenericCellState): string;
28
+ private _printSuccessDebug;
29
+ }
30
+ //# sourceMappingURL=generic-cell.limiter.d.ts.map
@@ -71,3 +71,4 @@ export class GenericCellLimiter extends AbstractRateLimiter {
71
71
  }
72
72
  }
73
73
  }
74
+ //# sourceMappingURL=generic-cell.limiter.js.map
@@ -0,0 +1,22 @@
1
+ import { type GenericCellState } from './generic-cell.state.js';
2
+ import { type RateLimiterOptions } from '../../interfaces/rate-limiter-options.js';
3
+ /**
4
+ * Options for the Generic Cell Rate Algorithm (GCRA) limiter.
5
+ */
6
+ export interface GenericCellOptions extends RateLimiterOptions<GenericCellState> {
7
+ /**
8
+ * The minimum interval between requests (in milliseconds).
9
+ *
10
+ * This defines the emission interval.
11
+ * For example, if you want to allow 10 requests per second, set this to 100ms (1000ms / 10).
12
+ */
13
+ intervalMs: number;
14
+ /**
15
+ * The maximum burst size.
16
+ *
17
+ * This defines how many requests can be made immediately in quick succession before rate limiting kicks in.
18
+ * The burst capacity allows temporary spikes in traffic.
19
+ */
20
+ burst: number;
21
+ }
22
+ //# sourceMappingURL=generic-cell.options.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=generic-cell.options.js.map
@@ -0,0 +1,18 @@
1
+ import { type GenericCellState } from './generic-cell.state.js';
2
+ import { type GenericCellStatus } from './generic-cell.status.js';
3
+ import { type RateLimitPolicy, type RateLimitPolicyResult } from '../../core/rate-limit-policy.js';
4
+ /** @internal */
5
+ export declare class GenericCellPolicy implements RateLimitPolicy<GenericCellState, GenericCellStatus> {
6
+ private readonly _intervalMs;
7
+ private readonly _burst;
8
+ private readonly _maxDelayMs;
9
+ constructor(_intervalMs: number, _burst: number, _maxDelayMs?: number);
10
+ get burst(): number;
11
+ get intervalMs(): number;
12
+ getInitialState(): GenericCellState;
13
+ getStatus(state: GenericCellState, now: number): GenericCellStatus;
14
+ evaluate(state: GenericCellState, now: number, cost: number, shouldReserve?: boolean): RateLimitPolicyResult<GenericCellState>;
15
+ revert(state: GenericCellState, cost: number): GenericCellState;
16
+ private _deny;
17
+ }
18
+ //# sourceMappingURL=generic-cell.policy.d.ts.map
@@ -84,3 +84,4 @@ export class GenericCellPolicy {
84
84
  };
85
85
  }
86
86
  }
87
+ //# sourceMappingURL=generic-cell.policy.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generic Cell rate limiter state.
3
+ *
4
+ * When using a distributed state store, make sure it properly serializes and deserializes the state.
5
+ */
6
+ export interface GenericCellState {
7
+ tat: number;
8
+ }
9
+ //# sourceMappingURL=generic-cell.state.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=generic-cell.state.js.map
@@ -0,0 +1,49 @@
1
+ import { type RateLimiterStatus } from '../../core/rate-limiter-status.js';
2
+ /**
3
+ * The status of the Generic Cell rate limiter.
4
+ */
5
+ export interface GenericCellStatus extends RateLimiterStatus {
6
+ /**
7
+ * The minimum interval between tokens (in milliseconds).
8
+ *
9
+ * It represents the emission interval - the time period between
10
+ * successive token emissions at the steady-state rate.
11
+ */
12
+ readonly intervalMs: number;
13
+ /**
14
+ * The maximum burst size (maximum number of tokens that can be accumulated).
15
+ *
16
+ * It represents the burst capacity - the maximum number of requests
17
+ * that can be made instantaneously when the bucket is full.
18
+ */
19
+ readonly burst: number;
20
+ /**
21
+ * Theoretical Arrival Time (TAT) - the virtual time when the bucket will be empty.
22
+ *
23
+ * TAT represents the earliest time at which a future request could be allowed.
24
+ *
25
+ * Value is in milliseconds.
26
+ */
27
+ readonly tat: number;
28
+ /**
29
+ * The number of tokens that can be used immediately.
30
+ *
31
+ * Calculated as the time allowance available between now and TAT, divided by
32
+ * the emission interval.
33
+ */
34
+ readonly remaining: number;
35
+ /**
36
+ * The timestamp (in milliseconds) when the next token will be available for use.
37
+ *
38
+ * This is the earliest time when a request can be accepted if no tokens are currently available.
39
+ */
40
+ readonly nextAvailableAt: number;
41
+ /**
42
+ * The timestamp when all tokens will be available for use again.
43
+ *
44
+ * It is when the TAT returns to the current time, meaning the bucket has fully recovered to its
45
+ * maximum burst capacity.
46
+ */
47
+ readonly resetAt: number;
48
+ }
49
+ //# sourceMappingURL=generic-cell.status.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=generic-cell.status.js.map
@@ -0,0 +1,5 @@
1
+ export type { GenericCellState } from './generic-cell.state.js';
2
+ export type { GenericCellStatus } from './generic-cell.status.js';
3
+ export type { GenericCellOptions } from './generic-cell.options.js';
4
+ export { GenericCellLimiter } from './generic-cell.limiter.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1,2 @@
1
1
  export { GenericCellLimiter } from './generic-cell.limiter.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,16 @@
1
+ import { type HttpLimitInfo } from './http-limit.info.js';
2
+ /**
3
+ * A function that extracts limit information from response headers.
4
+ *
5
+ * @param res The response object, for example, native `Response` object from the `fetch` API.
6
+ * @param err The error object, if any.
7
+ * @param now The current timestamp in milliseconds gotten from the internal clock.
8
+ * If you need the current timestamp, prefer this value over `Date.now()`.
9
+ *
10
+ * @returns {@link HttpLimitInfo} or `null` if not possible to extract or no limit info.
11
+ *
12
+ * @template TResponse The type of the response object.
13
+ * @template TError The type of the error object.
14
+ */
15
+ export type HttpLimitInfoExtractor<TResponse, TError extends Error = Error> = (res: TResponse | null, err: TError | null, now: number) => HttpLimitInfo | null;
16
+ //# sourceMappingURL=http-limit-info.extractor.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=http-limit-info.extractor.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Rate limit information extracted from the HTTP response headers.
3
+ */
4
+ export interface HttpLimitInfo {
5
+ /**
6
+ * The maximum number of requests allowed within the time window.
7
+ *
8
+ * It usually corresponds to `RateLimit-Limit` or `X-RateLimit-Limit` headers.
9
+ */
10
+ limit: number;
11
+ /**
12
+ * The number of requests remaining in the current time window.
13
+ *
14
+ * It usually corresponds to `RateLimit-Remaining` or `X-RateLimit-Remaining` headers.
15
+ */
16
+ remaining: number;
17
+ /**
18
+ * The timestamp (in milliseconds) when the current time window resets.
19
+ *
20
+ * It usually corresponds to `RateLimit-Reset`, `X-RateLimit-Reset`, or `Retry-After` headers.
21
+ *
22
+ * **WARNING:** these headers can be either delta (usually in seconds) or UNIX epoche
23
+ * timestamp (usually in seconds) depending on the target API specs.
24
+ *
25
+ *The library expects a UNIX epoche timestamp in milliseconds. Refer to the API docs to
26
+ * determine the header format and properly convert it to UNIX epoche timestamp in milliseconds.
27
+ *
28
+ * For example,
29
+ * - delta in seconds: `Date.now() + delta * 1000`
30
+ * - UNIX timestamp in seconds: `timestamp * 1000`
31
+ *
32
+ */
33
+ resetAt?: number | null;
34
+ /**
35
+ * HTTP status code of the response.
36
+ */
37
+ statusCode: number;
38
+ }
39
+ //# sourceMappingURL=http-limit.info.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=http-limit.info.js.map
@@ -0,0 +1,17 @@
1
+ import { type HttpLimitInfoExtractor } from './http-limit-info.extractor.js';
2
+ import { type HttpResponseBasedLimiterState } from './http-response-based-limiter.state.js';
3
+ import { type RateLimiterOptions } from '../../interfaces/rate-limiter-options.js';
4
+ /**
5
+ * Options for the HTTP Response Based rate limiter.
6
+ */
7
+ export interface HttpResponseBasedLimiterOptions<TResponse> extends RateLimiterOptions<HttpResponseBasedLimiterState> {
8
+ /**
9
+ * Function that extracts limit information from the HTTP response.
10
+ */
11
+ limitInfoExtractor: HttpLimitInfoExtractor<TResponse>;
12
+ /**
13
+ * The fallback reset delay in milliseconds.
14
+ */
15
+ fallbackResetDelayMs?: number;
16
+ }
17
+ //# sourceMappingURL=http-response-based-limiter.options.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=http-response-based-limiter.options.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The state of the HTTP Response Based rate limiter.
3
+ *
4
+ * When using a distributed state store, make sure it properly serializes and deserializes the state.
5
+ */
6
+ export interface HttpResponseBasedLimiterState {
7
+ isProbing: boolean;
8
+ isUnlimited: boolean;
9
+ lastKnownLimit: number | null;
10
+ lastKnownRemaining: number | null;
11
+ lastKnownResetAt: number | null;
12
+ lastSyncedAt: number | null;
13
+ }
14
+ //# sourceMappingURL=http-response-based-limiter.state.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=http-response-based-limiter.state.js.map
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The status of the HTTP Response Based rate limiter.
3
+ *
4
+ * This interface represents rate limit information extracted from HTTP response headers,
5
+ * such as RateLimit headers (RFC 6585) or custom headers provided by APIs (X-RateLimit-*).
6
+ *
7
+ * @remarks
8
+ * The status is updated after each API response and reflects the server-side rate limit state.
9
+ * Can be useful to check how many requests remain before hitting the rate limit.
10
+ */
11
+ export interface HttpResponseBasedLimiterStatus {
12
+ /**
13
+ * Indicates whether the rate limiter is currently probing for the server's limit state.
14
+ *
15
+ * This is `true` when the rate limiter is waiting for the first response from the server
16
+ * to extract rate limit headers.
17
+ */
18
+ isProbing: boolean;
19
+ /**
20
+ * Indicates whether the rate limiter is in unlimited mode.
21
+ *
22
+ * This is `true` if a server did not send any rate limit headers.
23
+ *
24
+ * If this is `true`, the `lastKnownLimit`, `lastKnownRemaining`, and `lastKnownResetAt` values are `null`.
25
+ */
26
+ isUnlimited: boolean;
27
+ /**
28
+ * The number of requests remaining in the current rate limit window.
29
+ *
30
+ * @remarks
31
+ * This value is extracted from response headers such as `X-RateLimit-Remaining`
32
+ * or `RateLimit-Remaining`. It decrements with each request and resets when
33
+ * the time window expires.
34
+ *
35
+ * When this reaches 0, later requests may be delayed or rejected until the reset time.
36
+ */
37
+ lastKnownRemaining: number | null;
38
+ /**
39
+ * The maximum number of requests allowed in the current rate limit window.
40
+ *
41
+ * @remarks
42
+ * This value is extracted from response headers such as `X-RateLimit-Limit`
43
+ * or `RateLimit-Limit`. It represents the total quota allocated by the API
44
+ * and typically remains constant across requests within the same window.
45
+ */
46
+ lastKnownLimit: number | null;
47
+ /**
48
+ * The timestamp (in milliseconds since Unix epoch) when the rate limit window resets.
49
+ *
50
+ * `null` if the reset time is not known or not applicable.
51
+ *
52
+ * @remarks
53
+ * This value is extracted from response headers such as `X-RateLimit-Reset`
54
+ * or `RateLimit-Reset`. The exact semantics depend on the API specification:
55
+ *
56
+ * - **Full window reset**: When the entire rate limit quota is restored
57
+ * - **Next request availability**: When the next single request slot becomes available
58
+ * - **Sliding window**: When the oldest request in the window expires
59
+ *
60
+ * Always refer to your API's documentation to understand the reset behavior.
61
+ */
62
+ lastKnownResetAt: number | null;
63
+ /**
64
+ * The timestamp (in milliseconds since Unix epoch) when the status was last synced with the server.
65
+ *
66
+ * `null` if the status has never been synced.
67
+ */
68
+ lastSyncedAt: number | null;
69
+ }
70
+ //# sourceMappingURL=http-response-based-limiter.status.d.ts.map
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=http-response-based-limiter.status.js.map
@@ -0,0 +1,56 @@
1
+ import { type HttpResponseBasedLimiterOptions } from './http-response-based-limiter.options.js';
2
+ import { type HttpResponseBasedLimiterStatus } from './http-response-based-limiter.status.js';
3
+ import { type RateLimiter } from '../../core/rate-limiter.js';
4
+ import { type RateLimiterRunOptions } from '../../interfaces/rate-limiter-run-options.js';
5
+ /**
6
+ * The options for single request execution.
7
+ */
8
+ export type HttpHeadersLimiterRunOptions = Omit<RateLimiterRunOptions, 'cost'>;
9
+ /**
10
+ * HTTP Response Based rate limiter.
11
+ *
12
+ * Designed for outbound requests to safely respect dynamic third-party API limits.
13
+ *
14
+ * This limiter synchronizes its internal state by extracting rate limit headers directly from the HTTP responses.
15
+ *
16
+ * Key features:
17
+ * - **Dynamic synchronization** - updates local capacity and reset schedules based on actual server responses
18
+ * - **Probing** - prevents 429 floods by pausing queued requests while a single "probe" fetches the latest limits
19
+ * - **Queueing & overflow** - optionally enqueues excess requests up to a maximum allowed overflow capacity
20
+ * - **Concurrency** - limits how many requests can be executed simultaneously
21
+ * - **Priority** - supports task priorities (with fairness and custom policy) to execute critical requests first
22
+ * - **Cancellation** - supports `AbortSignal` to safely remove pending requests from the queue
23
+ * - **Expiration** - automatically drops queued requests that wait longer than the allowed `maxWaitMs`
24
+ */
25
+ export declare class HttpResponseBasedLimiter<TResponse> implements RateLimiter<HttpResponseBasedLimiterStatus> {
26
+ private readonly _logger;
27
+ private readonly _clock;
28
+ private readonly _store;
29
+ private readonly _executor;
30
+ private readonly _pendingSyncs;
31
+ private readonly _getStoreKey;
32
+ private readonly _generateId;
33
+ private readonly _extractLimitInfo;
34
+ private readonly _defaultLimitBehavior;
35
+ private readonly _maxWaitMs;
36
+ private readonly _fallbackResetDelayMs;
37
+ private _isDestroyed;
38
+ constructor(options: HttpResponseBasedLimiterOptions<TResponse>);
39
+ getStatus(key?: string): Promise<HttpResponseBasedLimiterStatus>;
40
+ run<T = TResponse>(fn: () => T | Promise<T>, options?: HttpHeadersLimiterRunOptions): Promise<T>;
41
+ clear(key?: string): Promise<void>;
42
+ destroy(): Promise<void>;
43
+ private get _shouldLogDebug();
44
+ private _executeSingleRequest;
45
+ private _waitForSync;
46
+ private _reserveLocalToken;
47
+ private _setupLocalProbeLock;
48
+ private _resolvePendingSync;
49
+ private _processLimitHeaders;
50
+ private _rollbackProbingState;
51
+ private _syncStateWithServer;
52
+ private _setUnlimited;
53
+ private _ensureCanExecute;
54
+ private _getDebugStateString;
55
+ }
56
+ //# sourceMappingURL=http-response-based.limiter.d.ts.map
@@ -9,6 +9,12 @@ import { RateLimiterExecutor } from '../../runtime/rate-limiter.executor.js';
9
9
  import { generateRandomString } from '../../utils/generate-random-string.js';
10
10
  import { sanitizeError } from '../../utils/sanitize-error.js';
11
11
  const TOO_MANY_REQUESTS_ERROR_CODE = 429;
12
+ var TokenReservationAction;
13
+ (function (TokenReservationAction) {
14
+ TokenReservationAction[TokenReservationAction["Probe"] = 1] = "Probe";
15
+ TokenReservationAction[TokenReservationAction["Follow"] = 2] = "Follow";
16
+ TokenReservationAction[TokenReservationAction["Wait"] = 3] = "Wait";
17
+ })(TokenReservationAction || (TokenReservationAction = {}));
12
18
  /**
13
19
  * HTTP Response Based rate limiter.
14
20
  *
@@ -148,10 +154,10 @@ export class HttpResponseBasedLimiter {
148
154
  await this._waitForSync(ctx);
149
155
  ctx.startedAt = this._clock.now();
150
156
  const action = await this._reserveLocalToken(ctx);
151
- if (action === 3 /* TokenReservationAction.Wait */) {
157
+ if (action === TokenReservationAction.Wait) {
152
158
  continue;
153
159
  }
154
- ctx.isProbing = action === 1 /* TokenReservationAction.Probe */;
160
+ ctx.isProbing = action === TokenReservationAction.Probe;
155
161
  break;
156
162
  }
157
163
  try {
@@ -207,7 +213,7 @@ export class HttpResponseBasedLimiter {
207
213
  try {
208
214
  const state = await this._store.get(ctx.key);
209
215
  if (state?.isUnlimited) {
210
- return 2 /* TokenReservationAction.Follow */;
216
+ return TokenReservationAction.Follow;
211
217
  }
212
218
  const lastKnownRemaining = state?.lastKnownRemaining ?? null;
213
219
  const lastKnownResetAt = state?.lastKnownResetAt ?? Infinity;
@@ -226,11 +232,11 @@ export class HttpResponseBasedLimiter {
226
232
  await this._store.set(ctx.key, probeState, this._fallbackResetDelayMs);
227
233
  this._shouldLogDebug &&
228
234
  this._logger.debug(`[PROBE] [id: ${ctx.id}, key: ${ctx.key}] - Probing API for limits - ${this._getDebugStateString(probeState)}`);
229
- return 1 /* TokenReservationAction.Probe */;
235
+ return TokenReservationAction.Probe;
230
236
  }
231
237
  if (state.isProbing) {
232
238
  if (hasLocalProbe) {
233
- return 3 /* TokenReservationAction.Wait */;
239
+ return TokenReservationAction.Wait;
234
240
  }
235
241
  throw new RateLimitError(RateLimitErrorCode.LimitExceeded, lastKnownResetAt);
236
242
  }
@@ -249,7 +255,7 @@ export class HttpResponseBasedLimiter {
249
255
  await this._store.set(ctx.key, newState, ttl);
250
256
  this._shouldLogDebug &&
251
257
  this._logger.debug(`[RSRV] [id: ${ctx.id}, key: ${ctx.key}] - Local state - ${this._getDebugStateString(newState)}`);
252
- return 2 /* TokenReservationAction.Follow */;
258
+ return TokenReservationAction.Follow;
253
259
  }
254
260
  finally {
255
261
  await this._store.releaseLock?.(ctx.key);
@@ -377,3 +383,4 @@ export class HttpResponseBasedLimiter {
377
383
  return `probe: ${state.isProbing}, unl: ${state.isUnlimited}, lim: ${state.lastKnownLimit}, rem: ${state.lastKnownRemaining}, rst: ${state.lastKnownResetAt}, sync: ${state.lastSyncedAt}`;
378
384
  }
379
385
  }
386
+ //# sourceMappingURL=http-response-based.limiter.js.map
@@ -0,0 +1,7 @@
1
+ export type { HttpResponseBasedLimiterState } from './http-response-based-limiter.state.js';
2
+ export type { HttpResponseBasedLimiterStatus } from './http-response-based-limiter.status.js';
3
+ export type { HttpResponseBasedLimiterOptions } from './http-response-based-limiter.options.js';
4
+ export type { HttpLimitInfo } from './http-limit.info.js';
5
+ export type { HttpLimitInfoExtractor } from './http-limit-info.extractor.js';
6
+ export { type HttpHeadersLimiterRunOptions, HttpResponseBasedLimiter } from './http-response-based.limiter.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1,2 @@
1
1
  export { HttpResponseBasedLimiter } from './http-response-based.limiter.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ export type { LeakyBucketState } from './leaky-bucket.state.js';
2
+ export type { LeakyBucketStatus } from './leaky-bucket.status.js';
3
+ export type { LeakyBucketOptions } from './leaky-bucket.options.js';
4
+ export { LeakyBucketLimiter } from './leaky-bucket.limiter.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1,2 @@
1
1
  export { LeakyBucketLimiter } from './leaky-bucket.limiter.js';
2
+ //# sourceMappingURL=index.js.map