@dsai-io/tools 0.0.1 → 1.0.7
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/README.md +282 -30
- package/dist/cli/index.cjs +6271 -2233
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +4 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.js +6232 -2195
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.cjs +198 -61
- package/dist/config/index.cjs.map +1 -1
- package/dist/config/index.d.cts +490 -1759
- package/dist/config/index.d.ts +490 -1759
- package/dist/config/index.js +197 -61
- package/dist/config/index.js.map +1 -1
- package/dist/icons/index.cjs +1 -1
- package/dist/icons/index.cjs.map +1 -1
- package/dist/icons/index.d.cts +1 -1
- package/dist/icons/index.d.ts +1 -1
- package/dist/icons/index.js +1 -1
- package/dist/icons/index.js.map +1 -1
- package/dist/index.cjs +6733 -2888
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6774 -2963
- package/dist/index.js.map +1 -1
- package/dist/tokens/index.cjs +4457 -737
- package/dist/tokens/index.cjs.map +1 -1
- package/dist/tokens/index.d.cts +1258 -17
- package/dist/tokens/index.d.ts +1258 -17
- package/dist/tokens/index.js +4368 -683
- package/dist/tokens/index.js.map +1 -1
- package/dist/{types-Idj08nad.d.cts → types-DabOzcsj.d.cts} +236 -3
- package/dist/{types-Idj08nad.d.ts → types-DabOzcsj.d.ts} +236 -3
- package/dist/utils/circuit-breaker.cjs +173 -0
- package/dist/utils/circuit-breaker.cjs.map +1 -0
- package/dist/utils/circuit-breaker.d.cts +123 -0
- package/dist/utils/circuit-breaker.d.ts +123 -0
- package/dist/utils/circuit-breaker.js +169 -0
- package/dist/utils/circuit-breaker.js.map +1 -0
- package/package.json +10 -5
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* @dsai-io/tools - DSAi Design System Build Tools */
|
|
4
|
+
|
|
5
|
+
// src/utils/circuit-breaker.ts
|
|
6
|
+
var CircuitState = /* @__PURE__ */ ((CircuitState2) => {
|
|
7
|
+
CircuitState2["CLOSED"] = "CLOSED";
|
|
8
|
+
CircuitState2["OPEN"] = "OPEN";
|
|
9
|
+
CircuitState2["HALF_OPEN"] = "HALF_OPEN";
|
|
10
|
+
return CircuitState2;
|
|
11
|
+
})(CircuitState || {});
|
|
12
|
+
var CircuitBreakerOpenError = class extends Error {
|
|
13
|
+
constructor(circuitName, resetAt) {
|
|
14
|
+
super(`Circuit breaker "${circuitName}" is open. Will retry at ${resetAt.toISOString()}`);
|
|
15
|
+
this.circuitName = circuitName;
|
|
16
|
+
this.resetAt = resetAt;
|
|
17
|
+
this.name = "CircuitBreakerOpenError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var CircuitBreaker = class {
|
|
21
|
+
state = "CLOSED" /* CLOSED */;
|
|
22
|
+
failures = 0;
|
|
23
|
+
successes = 0;
|
|
24
|
+
totalCalls = 0;
|
|
25
|
+
openedAt;
|
|
26
|
+
resetAt;
|
|
27
|
+
lastError;
|
|
28
|
+
failureThreshold;
|
|
29
|
+
cooldownMs;
|
|
30
|
+
timeout;
|
|
31
|
+
name;
|
|
32
|
+
constructor(config = {}) {
|
|
33
|
+
this.failureThreshold = config.failureThreshold ?? 5;
|
|
34
|
+
this.cooldownMs = config.cooldownMs ?? 3e4;
|
|
35
|
+
this.timeout = config.timeout ?? 1e4;
|
|
36
|
+
this.name = config.name ?? "CircuitBreaker";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Execute a function with circuit breaker protection
|
|
40
|
+
*/
|
|
41
|
+
async execute(fn) {
|
|
42
|
+
this.totalCalls++;
|
|
43
|
+
if (this.state === "OPEN" /* OPEN */ && this.canAttemptReset()) {
|
|
44
|
+
this.state = "HALF_OPEN" /* HALF_OPEN */;
|
|
45
|
+
this.failures = 0;
|
|
46
|
+
}
|
|
47
|
+
if (this.state === "OPEN" /* OPEN */) {
|
|
48
|
+
if (!this.resetAt) {
|
|
49
|
+
throw new Error(`Circuit breaker "${this.name}" is open but has no reset time`);
|
|
50
|
+
}
|
|
51
|
+
throw new CircuitBreakerOpenError(this.name, this.resetAt);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const result = await this.executeWithTimeout(fn);
|
|
55
|
+
this.onSuccess();
|
|
56
|
+
return result;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
this.onFailure(error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Execute function with timeout
|
|
64
|
+
*/
|
|
65
|
+
async executeWithTimeout(fn) {
|
|
66
|
+
return Promise.race([
|
|
67
|
+
fn(),
|
|
68
|
+
new Promise((_, reject) => {
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
reject(new Error(`Circuit breaker timeout after ${this.timeout}ms`));
|
|
71
|
+
}, this.timeout);
|
|
72
|
+
})
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Handle successful execution
|
|
77
|
+
*/
|
|
78
|
+
onSuccess() {
|
|
79
|
+
this.successes++;
|
|
80
|
+
if (this.state === "HALF_OPEN" /* HALF_OPEN */) {
|
|
81
|
+
this.state = "CLOSED" /* CLOSED */;
|
|
82
|
+
this.failures = 0;
|
|
83
|
+
this.openedAt = void 0;
|
|
84
|
+
this.resetAt = void 0;
|
|
85
|
+
this.lastError = void 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Handle failed execution
|
|
90
|
+
*/
|
|
91
|
+
onFailure(error) {
|
|
92
|
+
this.failures++;
|
|
93
|
+
this.lastError = error instanceof Error ? error.message : String(error);
|
|
94
|
+
if (this.state === "HALF_OPEN" /* HALF_OPEN */) {
|
|
95
|
+
this.openCircuit();
|
|
96
|
+
} else if (this.failures >= this.failureThreshold) {
|
|
97
|
+
this.openCircuit();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Open the circuit
|
|
102
|
+
*/
|
|
103
|
+
openCircuit() {
|
|
104
|
+
this.state = "OPEN" /* OPEN */;
|
|
105
|
+
this.openedAt = /* @__PURE__ */ new Date();
|
|
106
|
+
this.resetAt = new Date(Date.now() + this.cooldownMs);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if circuit can attempt reset
|
|
110
|
+
*/
|
|
111
|
+
canAttemptReset() {
|
|
112
|
+
if (!this.resetAt) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return Date.now() >= this.resetAt.getTime();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get current circuit breaker state
|
|
119
|
+
*/
|
|
120
|
+
getState() {
|
|
121
|
+
return this.state;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get circuit breaker statistics
|
|
125
|
+
*/
|
|
126
|
+
getStats() {
|
|
127
|
+
return {
|
|
128
|
+
state: this.state,
|
|
129
|
+
failures: this.failures,
|
|
130
|
+
successes: this.successes,
|
|
131
|
+
totalCalls: this.totalCalls,
|
|
132
|
+
openedAt: this.openedAt,
|
|
133
|
+
resetAt: this.resetAt,
|
|
134
|
+
lastError: this.lastError
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Manually reset circuit breaker
|
|
139
|
+
*/
|
|
140
|
+
reset() {
|
|
141
|
+
this.state = "CLOSED" /* CLOSED */;
|
|
142
|
+
this.failures = 0;
|
|
143
|
+
this.successes = 0;
|
|
144
|
+
this.totalCalls = 0;
|
|
145
|
+
this.openedAt = void 0;
|
|
146
|
+
this.resetAt = void 0;
|
|
147
|
+
this.lastError = void 0;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Check if circuit is open
|
|
151
|
+
*/
|
|
152
|
+
isOpen() {
|
|
153
|
+
return this.state === "OPEN" /* OPEN */;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if circuit is closed
|
|
157
|
+
*/
|
|
158
|
+
isClosed() {
|
|
159
|
+
return this.state === "CLOSED" /* CLOSED */;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Check if circuit is half-open
|
|
163
|
+
*/
|
|
164
|
+
isHalfOpen() {
|
|
165
|
+
return this.state === "HALF_OPEN" /* HALF_OPEN */;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
exports.CircuitBreaker = CircuitBreaker;
|
|
170
|
+
exports.CircuitBreakerOpenError = CircuitBreakerOpenError;
|
|
171
|
+
exports.CircuitState = CircuitState;
|
|
172
|
+
//# sourceMappingURL=circuit-breaker.cjs.map
|
|
173
|
+
//# sourceMappingURL=circuit-breaker.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/circuit-breaker.ts"],"names":["CircuitState"],"mappings":"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","file":"circuit-breaker.cjs","sourcesContent":["/**\n * @fileoverview Circuit Breaker pattern implementation\n * Prevents cascade failures by tracking error rates and temporarily blocking requests\n */\n\n/**\n * Circuit breaker states\n */\nexport enum CircuitState {\n /** Normal operation - requests are allowed */\n CLOSED = 'CLOSED',\n /** Failing - all requests are rejected immediately */\n OPEN = 'OPEN',\n /** Testing recovery - limited requests are allowed */\n HALF_OPEN = 'HALF_OPEN',\n}\n\n/**\n * Circuit breaker configuration\n */\nexport interface CircuitBreakerConfig {\n /** Number of failures before opening circuit */\n failureThreshold?: number;\n /** Time in ms before attempting to close circuit */\n cooldownMs?: number;\n /** Request timeout in ms */\n timeout?: number;\n /** Name for logging */\n name?: string;\n}\n\n/**\n * Circuit breaker statistics\n */\nexport interface CircuitBreakerStats {\n /** Current state */\n state: CircuitState;\n /** Total failures */\n failures: number;\n /** Total successes */\n successes: number;\n /** Total calls */\n totalCalls: number;\n /** Time circuit opened (if open) */\n openedAt?: Date;\n /** Time circuit will attempt to close */\n resetAt?: Date;\n /** Last error */\n lastError?: string;\n}\n\n/**\n * Circuit breaker error thrown when circuit is open\n */\nexport class CircuitBreakerOpenError extends Error {\n constructor(\n public readonly circuitName: string,\n public readonly resetAt: Date\n ) {\n super(`Circuit breaker \"${circuitName}\" is open. Will retry at ${resetAt.toISOString()}`);\n this.name = 'CircuitBreakerOpenError';\n }\n}\n\n/**\n * Circuit breaker implementation\n * Tracks failures and opens circuit to prevent cascade failures\n */\nexport class CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failures = 0;\n private successes = 0;\n private totalCalls = 0;\n private openedAt?: Date;\n private resetAt?: Date;\n private lastError?: string;\n\n private readonly failureThreshold: number;\n private readonly cooldownMs: number;\n private readonly timeout: number;\n private readonly name: string;\n\n constructor(config: CircuitBreakerConfig = {}) {\n this.failureThreshold = config.failureThreshold ?? 5;\n this.cooldownMs = config.cooldownMs ?? 30000; // 30 seconds\n this.timeout = config.timeout ?? 10000; // 10 seconds\n this.name = config.name ?? 'CircuitBreaker';\n }\n\n /**\n * Execute a function with circuit breaker protection\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n this.totalCalls++;\n\n // Check if circuit should transition from OPEN to HALF_OPEN\n if (this.state === CircuitState.OPEN && this.canAttemptReset()) {\n this.state = CircuitState.HALF_OPEN;\n this.failures = 0; // Reset failure count for half-open state\n }\n\n // Reject immediately if circuit is open\n if (this.state === CircuitState.OPEN) {\n if (!this.resetAt) {\n throw new Error(`Circuit breaker \"${this.name}\" is open but has no reset time`);\n }\n throw new CircuitBreakerOpenError(this.name, this.resetAt);\n }\n\n try {\n // Execute with timeout\n const result = await this.executeWithTimeout(fn);\n\n // Record success\n this.onSuccess();\n\n return result;\n } catch (error) {\n // Record failure\n this.onFailure(error);\n throw error;\n }\n }\n\n /**\n * Execute function with timeout\n */\n private async executeWithTimeout<T>(fn: () => Promise<T>): Promise<T> {\n return Promise.race([\n fn(),\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Circuit breaker timeout after ${this.timeout}ms`));\n }, this.timeout);\n }),\n ]);\n }\n\n /**\n * Handle successful execution\n */\n private onSuccess(): void {\n this.successes++;\n\n if (this.state === CircuitState.HALF_OPEN) {\n // Successful call in HALF_OPEN state closes the circuit\n this.state = CircuitState.CLOSED;\n this.failures = 0;\n this.openedAt = undefined;\n this.resetAt = undefined;\n this.lastError = undefined;\n }\n }\n\n /**\n * Handle failed execution\n */\n private onFailure(error: unknown): void {\n this.failures++;\n this.lastError = error instanceof Error ? error.message : String(error);\n\n if (this.state === CircuitState.HALF_OPEN) {\n // Failure in HALF_OPEN state immediately reopens circuit\n this.openCircuit();\n } else if (this.failures >= this.failureThreshold) {\n // Threshold reached, open circuit\n this.openCircuit();\n }\n }\n\n /**\n * Open the circuit\n */\n private openCircuit(): void {\n this.state = CircuitState.OPEN;\n this.openedAt = new Date();\n this.resetAt = new Date(Date.now() + this.cooldownMs);\n }\n\n /**\n * Check if circuit can attempt reset\n */\n private canAttemptReset(): boolean {\n if (!this.resetAt) {\n return false;\n }\n return Date.now() >= this.resetAt.getTime();\n }\n\n /**\n * Get current circuit breaker state\n */\n getState(): CircuitState {\n return this.state;\n }\n\n /**\n * Get circuit breaker statistics\n */\n getStats(): CircuitBreakerStats {\n return {\n state: this.state,\n failures: this.failures,\n successes: this.successes,\n totalCalls: this.totalCalls,\n openedAt: this.openedAt,\n resetAt: this.resetAt,\n lastError: this.lastError,\n };\n }\n\n /**\n * Manually reset circuit breaker\n */\n reset(): void {\n this.state = CircuitState.CLOSED;\n this.failures = 0;\n this.successes = 0;\n this.totalCalls = 0;\n this.openedAt = undefined;\n this.resetAt = undefined;\n this.lastError = undefined;\n }\n\n /**\n * Check if circuit is open\n */\n isOpen(): boolean {\n return this.state === CircuitState.OPEN;\n }\n\n /**\n * Check if circuit is closed\n */\n isClosed(): boolean {\n return this.state === CircuitState.CLOSED;\n }\n\n /**\n * Check if circuit is half-open\n */\n isHalfOpen(): boolean {\n return this.state === CircuitState.HALF_OPEN;\n }\n}\n"]}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Circuit Breaker pattern implementation
|
|
3
|
+
* Prevents cascade failures by tracking error rates and temporarily blocking requests
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Circuit breaker states
|
|
7
|
+
*/
|
|
8
|
+
declare enum CircuitState {
|
|
9
|
+
/** Normal operation - requests are allowed */
|
|
10
|
+
CLOSED = "CLOSED",
|
|
11
|
+
/** Failing - all requests are rejected immediately */
|
|
12
|
+
OPEN = "OPEN",
|
|
13
|
+
/** Testing recovery - limited requests are allowed */
|
|
14
|
+
HALF_OPEN = "HALF_OPEN"
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Circuit breaker configuration
|
|
18
|
+
*/
|
|
19
|
+
interface CircuitBreakerConfig {
|
|
20
|
+
/** Number of failures before opening circuit */
|
|
21
|
+
failureThreshold?: number;
|
|
22
|
+
/** Time in ms before attempting to close circuit */
|
|
23
|
+
cooldownMs?: number;
|
|
24
|
+
/** Request timeout in ms */
|
|
25
|
+
timeout?: number;
|
|
26
|
+
/** Name for logging */
|
|
27
|
+
name?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Circuit breaker statistics
|
|
31
|
+
*/
|
|
32
|
+
interface CircuitBreakerStats {
|
|
33
|
+
/** Current state */
|
|
34
|
+
state: CircuitState;
|
|
35
|
+
/** Total failures */
|
|
36
|
+
failures: number;
|
|
37
|
+
/** Total successes */
|
|
38
|
+
successes: number;
|
|
39
|
+
/** Total calls */
|
|
40
|
+
totalCalls: number;
|
|
41
|
+
/** Time circuit opened (if open) */
|
|
42
|
+
openedAt?: Date;
|
|
43
|
+
/** Time circuit will attempt to close */
|
|
44
|
+
resetAt?: Date;
|
|
45
|
+
/** Last error */
|
|
46
|
+
lastError?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Circuit breaker error thrown when circuit is open
|
|
50
|
+
*/
|
|
51
|
+
declare class CircuitBreakerOpenError extends Error {
|
|
52
|
+
readonly circuitName: string;
|
|
53
|
+
readonly resetAt: Date;
|
|
54
|
+
constructor(circuitName: string, resetAt: Date);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Circuit breaker implementation
|
|
58
|
+
* Tracks failures and opens circuit to prevent cascade failures
|
|
59
|
+
*/
|
|
60
|
+
declare class CircuitBreaker {
|
|
61
|
+
private state;
|
|
62
|
+
private failures;
|
|
63
|
+
private successes;
|
|
64
|
+
private totalCalls;
|
|
65
|
+
private openedAt?;
|
|
66
|
+
private resetAt?;
|
|
67
|
+
private lastError?;
|
|
68
|
+
private readonly failureThreshold;
|
|
69
|
+
private readonly cooldownMs;
|
|
70
|
+
private readonly timeout;
|
|
71
|
+
private readonly name;
|
|
72
|
+
constructor(config?: CircuitBreakerConfig);
|
|
73
|
+
/**
|
|
74
|
+
* Execute a function with circuit breaker protection
|
|
75
|
+
*/
|
|
76
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Execute function with timeout
|
|
79
|
+
*/
|
|
80
|
+
private executeWithTimeout;
|
|
81
|
+
/**
|
|
82
|
+
* Handle successful execution
|
|
83
|
+
*/
|
|
84
|
+
private onSuccess;
|
|
85
|
+
/**
|
|
86
|
+
* Handle failed execution
|
|
87
|
+
*/
|
|
88
|
+
private onFailure;
|
|
89
|
+
/**
|
|
90
|
+
* Open the circuit
|
|
91
|
+
*/
|
|
92
|
+
private openCircuit;
|
|
93
|
+
/**
|
|
94
|
+
* Check if circuit can attempt reset
|
|
95
|
+
*/
|
|
96
|
+
private canAttemptReset;
|
|
97
|
+
/**
|
|
98
|
+
* Get current circuit breaker state
|
|
99
|
+
*/
|
|
100
|
+
getState(): CircuitState;
|
|
101
|
+
/**
|
|
102
|
+
* Get circuit breaker statistics
|
|
103
|
+
*/
|
|
104
|
+
getStats(): CircuitBreakerStats;
|
|
105
|
+
/**
|
|
106
|
+
* Manually reset circuit breaker
|
|
107
|
+
*/
|
|
108
|
+
reset(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Check if circuit is open
|
|
111
|
+
*/
|
|
112
|
+
isOpen(): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Check if circuit is closed
|
|
115
|
+
*/
|
|
116
|
+
isClosed(): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Check if circuit is half-open
|
|
119
|
+
*/
|
|
120
|
+
isHalfOpen(): boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { CircuitBreaker, type CircuitBreakerConfig, CircuitBreakerOpenError, type CircuitBreakerStats, CircuitState };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Circuit Breaker pattern implementation
|
|
3
|
+
* Prevents cascade failures by tracking error rates and temporarily blocking requests
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Circuit breaker states
|
|
7
|
+
*/
|
|
8
|
+
declare enum CircuitState {
|
|
9
|
+
/** Normal operation - requests are allowed */
|
|
10
|
+
CLOSED = "CLOSED",
|
|
11
|
+
/** Failing - all requests are rejected immediately */
|
|
12
|
+
OPEN = "OPEN",
|
|
13
|
+
/** Testing recovery - limited requests are allowed */
|
|
14
|
+
HALF_OPEN = "HALF_OPEN"
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Circuit breaker configuration
|
|
18
|
+
*/
|
|
19
|
+
interface CircuitBreakerConfig {
|
|
20
|
+
/** Number of failures before opening circuit */
|
|
21
|
+
failureThreshold?: number;
|
|
22
|
+
/** Time in ms before attempting to close circuit */
|
|
23
|
+
cooldownMs?: number;
|
|
24
|
+
/** Request timeout in ms */
|
|
25
|
+
timeout?: number;
|
|
26
|
+
/** Name for logging */
|
|
27
|
+
name?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Circuit breaker statistics
|
|
31
|
+
*/
|
|
32
|
+
interface CircuitBreakerStats {
|
|
33
|
+
/** Current state */
|
|
34
|
+
state: CircuitState;
|
|
35
|
+
/** Total failures */
|
|
36
|
+
failures: number;
|
|
37
|
+
/** Total successes */
|
|
38
|
+
successes: number;
|
|
39
|
+
/** Total calls */
|
|
40
|
+
totalCalls: number;
|
|
41
|
+
/** Time circuit opened (if open) */
|
|
42
|
+
openedAt?: Date;
|
|
43
|
+
/** Time circuit will attempt to close */
|
|
44
|
+
resetAt?: Date;
|
|
45
|
+
/** Last error */
|
|
46
|
+
lastError?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Circuit breaker error thrown when circuit is open
|
|
50
|
+
*/
|
|
51
|
+
declare class CircuitBreakerOpenError extends Error {
|
|
52
|
+
readonly circuitName: string;
|
|
53
|
+
readonly resetAt: Date;
|
|
54
|
+
constructor(circuitName: string, resetAt: Date);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Circuit breaker implementation
|
|
58
|
+
* Tracks failures and opens circuit to prevent cascade failures
|
|
59
|
+
*/
|
|
60
|
+
declare class CircuitBreaker {
|
|
61
|
+
private state;
|
|
62
|
+
private failures;
|
|
63
|
+
private successes;
|
|
64
|
+
private totalCalls;
|
|
65
|
+
private openedAt?;
|
|
66
|
+
private resetAt?;
|
|
67
|
+
private lastError?;
|
|
68
|
+
private readonly failureThreshold;
|
|
69
|
+
private readonly cooldownMs;
|
|
70
|
+
private readonly timeout;
|
|
71
|
+
private readonly name;
|
|
72
|
+
constructor(config?: CircuitBreakerConfig);
|
|
73
|
+
/**
|
|
74
|
+
* Execute a function with circuit breaker protection
|
|
75
|
+
*/
|
|
76
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Execute function with timeout
|
|
79
|
+
*/
|
|
80
|
+
private executeWithTimeout;
|
|
81
|
+
/**
|
|
82
|
+
* Handle successful execution
|
|
83
|
+
*/
|
|
84
|
+
private onSuccess;
|
|
85
|
+
/**
|
|
86
|
+
* Handle failed execution
|
|
87
|
+
*/
|
|
88
|
+
private onFailure;
|
|
89
|
+
/**
|
|
90
|
+
* Open the circuit
|
|
91
|
+
*/
|
|
92
|
+
private openCircuit;
|
|
93
|
+
/**
|
|
94
|
+
* Check if circuit can attempt reset
|
|
95
|
+
*/
|
|
96
|
+
private canAttemptReset;
|
|
97
|
+
/**
|
|
98
|
+
* Get current circuit breaker state
|
|
99
|
+
*/
|
|
100
|
+
getState(): CircuitState;
|
|
101
|
+
/**
|
|
102
|
+
* Get circuit breaker statistics
|
|
103
|
+
*/
|
|
104
|
+
getStats(): CircuitBreakerStats;
|
|
105
|
+
/**
|
|
106
|
+
* Manually reset circuit breaker
|
|
107
|
+
*/
|
|
108
|
+
reset(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Check if circuit is open
|
|
111
|
+
*/
|
|
112
|
+
isOpen(): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Check if circuit is closed
|
|
115
|
+
*/
|
|
116
|
+
isClosed(): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Check if circuit is half-open
|
|
119
|
+
*/
|
|
120
|
+
isHalfOpen(): boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { CircuitBreaker, type CircuitBreakerConfig, CircuitBreakerOpenError, type CircuitBreakerStats, CircuitState };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/* @dsai-io/tools - DSAi Design System Build Tools */
|
|
2
|
+
|
|
3
|
+
// src/utils/circuit-breaker.ts
|
|
4
|
+
var CircuitState = /* @__PURE__ */ ((CircuitState2) => {
|
|
5
|
+
CircuitState2["CLOSED"] = "CLOSED";
|
|
6
|
+
CircuitState2["OPEN"] = "OPEN";
|
|
7
|
+
CircuitState2["HALF_OPEN"] = "HALF_OPEN";
|
|
8
|
+
return CircuitState2;
|
|
9
|
+
})(CircuitState || {});
|
|
10
|
+
var CircuitBreakerOpenError = class extends Error {
|
|
11
|
+
constructor(circuitName, resetAt) {
|
|
12
|
+
super(`Circuit breaker "${circuitName}" is open. Will retry at ${resetAt.toISOString()}`);
|
|
13
|
+
this.circuitName = circuitName;
|
|
14
|
+
this.resetAt = resetAt;
|
|
15
|
+
this.name = "CircuitBreakerOpenError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var CircuitBreaker = class {
|
|
19
|
+
state = "CLOSED" /* CLOSED */;
|
|
20
|
+
failures = 0;
|
|
21
|
+
successes = 0;
|
|
22
|
+
totalCalls = 0;
|
|
23
|
+
openedAt;
|
|
24
|
+
resetAt;
|
|
25
|
+
lastError;
|
|
26
|
+
failureThreshold;
|
|
27
|
+
cooldownMs;
|
|
28
|
+
timeout;
|
|
29
|
+
name;
|
|
30
|
+
constructor(config = {}) {
|
|
31
|
+
this.failureThreshold = config.failureThreshold ?? 5;
|
|
32
|
+
this.cooldownMs = config.cooldownMs ?? 3e4;
|
|
33
|
+
this.timeout = config.timeout ?? 1e4;
|
|
34
|
+
this.name = config.name ?? "CircuitBreaker";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute a function with circuit breaker protection
|
|
38
|
+
*/
|
|
39
|
+
async execute(fn) {
|
|
40
|
+
this.totalCalls++;
|
|
41
|
+
if (this.state === "OPEN" /* OPEN */ && this.canAttemptReset()) {
|
|
42
|
+
this.state = "HALF_OPEN" /* HALF_OPEN */;
|
|
43
|
+
this.failures = 0;
|
|
44
|
+
}
|
|
45
|
+
if (this.state === "OPEN" /* OPEN */) {
|
|
46
|
+
if (!this.resetAt) {
|
|
47
|
+
throw new Error(`Circuit breaker "${this.name}" is open but has no reset time`);
|
|
48
|
+
}
|
|
49
|
+
throw new CircuitBreakerOpenError(this.name, this.resetAt);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const result = await this.executeWithTimeout(fn);
|
|
53
|
+
this.onSuccess();
|
|
54
|
+
return result;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
this.onFailure(error);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Execute function with timeout
|
|
62
|
+
*/
|
|
63
|
+
async executeWithTimeout(fn) {
|
|
64
|
+
return Promise.race([
|
|
65
|
+
fn(),
|
|
66
|
+
new Promise((_, reject) => {
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
reject(new Error(`Circuit breaker timeout after ${this.timeout}ms`));
|
|
69
|
+
}, this.timeout);
|
|
70
|
+
})
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Handle successful execution
|
|
75
|
+
*/
|
|
76
|
+
onSuccess() {
|
|
77
|
+
this.successes++;
|
|
78
|
+
if (this.state === "HALF_OPEN" /* HALF_OPEN */) {
|
|
79
|
+
this.state = "CLOSED" /* CLOSED */;
|
|
80
|
+
this.failures = 0;
|
|
81
|
+
this.openedAt = void 0;
|
|
82
|
+
this.resetAt = void 0;
|
|
83
|
+
this.lastError = void 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Handle failed execution
|
|
88
|
+
*/
|
|
89
|
+
onFailure(error) {
|
|
90
|
+
this.failures++;
|
|
91
|
+
this.lastError = error instanceof Error ? error.message : String(error);
|
|
92
|
+
if (this.state === "HALF_OPEN" /* HALF_OPEN */) {
|
|
93
|
+
this.openCircuit();
|
|
94
|
+
} else if (this.failures >= this.failureThreshold) {
|
|
95
|
+
this.openCircuit();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Open the circuit
|
|
100
|
+
*/
|
|
101
|
+
openCircuit() {
|
|
102
|
+
this.state = "OPEN" /* OPEN */;
|
|
103
|
+
this.openedAt = /* @__PURE__ */ new Date();
|
|
104
|
+
this.resetAt = new Date(Date.now() + this.cooldownMs);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if circuit can attempt reset
|
|
108
|
+
*/
|
|
109
|
+
canAttemptReset() {
|
|
110
|
+
if (!this.resetAt) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return Date.now() >= this.resetAt.getTime();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get current circuit breaker state
|
|
117
|
+
*/
|
|
118
|
+
getState() {
|
|
119
|
+
return this.state;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get circuit breaker statistics
|
|
123
|
+
*/
|
|
124
|
+
getStats() {
|
|
125
|
+
return {
|
|
126
|
+
state: this.state,
|
|
127
|
+
failures: this.failures,
|
|
128
|
+
successes: this.successes,
|
|
129
|
+
totalCalls: this.totalCalls,
|
|
130
|
+
openedAt: this.openedAt,
|
|
131
|
+
resetAt: this.resetAt,
|
|
132
|
+
lastError: this.lastError
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Manually reset circuit breaker
|
|
137
|
+
*/
|
|
138
|
+
reset() {
|
|
139
|
+
this.state = "CLOSED" /* CLOSED */;
|
|
140
|
+
this.failures = 0;
|
|
141
|
+
this.successes = 0;
|
|
142
|
+
this.totalCalls = 0;
|
|
143
|
+
this.openedAt = void 0;
|
|
144
|
+
this.resetAt = void 0;
|
|
145
|
+
this.lastError = void 0;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if circuit is open
|
|
149
|
+
*/
|
|
150
|
+
isOpen() {
|
|
151
|
+
return this.state === "OPEN" /* OPEN */;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Check if circuit is closed
|
|
155
|
+
*/
|
|
156
|
+
isClosed() {
|
|
157
|
+
return this.state === "CLOSED" /* CLOSED */;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Check if circuit is half-open
|
|
161
|
+
*/
|
|
162
|
+
isHalfOpen() {
|
|
163
|
+
return this.state === "HALF_OPEN" /* HALF_OPEN */;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export { CircuitBreaker, CircuitBreakerOpenError, CircuitState };
|
|
168
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
169
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/circuit-breaker.ts"],"names":["CircuitState"],"mappings":"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","file":"circuit-breaker.js","sourcesContent":["/**\n * @fileoverview Circuit Breaker pattern implementation\n * Prevents cascade failures by tracking error rates and temporarily blocking requests\n */\n\n/**\n * Circuit breaker states\n */\nexport enum CircuitState {\n /** Normal operation - requests are allowed */\n CLOSED = 'CLOSED',\n /** Failing - all requests are rejected immediately */\n OPEN = 'OPEN',\n /** Testing recovery - limited requests are allowed */\n HALF_OPEN = 'HALF_OPEN',\n}\n\n/**\n * Circuit breaker configuration\n */\nexport interface CircuitBreakerConfig {\n /** Number of failures before opening circuit */\n failureThreshold?: number;\n /** Time in ms before attempting to close circuit */\n cooldownMs?: number;\n /** Request timeout in ms */\n timeout?: number;\n /** Name for logging */\n name?: string;\n}\n\n/**\n * Circuit breaker statistics\n */\nexport interface CircuitBreakerStats {\n /** Current state */\n state: CircuitState;\n /** Total failures */\n failures: number;\n /** Total successes */\n successes: number;\n /** Total calls */\n totalCalls: number;\n /** Time circuit opened (if open) */\n openedAt?: Date;\n /** Time circuit will attempt to close */\n resetAt?: Date;\n /** Last error */\n lastError?: string;\n}\n\n/**\n * Circuit breaker error thrown when circuit is open\n */\nexport class CircuitBreakerOpenError extends Error {\n constructor(\n public readonly circuitName: string,\n public readonly resetAt: Date\n ) {\n super(`Circuit breaker \"${circuitName}\" is open. Will retry at ${resetAt.toISOString()}`);\n this.name = 'CircuitBreakerOpenError';\n }\n}\n\n/**\n * Circuit breaker implementation\n * Tracks failures and opens circuit to prevent cascade failures\n */\nexport class CircuitBreaker {\n private state: CircuitState = CircuitState.CLOSED;\n private failures = 0;\n private successes = 0;\n private totalCalls = 0;\n private openedAt?: Date;\n private resetAt?: Date;\n private lastError?: string;\n\n private readonly failureThreshold: number;\n private readonly cooldownMs: number;\n private readonly timeout: number;\n private readonly name: string;\n\n constructor(config: CircuitBreakerConfig = {}) {\n this.failureThreshold = config.failureThreshold ?? 5;\n this.cooldownMs = config.cooldownMs ?? 30000; // 30 seconds\n this.timeout = config.timeout ?? 10000; // 10 seconds\n this.name = config.name ?? 'CircuitBreaker';\n }\n\n /**\n * Execute a function with circuit breaker protection\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n this.totalCalls++;\n\n // Check if circuit should transition from OPEN to HALF_OPEN\n if (this.state === CircuitState.OPEN && this.canAttemptReset()) {\n this.state = CircuitState.HALF_OPEN;\n this.failures = 0; // Reset failure count for half-open state\n }\n\n // Reject immediately if circuit is open\n if (this.state === CircuitState.OPEN) {\n if (!this.resetAt) {\n throw new Error(`Circuit breaker \"${this.name}\" is open but has no reset time`);\n }\n throw new CircuitBreakerOpenError(this.name, this.resetAt);\n }\n\n try {\n // Execute with timeout\n const result = await this.executeWithTimeout(fn);\n\n // Record success\n this.onSuccess();\n\n return result;\n } catch (error) {\n // Record failure\n this.onFailure(error);\n throw error;\n }\n }\n\n /**\n * Execute function with timeout\n */\n private async executeWithTimeout<T>(fn: () => Promise<T>): Promise<T> {\n return Promise.race([\n fn(),\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Circuit breaker timeout after ${this.timeout}ms`));\n }, this.timeout);\n }),\n ]);\n }\n\n /**\n * Handle successful execution\n */\n private onSuccess(): void {\n this.successes++;\n\n if (this.state === CircuitState.HALF_OPEN) {\n // Successful call in HALF_OPEN state closes the circuit\n this.state = CircuitState.CLOSED;\n this.failures = 0;\n this.openedAt = undefined;\n this.resetAt = undefined;\n this.lastError = undefined;\n }\n }\n\n /**\n * Handle failed execution\n */\n private onFailure(error: unknown): void {\n this.failures++;\n this.lastError = error instanceof Error ? error.message : String(error);\n\n if (this.state === CircuitState.HALF_OPEN) {\n // Failure in HALF_OPEN state immediately reopens circuit\n this.openCircuit();\n } else if (this.failures >= this.failureThreshold) {\n // Threshold reached, open circuit\n this.openCircuit();\n }\n }\n\n /**\n * Open the circuit\n */\n private openCircuit(): void {\n this.state = CircuitState.OPEN;\n this.openedAt = new Date();\n this.resetAt = new Date(Date.now() + this.cooldownMs);\n }\n\n /**\n * Check if circuit can attempt reset\n */\n private canAttemptReset(): boolean {\n if (!this.resetAt) {\n return false;\n }\n return Date.now() >= this.resetAt.getTime();\n }\n\n /**\n * Get current circuit breaker state\n */\n getState(): CircuitState {\n return this.state;\n }\n\n /**\n * Get circuit breaker statistics\n */\n getStats(): CircuitBreakerStats {\n return {\n state: this.state,\n failures: this.failures,\n successes: this.successes,\n totalCalls: this.totalCalls,\n openedAt: this.openedAt,\n resetAt: this.resetAt,\n lastError: this.lastError,\n };\n }\n\n /**\n * Manually reset circuit breaker\n */\n reset(): void {\n this.state = CircuitState.CLOSED;\n this.failures = 0;\n this.successes = 0;\n this.totalCalls = 0;\n this.openedAt = undefined;\n this.resetAt = undefined;\n this.lastError = undefined;\n }\n\n /**\n * Check if circuit is open\n */\n isOpen(): boolean {\n return this.state === CircuitState.OPEN;\n }\n\n /**\n * Check if circuit is closed\n */\n isClosed(): boolean {\n return this.state === CircuitState.CLOSED;\n }\n\n /**\n * Check if circuit is half-open\n */\n isHalfOpen(): boolean {\n return this.state === CircuitState.HALF_OPEN;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsai-io/tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Build tooling and CLI for DSAi Design System",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
"types": "./dist/cli/index.d.ts",
|
|
36
36
|
"import": "./dist/cli/index.js",
|
|
37
37
|
"require": "./dist/cli/index.cjs"
|
|
38
|
+
},
|
|
39
|
+
"./utils/circuit-breaker": {
|
|
40
|
+
"types": "./dist/utils/circuit-breaker.d.ts",
|
|
41
|
+
"import": "./dist/utils/circuit-breaker.js",
|
|
42
|
+
"require": "./dist/utils/circuit-breaker.cjs"
|
|
38
43
|
}
|
|
39
44
|
},
|
|
40
45
|
"files": [
|
|
@@ -72,19 +77,19 @@
|
|
|
72
77
|
"ora": "^9.0.0",
|
|
73
78
|
"picocolors": "^1.1.1",
|
|
74
79
|
"svgo": "^4.0.0",
|
|
75
|
-
"zod": "^3.
|
|
80
|
+
"zod": "^4.3.5"
|
|
76
81
|
},
|
|
77
82
|
"devDependencies": {
|
|
78
83
|
"@clack/prompts": "^0.11.0",
|
|
79
84
|
"@types/node": "^22.15.30",
|
|
80
85
|
"@types/prompts": "^2.4.9",
|
|
81
|
-
"style-dictionary": "^5.1.
|
|
86
|
+
"style-dictionary": "^5.1.4",
|
|
82
87
|
"tsup": "^8.5.1",
|
|
83
88
|
"typescript": "^5.9.3",
|
|
84
|
-
"zod-to-json-schema": "^3.25.
|
|
89
|
+
"zod-to-json-schema": "^3.25.1"
|
|
85
90
|
},
|
|
86
91
|
"peerDependencies": {
|
|
87
|
-
"style-dictionary": "^5.1.
|
|
92
|
+
"style-dictionary": "^5.1.4"
|
|
88
93
|
},
|
|
89
94
|
"peerDependenciesMeta": {
|
|
90
95
|
"style-dictionary": {
|