@hazeljs/resilience 0.2.0-beta.41

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 (60) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +95 -0
  3. package/dist/__tests__/bulkhead-timeout.test.d.ts +2 -0
  4. package/dist/__tests__/bulkhead-timeout.test.d.ts.map +1 -0
  5. package/dist/__tests__/bulkhead-timeout.test.js +74 -0
  6. package/dist/__tests__/circuit-breaker.test.d.ts +2 -0
  7. package/dist/__tests__/circuit-breaker.test.d.ts.map +1 -0
  8. package/dist/__tests__/circuit-breaker.test.js +160 -0
  9. package/dist/__tests__/decorators.test.d.ts +2 -0
  10. package/dist/__tests__/decorators.test.d.ts.map +1 -0
  11. package/dist/__tests__/decorators.test.js +288 -0
  12. package/dist/__tests__/index.test.d.ts +2 -0
  13. package/dist/__tests__/index.test.d.ts.map +1 -0
  14. package/dist/__tests__/index.test.js +50 -0
  15. package/dist/__tests__/metrics.test.d.ts +2 -0
  16. package/dist/__tests__/metrics.test.d.ts.map +1 -0
  17. package/dist/__tests__/metrics.test.js +83 -0
  18. package/dist/__tests__/rate-limiter.test.d.ts +2 -0
  19. package/dist/__tests__/rate-limiter.test.d.ts.map +1 -0
  20. package/dist/__tests__/rate-limiter.test.js +143 -0
  21. package/dist/__tests__/retry-policy.test.d.ts +2 -0
  22. package/dist/__tests__/retry-policy.test.d.ts.map +1 -0
  23. package/dist/__tests__/retry-policy.test.js +84 -0
  24. package/dist/__tests__/sliding-window.test.d.ts +2 -0
  25. package/dist/__tests__/sliding-window.test.d.ts.map +1 -0
  26. package/dist/__tests__/sliding-window.test.js +93 -0
  27. package/dist/bulkhead/bulkhead.d.ts +34 -0
  28. package/dist/bulkhead/bulkhead.d.ts.map +1 -0
  29. package/dist/bulkhead/bulkhead.js +97 -0
  30. package/dist/circuit-breaker/circuit-breaker-registry.d.ts +38 -0
  31. package/dist/circuit-breaker/circuit-breaker-registry.d.ts.map +1 -0
  32. package/dist/circuit-breaker/circuit-breaker-registry.js +61 -0
  33. package/dist/circuit-breaker/circuit-breaker.d.ts +51 -0
  34. package/dist/circuit-breaker/circuit-breaker.d.ts.map +1 -0
  35. package/dist/circuit-breaker/circuit-breaker.js +182 -0
  36. package/dist/circuit-breaker/sliding-window.d.ts +49 -0
  37. package/dist/circuit-breaker/sliding-window.d.ts.map +1 -0
  38. package/dist/circuit-breaker/sliding-window.js +89 -0
  39. package/dist/decorators/index.d.ts +51 -0
  40. package/dist/decorators/index.d.ts.map +1 -0
  41. package/dist/decorators/index.js +133 -0
  42. package/dist/index.d.ts +18 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +55 -0
  45. package/dist/metrics/metrics-collector.d.ts +69 -0
  46. package/dist/metrics/metrics-collector.d.ts.map +1 -0
  47. package/dist/metrics/metrics-collector.js +180 -0
  48. package/dist/rate-limiter/rate-limiter.d.ts +72 -0
  49. package/dist/rate-limiter/rate-limiter.d.ts.map +1 -0
  50. package/dist/rate-limiter/rate-limiter.js +147 -0
  51. package/dist/retry/retry-policy.d.ts +19 -0
  52. package/dist/retry/retry-policy.d.ts.map +1 -0
  53. package/dist/retry/retry-policy.js +87 -0
  54. package/dist/timeout/timeout.d.ts +23 -0
  55. package/dist/timeout/timeout.d.ts.map +1 -0
  56. package/dist/timeout/timeout.js +55 -0
  57. package/dist/types/index.d.ts +135 -0
  58. package/dist/types/index.d.ts.map +1 -0
  59. package/dist/types/index.js +61 -0
  60. package/package.json +63 -0
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ /**
3
+ * Sliding Window implementations for Circuit Breaker
4
+ *
5
+ * Count-based: tracks the last N calls
6
+ * Time-based: tracks calls within a rolling time window
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TimeBasedSlidingWindow = exports.CountBasedSlidingWindow = void 0;
10
+ exports.createSlidingWindow = createSlidingWindow;
11
+ /**
12
+ * Count-based sliding window
13
+ * Tracks the last `size` calls regardless of time
14
+ */
15
+ class CountBasedSlidingWindow {
16
+ constructor(size) {
17
+ this.size = size;
18
+ this.entries = [];
19
+ }
20
+ record(success) {
21
+ this.entries.push(success);
22
+ if (this.entries.length > this.size) {
23
+ this.entries.shift();
24
+ }
25
+ }
26
+ getResult() {
27
+ const total = this.entries.length;
28
+ if (total === 0) {
29
+ return { totalCalls: 0, failureCount: 0, failureRate: 0 };
30
+ }
31
+ const failures = this.entries.filter((s) => !s).length;
32
+ return {
33
+ totalCalls: total,
34
+ failureCount: failures,
35
+ failureRate: (failures / total) * 100,
36
+ };
37
+ }
38
+ reset() {
39
+ this.entries = [];
40
+ }
41
+ }
42
+ exports.CountBasedSlidingWindow = CountBasedSlidingWindow;
43
+ /**
44
+ * Time-based sliding window
45
+ * Tracks calls within a rolling time window of `sizeMs` milliseconds
46
+ */
47
+ class TimeBasedSlidingWindow {
48
+ constructor(sizeMs) {
49
+ this.sizeMs = sizeMs;
50
+ this.entries = [];
51
+ }
52
+ record(success) {
53
+ this.entries.push({ timestamp: Date.now(), success });
54
+ this.evict();
55
+ }
56
+ getResult() {
57
+ this.evict();
58
+ const total = this.entries.length;
59
+ if (total === 0) {
60
+ return { totalCalls: 0, failureCount: 0, failureRate: 0 };
61
+ }
62
+ const failures = this.entries.filter((e) => !e.success).length;
63
+ return {
64
+ totalCalls: total,
65
+ failureCount: failures,
66
+ failureRate: (failures / total) * 100,
67
+ };
68
+ }
69
+ reset() {
70
+ this.entries = [];
71
+ }
72
+ evict() {
73
+ const cutoff = Date.now() - this.sizeMs;
74
+ let i = 0;
75
+ while (i < this.entries.length && this.entries[i].timestamp < cutoff) {
76
+ i++;
77
+ }
78
+ if (i > 0) {
79
+ this.entries = this.entries.slice(i);
80
+ }
81
+ }
82
+ }
83
+ exports.TimeBasedSlidingWindow = TimeBasedSlidingWindow;
84
+ /**
85
+ * Factory to create the appropriate sliding window
86
+ */
87
+ function createSlidingWindow(type, size) {
88
+ return type === 'count' ? new CountBasedSlidingWindow(size) : new TimeBasedSlidingWindow(size);
89
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Resilience Decorators
3
+ * Decorator-based API consistent with HazelJS philosophy.
4
+ *
5
+ * Decorators compose in the order they are declared (outermost first).
6
+ * Example:
7
+ * @CircuitBreaker(...) <-- outermost wrapper
8
+ * @Retry(...) <-- wraps the timeout
9
+ * @Timeout(5000) <-- wraps the bulkhead
10
+ * @Bulkhead(...) <-- innermost wrapper around the original fn
11
+ */
12
+ import 'reflect-metadata';
13
+ import { CircuitBreakerConfig, RetryConfig, BulkheadConfig, RateLimiterConfig } from '../types';
14
+ /**
15
+ * @CircuitBreaker decorator
16
+ * Wraps a method with circuit breaker protection.
17
+ */
18
+ export declare function CircuitBreaker(config?: Partial<CircuitBreakerConfig>): MethodDecorator;
19
+ /**
20
+ * @Retry decorator
21
+ * Wraps a method with retry logic.
22
+ */
23
+ export declare function Retry(config?: Partial<RetryConfig>): MethodDecorator;
24
+ /**
25
+ * @Timeout decorator
26
+ * Wraps a method with a timeout.
27
+ */
28
+ export declare function Timeout(durationOrConfig: number | {
29
+ duration: number;
30
+ message?: string;
31
+ }): MethodDecorator;
32
+ /**
33
+ * @Bulkhead decorator
34
+ * Limits concurrent executions of a method.
35
+ */
36
+ export declare function Bulkhead(config: BulkheadConfig): MethodDecorator;
37
+ /**
38
+ * @Fallback decorator
39
+ * Marks a method as the fallback for a specified primary method.
40
+ *
41
+ * Usage:
42
+ * @Fallback('processPayment')
43
+ * async processPaymentFallback(...) { }
44
+ */
45
+ export declare function Fallback(primaryMethodName: string): MethodDecorator;
46
+ /**
47
+ * @RateLimit decorator
48
+ * Rate limits a method.
49
+ */
50
+ export declare function RateLimit(config: RateLimiterConfig): MethodDecorator;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,kBAAkB,CAAC;AAM1B,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAKhG;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,eAAe,CAyCtF;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,eAAe,CAWpE;AAED;;;GAGG;AACH,wBAAgB,OAAO,CACrB,gBAAgB,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,eAAe,CAajB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAWhE;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,eAAe,CAMnE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAWpE"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /**
3
+ * Resilience Decorators
4
+ * Decorator-based API consistent with HazelJS philosophy.
5
+ *
6
+ * Decorators compose in the order they are declared (outermost first).
7
+ * Example:
8
+ * @CircuitBreaker(...) <-- outermost wrapper
9
+ * @Retry(...) <-- wraps the timeout
10
+ * @Timeout(5000) <-- wraps the bulkhead
11
+ * @Bulkhead(...) <-- innermost wrapper around the original fn
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.CircuitBreaker = CircuitBreaker;
15
+ exports.Retry = Retry;
16
+ exports.Timeout = Timeout;
17
+ exports.Bulkhead = Bulkhead;
18
+ exports.Fallback = Fallback;
19
+ exports.RateLimit = RateLimit;
20
+ require("reflect-metadata");
21
+ const circuit_breaker_registry_1 = require("../circuit-breaker/circuit-breaker-registry");
22
+ const retry_policy_1 = require("../retry/retry-policy");
23
+ const timeout_1 = require("../timeout/timeout");
24
+ const bulkhead_1 = require("../bulkhead/bulkhead");
25
+ const rate_limiter_1 = require("../rate-limiter/rate-limiter");
26
+ // Metadata keys
27
+ const FALLBACK_KEY = Symbol('resilience:fallback');
28
+ /**
29
+ * @CircuitBreaker decorator
30
+ * Wraps a method with circuit breaker protection.
31
+ */
32
+ function CircuitBreaker(config) {
33
+ return function (target, propertyKey, descriptor) {
34
+ const originalMethod = descriptor.value;
35
+ const breakerName = `${target.constructor.name}.${String(propertyKey)}`;
36
+ descriptor.value = async function (...args) {
37
+ const breaker = circuit_breaker_registry_1.CircuitBreakerRegistry.getOrCreate(breakerName, config);
38
+ try {
39
+ return await breaker.execute(() => originalMethod.apply(this, args));
40
+ }
41
+ catch (error) {
42
+ // If there's a fallback configured, try it
43
+ if (config?.fallback) {
44
+ const fallbackMethod = this[config.fallback];
45
+ if (typeof fallbackMethod === 'function') {
46
+ return fallbackMethod.apply(this, args);
47
+ }
48
+ }
49
+ // Check for decorator-based fallback
50
+ const fallbackName = Reflect.getMetadata(FALLBACK_KEY, target, propertyKey);
51
+ if (fallbackName) {
52
+ const fallbackMethod = this[fallbackName];
53
+ if (typeof fallbackMethod === 'function') {
54
+ return fallbackMethod.apply(this, args);
55
+ }
56
+ }
57
+ throw error;
58
+ }
59
+ };
60
+ return descriptor;
61
+ };
62
+ }
63
+ /**
64
+ * @Retry decorator
65
+ * Wraps a method with retry logic.
66
+ */
67
+ function Retry(config) {
68
+ return function (_target, _propertyKey, descriptor) {
69
+ const originalMethod = descriptor.value;
70
+ const retryPolicy = new retry_policy_1.RetryPolicy(config);
71
+ descriptor.value = async function (...args) {
72
+ return retryPolicy.execute(() => originalMethod.apply(this, args));
73
+ };
74
+ return descriptor;
75
+ };
76
+ }
77
+ /**
78
+ * @Timeout decorator
79
+ * Wraps a method with a timeout.
80
+ */
81
+ function Timeout(durationOrConfig) {
82
+ return function (_target, _propertyKey, descriptor) {
83
+ const originalMethod = descriptor.value;
84
+ const timeout = new timeout_1.Timeout(typeof durationOrConfig === 'number' ? durationOrConfig : durationOrConfig);
85
+ descriptor.value = async function (...args) {
86
+ return timeout.execute(() => originalMethod.apply(this, args));
87
+ };
88
+ return descriptor;
89
+ };
90
+ }
91
+ /**
92
+ * @Bulkhead decorator
93
+ * Limits concurrent executions of a method.
94
+ */
95
+ function Bulkhead(config) {
96
+ return function (_target, _propertyKey, descriptor) {
97
+ const originalMethod = descriptor.value;
98
+ const bulkhead = new bulkhead_1.Bulkhead(config);
99
+ descriptor.value = async function (...args) {
100
+ return bulkhead.execute(() => originalMethod.apply(this, args));
101
+ };
102
+ return descriptor;
103
+ };
104
+ }
105
+ /**
106
+ * @Fallback decorator
107
+ * Marks a method as the fallback for a specified primary method.
108
+ *
109
+ * Usage:
110
+ * @Fallback('processPayment')
111
+ * async processPaymentFallback(...) { }
112
+ */
113
+ function Fallback(primaryMethodName) {
114
+ return function (target, propertyKey, descriptor) {
115
+ // Store the fallback mapping on the primary method
116
+ Reflect.defineMetadata(FALLBACK_KEY, String(propertyKey), target, primaryMethodName);
117
+ return descriptor;
118
+ };
119
+ }
120
+ /**
121
+ * @RateLimit decorator
122
+ * Rate limits a method.
123
+ */
124
+ function RateLimit(config) {
125
+ return function (_target, _propertyKey, descriptor) {
126
+ const originalMethod = descriptor.value;
127
+ const limiter = new rate_limiter_1.RateLimiter(config);
128
+ descriptor.value = async function (...args) {
129
+ return limiter.execute(() => originalMethod.apply(this, args));
130
+ };
131
+ return descriptor;
132
+ };
133
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @hazeljs/resilience
3
+ * Fault-tolerance and resilience patterns for HazelJS
4
+ *
5
+ * Provides circuit breaker, retry, timeout, bulkhead, rate limiter,
6
+ * and metrics collection — all usable via decorators or programmatic API.
7
+ */
8
+ export { CircuitState, CircuitBreakerConfig, CircuitBreakerMetrics, CircuitBreakerError, SlidingWindowConfig, RetryConfig, BackoffStrategy, RetryExhaustedError, TimeoutConfig, TimeoutError, BulkheadConfig, BulkheadMetrics, BulkheadError, RateLimiterConfig, RateLimiterStrategy, RateLimitError, MetricsSnapshot, MetricsEntry, ResilienceError, } from './types';
9
+ export { CircuitBreaker } from './circuit-breaker/circuit-breaker';
10
+ export { CircuitBreakerRegistry } from './circuit-breaker/circuit-breaker-registry';
11
+ export { SlidingWindow, CountBasedSlidingWindow, TimeBasedSlidingWindow, createSlidingWindow, } from './circuit-breaker/sliding-window';
12
+ export { RetryPolicy } from './retry/retry-policy';
13
+ export { Timeout, withTimeout } from './timeout/timeout';
14
+ export { Bulkhead } from './bulkhead/bulkhead';
15
+ export { RateLimiter, TokenBucketLimiter, SlidingWindowLimiter } from './rate-limiter/rate-limiter';
16
+ export { MetricsCollector, MetricsRegistry } from './metrics/metrics-collector';
17
+ export { CircuitBreaker as WithCircuitBreaker, Retry as WithRetry, Timeout as WithTimeout, Bulkhead as WithBulkhead, Fallback, RateLimit as WithRateLimit, } from './decorators';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGpG,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAGhF,OAAO,EACL,cAAc,IAAI,kBAAkB,EACpC,KAAK,IAAI,SAAS,EAClB,OAAO,IAAI,WAAW,EACtB,QAAQ,IAAI,YAAY,EACxB,QAAQ,EACR,SAAS,IAAI,aAAa,GAC3B,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * @hazeljs/resilience
4
+ * Fault-tolerance and resilience patterns for HazelJS
5
+ *
6
+ * Provides circuit breaker, retry, timeout, bulkhead, rate limiter,
7
+ * and metrics collection — all usable via decorators or programmatic API.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.WithRateLimit = exports.Fallback = exports.WithBulkhead = exports.WithTimeout = exports.WithRetry = exports.WithCircuitBreaker = exports.MetricsRegistry = exports.MetricsCollector = exports.SlidingWindowLimiter = exports.TokenBucketLimiter = exports.RateLimiter = exports.Bulkhead = exports.withTimeout = exports.Timeout = exports.RetryPolicy = exports.createSlidingWindow = exports.TimeBasedSlidingWindow = exports.CountBasedSlidingWindow = exports.CircuitBreakerRegistry = exports.CircuitBreaker = exports.ResilienceError = exports.RateLimitError = exports.BulkheadError = exports.TimeoutError = exports.RetryExhaustedError = exports.CircuitBreakerError = exports.CircuitState = void 0;
11
+ // Types & Errors
12
+ var types_1 = require("./types");
13
+ Object.defineProperty(exports, "CircuitState", { enumerable: true, get: function () { return types_1.CircuitState; } });
14
+ Object.defineProperty(exports, "CircuitBreakerError", { enumerable: true, get: function () { return types_1.CircuitBreakerError; } });
15
+ Object.defineProperty(exports, "RetryExhaustedError", { enumerable: true, get: function () { return types_1.RetryExhaustedError; } });
16
+ Object.defineProperty(exports, "TimeoutError", { enumerable: true, get: function () { return types_1.TimeoutError; } });
17
+ Object.defineProperty(exports, "BulkheadError", { enumerable: true, get: function () { return types_1.BulkheadError; } });
18
+ Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return types_1.RateLimitError; } });
19
+ Object.defineProperty(exports, "ResilienceError", { enumerable: true, get: function () { return types_1.ResilienceError; } });
20
+ // Circuit Breaker
21
+ var circuit_breaker_1 = require("./circuit-breaker/circuit-breaker");
22
+ Object.defineProperty(exports, "CircuitBreaker", { enumerable: true, get: function () { return circuit_breaker_1.CircuitBreaker; } });
23
+ var circuit_breaker_registry_1 = require("./circuit-breaker/circuit-breaker-registry");
24
+ Object.defineProperty(exports, "CircuitBreakerRegistry", { enumerable: true, get: function () { return circuit_breaker_registry_1.CircuitBreakerRegistry; } });
25
+ var sliding_window_1 = require("./circuit-breaker/sliding-window");
26
+ Object.defineProperty(exports, "CountBasedSlidingWindow", { enumerable: true, get: function () { return sliding_window_1.CountBasedSlidingWindow; } });
27
+ Object.defineProperty(exports, "TimeBasedSlidingWindow", { enumerable: true, get: function () { return sliding_window_1.TimeBasedSlidingWindow; } });
28
+ Object.defineProperty(exports, "createSlidingWindow", { enumerable: true, get: function () { return sliding_window_1.createSlidingWindow; } });
29
+ // Retry
30
+ var retry_policy_1 = require("./retry/retry-policy");
31
+ Object.defineProperty(exports, "RetryPolicy", { enumerable: true, get: function () { return retry_policy_1.RetryPolicy; } });
32
+ // Timeout
33
+ var timeout_1 = require("./timeout/timeout");
34
+ Object.defineProperty(exports, "Timeout", { enumerable: true, get: function () { return timeout_1.Timeout; } });
35
+ Object.defineProperty(exports, "withTimeout", { enumerable: true, get: function () { return timeout_1.withTimeout; } });
36
+ // Bulkhead
37
+ var bulkhead_1 = require("./bulkhead/bulkhead");
38
+ Object.defineProperty(exports, "Bulkhead", { enumerable: true, get: function () { return bulkhead_1.Bulkhead; } });
39
+ // Rate Limiter
40
+ var rate_limiter_1 = require("./rate-limiter/rate-limiter");
41
+ Object.defineProperty(exports, "RateLimiter", { enumerable: true, get: function () { return rate_limiter_1.RateLimiter; } });
42
+ Object.defineProperty(exports, "TokenBucketLimiter", { enumerable: true, get: function () { return rate_limiter_1.TokenBucketLimiter; } });
43
+ Object.defineProperty(exports, "SlidingWindowLimiter", { enumerable: true, get: function () { return rate_limiter_1.SlidingWindowLimiter; } });
44
+ // Metrics
45
+ var metrics_collector_1 = require("./metrics/metrics-collector");
46
+ Object.defineProperty(exports, "MetricsCollector", { enumerable: true, get: function () { return metrics_collector_1.MetricsCollector; } });
47
+ Object.defineProperty(exports, "MetricsRegistry", { enumerable: true, get: function () { return metrics_collector_1.MetricsRegistry; } });
48
+ // Decorators (re-exported with decorator-friendly names)
49
+ var decorators_1 = require("./decorators");
50
+ Object.defineProperty(exports, "WithCircuitBreaker", { enumerable: true, get: function () { return decorators_1.CircuitBreaker; } });
51
+ Object.defineProperty(exports, "WithRetry", { enumerable: true, get: function () { return decorators_1.Retry; } });
52
+ Object.defineProperty(exports, "WithTimeout", { enumerable: true, get: function () { return decorators_1.Timeout; } });
53
+ Object.defineProperty(exports, "WithBulkhead", { enumerable: true, get: function () { return decorators_1.Bulkhead; } });
54
+ Object.defineProperty(exports, "Fallback", { enumerable: true, get: function () { return decorators_1.Fallback; } });
55
+ Object.defineProperty(exports, "WithRateLimit", { enumerable: true, get: function () { return decorators_1.RateLimit; } });
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Metrics Collector
3
+ * Tracks success/failure/latency per target. Used internally by circuit breakers
4
+ * and exposed to the gateway for canary deployment decisions.
5
+ */
6
+ import { MetricsSnapshot } from '../types';
7
+ export declare class MetricsCollector {
8
+ private entries;
9
+ private windowMs;
10
+ constructor(windowMs?: number);
11
+ /**
12
+ * Record a successful call
13
+ */
14
+ recordSuccess(duration: number): void;
15
+ /**
16
+ * Record a failed call
17
+ */
18
+ recordFailure(duration: number, error?: string): void;
19
+ /**
20
+ * Get a snapshot of current metrics within the sliding window
21
+ */
22
+ getSnapshot(): MetricsSnapshot;
23
+ /**
24
+ * Get the current failure rate as a percentage (0-100)
25
+ */
26
+ getFailureRate(): number;
27
+ /**
28
+ * Get the number of entries in the current window
29
+ */
30
+ getCallCount(): number;
31
+ /**
32
+ * Get failure count in the current window
33
+ */
34
+ getFailureCount(): number;
35
+ /**
36
+ * Get success count in the current window
37
+ */
38
+ getSuccessCount(): number;
39
+ /**
40
+ * Reset all metrics
41
+ */
42
+ reset(): void;
43
+ /**
44
+ * Set the window duration
45
+ */
46
+ setWindow(windowMs: number): void;
47
+ /**
48
+ * Evict entries outside the sliding window
49
+ */
50
+ private evict;
51
+ /**
52
+ * Calculate percentile from sorted array
53
+ */
54
+ private percentile;
55
+ }
56
+ /**
57
+ * Global registry of metrics collectors, keyed by name
58
+ */
59
+ export declare class MetricsRegistry {
60
+ private static collectors;
61
+ static getOrCreate(name: string, windowMs?: number): MetricsCollector;
62
+ static get(name: string): MetricsCollector | undefined;
63
+ static getAll(): Map<string, MetricsCollector>;
64
+ static remove(name: string): boolean;
65
+ static clear(): void;
66
+ static getSnapshot(name: string): MetricsSnapshot | undefined;
67
+ static getAllSnapshots(): Record<string, MetricsSnapshot>;
68
+ }
69
+ //# sourceMappingURL=metrics-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-collector.d.ts","sourceRoot":"","sources":["../../src/metrics/metrics-collector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAgB,eAAe,EAAE,MAAM,UAAU,CAAC;AAEzD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,GAAE,MAAe;IAIrC;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IASrC;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAUrD;;OAEG;IACH,WAAW,IAAI,eAAe;IAuC9B;;OAEG;IACH,cAAc,IAAI,MAAM;IAOxB;;OAEG;IACH,YAAY,IAAI,MAAM;IAKtB;;OAEG;IACH,eAAe,IAAI,MAAM;IAKzB;;OAEG;IACH,eAAe,IAAI,MAAM;IAKzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKjC;;OAEG;IACH,OAAO,CAAC,KAAK;IAYb;;OAEG;IACH,OAAO,CAAC,UAAU;CAKnB;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAuC;IAEhE,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB;IASrE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAItD,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAI9C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpC,MAAM,CAAC,KAAK,IAAI,IAAI;IAIpB,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI7D,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;CAO1D"}
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ /**
3
+ * Metrics Collector
4
+ * Tracks success/failure/latency per target. Used internally by circuit breakers
5
+ * and exposed to the gateway for canary deployment decisions.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.MetricsRegistry = exports.MetricsCollector = void 0;
9
+ class MetricsCollector {
10
+ constructor(windowMs = 60000) {
11
+ this.entries = [];
12
+ this.windowMs = windowMs;
13
+ }
14
+ /**
15
+ * Record a successful call
16
+ */
17
+ recordSuccess(duration) {
18
+ this.entries.push({
19
+ timestamp: Date.now(),
20
+ duration,
21
+ success: true,
22
+ });
23
+ this.evict();
24
+ }
25
+ /**
26
+ * Record a failed call
27
+ */
28
+ recordFailure(duration, error) {
29
+ this.entries.push({
30
+ timestamp: Date.now(),
31
+ duration,
32
+ success: false,
33
+ error,
34
+ });
35
+ this.evict();
36
+ }
37
+ /**
38
+ * Get a snapshot of current metrics within the sliding window
39
+ */
40
+ getSnapshot() {
41
+ this.evict();
42
+ const entries = this.entries;
43
+ const total = entries.length;
44
+ if (total === 0) {
45
+ return {
46
+ totalCalls: 0,
47
+ successCalls: 0,
48
+ failureCalls: 0,
49
+ failureRate: 0,
50
+ averageResponseTime: 0,
51
+ p50ResponseTime: 0,
52
+ p95ResponseTime: 0,
53
+ p99ResponseTime: 0,
54
+ minResponseTime: 0,
55
+ maxResponseTime: 0,
56
+ };
57
+ }
58
+ const successes = entries.filter((e) => e.success).length;
59
+ const failures = total - successes;
60
+ const durations = entries.map((e) => e.duration).sort((a, b) => a - b);
61
+ return {
62
+ totalCalls: total,
63
+ successCalls: successes,
64
+ failureCalls: failures,
65
+ failureRate: total > 0 ? (failures / total) * 100 : 0,
66
+ averageResponseTime: durations.reduce((a, b) => a + b, 0) / total,
67
+ p50ResponseTime: this.percentile(durations, 50),
68
+ p95ResponseTime: this.percentile(durations, 95),
69
+ p99ResponseTime: this.percentile(durations, 99),
70
+ minResponseTime: durations[0],
71
+ maxResponseTime: durations[durations.length - 1],
72
+ lastCallTime: entries[entries.length - 1]?.timestamp,
73
+ };
74
+ }
75
+ /**
76
+ * Get the current failure rate as a percentage (0-100)
77
+ */
78
+ getFailureRate() {
79
+ this.evict();
80
+ if (this.entries.length === 0)
81
+ return 0;
82
+ const failures = this.entries.filter((e) => !e.success).length;
83
+ return (failures / this.entries.length) * 100;
84
+ }
85
+ /**
86
+ * Get the number of entries in the current window
87
+ */
88
+ getCallCount() {
89
+ this.evict();
90
+ return this.entries.length;
91
+ }
92
+ /**
93
+ * Get failure count in the current window
94
+ */
95
+ getFailureCount() {
96
+ this.evict();
97
+ return this.entries.filter((e) => !e.success).length;
98
+ }
99
+ /**
100
+ * Get success count in the current window
101
+ */
102
+ getSuccessCount() {
103
+ this.evict();
104
+ return this.entries.filter((e) => e.success).length;
105
+ }
106
+ /**
107
+ * Reset all metrics
108
+ */
109
+ reset() {
110
+ this.entries = [];
111
+ }
112
+ /**
113
+ * Set the window duration
114
+ */
115
+ setWindow(windowMs) {
116
+ this.windowMs = windowMs;
117
+ this.evict();
118
+ }
119
+ /**
120
+ * Evict entries outside the sliding window
121
+ */
122
+ evict() {
123
+ const cutoff = Date.now() - this.windowMs;
124
+ // Find first entry within window using binary-ish scan
125
+ let i = 0;
126
+ while (i < this.entries.length && this.entries[i].timestamp < cutoff) {
127
+ i++;
128
+ }
129
+ if (i > 0) {
130
+ this.entries = this.entries.slice(i);
131
+ }
132
+ }
133
+ /**
134
+ * Calculate percentile from sorted array
135
+ */
136
+ percentile(sorted, p) {
137
+ if (sorted.length === 0)
138
+ return 0;
139
+ const index = Math.ceil((p / 100) * sorted.length) - 1;
140
+ return sorted[Math.max(0, index)];
141
+ }
142
+ }
143
+ exports.MetricsCollector = MetricsCollector;
144
+ /**
145
+ * Global registry of metrics collectors, keyed by name
146
+ */
147
+ class MetricsRegistry {
148
+ static getOrCreate(name, windowMs) {
149
+ let collector = this.collectors.get(name);
150
+ if (!collector) {
151
+ collector = new MetricsCollector(windowMs);
152
+ this.collectors.set(name, collector);
153
+ }
154
+ return collector;
155
+ }
156
+ static get(name) {
157
+ return this.collectors.get(name);
158
+ }
159
+ static getAll() {
160
+ return new Map(this.collectors);
161
+ }
162
+ static remove(name) {
163
+ return this.collectors.delete(name);
164
+ }
165
+ static clear() {
166
+ this.collectors.clear();
167
+ }
168
+ static getSnapshot(name) {
169
+ return this.collectors.get(name)?.getSnapshot();
170
+ }
171
+ static getAllSnapshots() {
172
+ const snapshots = {};
173
+ for (const [name, collector] of this.collectors) {
174
+ snapshots[name] = collector.getSnapshot();
175
+ }
176
+ return snapshots;
177
+ }
178
+ }
179
+ exports.MetricsRegistry = MetricsRegistry;
180
+ MetricsRegistry.collectors = new Map();
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Rate Limiter
3
+ * Token bucket and sliding window implementations for rate limiting.
4
+ */
5
+ import { RateLimiterConfig, RateLimiterStrategy } from '../types';
6
+ /**
7
+ * Token Bucket Rate Limiter
8
+ * Allows bursts up to the bucket capacity and refills at a steady rate.
9
+ */
10
+ export declare class TokenBucketLimiter {
11
+ private tokens;
12
+ private lastRefill;
13
+ private capacity;
14
+ private refillRate;
15
+ constructor(capacity: number, refillRatePerSecond: number);
16
+ /**
17
+ * Try to consume a token. Returns true if allowed.
18
+ */
19
+ tryAcquire(): boolean;
20
+ /**
21
+ * Get time in ms until the next token is available
22
+ */
23
+ getRetryAfterMs(): number;
24
+ private refill;
25
+ }
26
+ /**
27
+ * Sliding Window Counter Rate Limiter
28
+ * Tracks request counts in small sub-windows for more accurate rate limiting.
29
+ */
30
+ export declare class SlidingWindowLimiter {
31
+ private windows;
32
+ private max;
33
+ private windowMs;
34
+ private subWindowMs;
35
+ constructor(max: number, windowMs: number);
36
+ /**
37
+ * Try to record a request. Returns true if within limit.
38
+ */
39
+ tryAcquire(): boolean;
40
+ /**
41
+ * Get time in ms until a slot opens up
42
+ */
43
+ getRetryAfterMs(): number;
44
+ private getCurrentCount;
45
+ private getCurrentSubKey;
46
+ private evict;
47
+ }
48
+ /**
49
+ * Unified RateLimiter that wraps the configured strategy
50
+ */
51
+ export declare class RateLimiter {
52
+ private limiter;
53
+ private strategy;
54
+ constructor(config: RateLimiterConfig);
55
+ /**
56
+ * Execute a function within rate limit constraints
57
+ */
58
+ execute<T>(fn: () => Promise<T>): Promise<T>;
59
+ /**
60
+ * Try to acquire permission (consumes a token/slot)
61
+ */
62
+ tryAcquire(): boolean;
63
+ /**
64
+ * Get time in ms until the next request is allowed
65
+ */
66
+ getRetryAfterMs(): number;
67
+ /**
68
+ * Get the strategy in use
69
+ */
70
+ getStrategy(): RateLimiterStrategy;
71
+ }
72
+ //# sourceMappingURL=rate-limiter.d.ts.map