@sparkleideas/shared 3.0.0-alpha.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.
Files changed (96) hide show
  1. package/README.md +323 -0
  2. package/__tests__/hooks/bash-safety.test.ts +289 -0
  3. package/__tests__/hooks/file-organization.test.ts +335 -0
  4. package/__tests__/hooks/git-commit.test.ts +336 -0
  5. package/__tests__/hooks/index.ts +23 -0
  6. package/__tests__/hooks/session-hooks.test.ts +357 -0
  7. package/__tests__/hooks/task-hooks.test.ts +193 -0
  8. package/docs/EVENTS_IMPLEMENTATION_SUMMARY.md +388 -0
  9. package/docs/EVENTS_QUICK_REFERENCE.md +470 -0
  10. package/docs/EVENTS_README.md +352 -0
  11. package/package.json +39 -0
  12. package/src/core/config/defaults.ts +207 -0
  13. package/src/core/config/index.ts +15 -0
  14. package/src/core/config/loader.ts +271 -0
  15. package/src/core/config/schema.ts +188 -0
  16. package/src/core/config/validator.ts +209 -0
  17. package/src/core/event-bus.ts +236 -0
  18. package/src/core/index.ts +22 -0
  19. package/src/core/interfaces/agent.interface.ts +251 -0
  20. package/src/core/interfaces/coordinator.interface.ts +363 -0
  21. package/src/core/interfaces/event.interface.ts +267 -0
  22. package/src/core/interfaces/index.ts +19 -0
  23. package/src/core/interfaces/memory.interface.ts +332 -0
  24. package/src/core/interfaces/task.interface.ts +223 -0
  25. package/src/core/orchestrator/event-coordinator.ts +122 -0
  26. package/src/core/orchestrator/health-monitor.ts +214 -0
  27. package/src/core/orchestrator/index.ts +89 -0
  28. package/src/core/orchestrator/lifecycle-manager.ts +263 -0
  29. package/src/core/orchestrator/session-manager.ts +279 -0
  30. package/src/core/orchestrator/task-manager.ts +317 -0
  31. package/src/events/domain-events.ts +584 -0
  32. package/src/events/event-store.test.ts +387 -0
  33. package/src/events/event-store.ts +588 -0
  34. package/src/events/example-usage.ts +293 -0
  35. package/src/events/index.ts +90 -0
  36. package/src/events/projections.ts +561 -0
  37. package/src/events/state-reconstructor.ts +349 -0
  38. package/src/events.ts +367 -0
  39. package/src/hooks/INTEGRATION.md +658 -0
  40. package/src/hooks/README.md +532 -0
  41. package/src/hooks/example-usage.ts +499 -0
  42. package/src/hooks/executor.ts +379 -0
  43. package/src/hooks/hooks.test.ts +421 -0
  44. package/src/hooks/index.ts +131 -0
  45. package/src/hooks/registry.ts +333 -0
  46. package/src/hooks/safety/bash-safety.ts +604 -0
  47. package/src/hooks/safety/file-organization.ts +473 -0
  48. package/src/hooks/safety/git-commit.ts +623 -0
  49. package/src/hooks/safety/index.ts +46 -0
  50. package/src/hooks/session-hooks.ts +559 -0
  51. package/src/hooks/task-hooks.ts +513 -0
  52. package/src/hooks/types.ts +357 -0
  53. package/src/hooks/verify-exports.test.ts +125 -0
  54. package/src/index.ts +195 -0
  55. package/src/mcp/connection-pool.ts +438 -0
  56. package/src/mcp/index.ts +183 -0
  57. package/src/mcp/server.ts +774 -0
  58. package/src/mcp/session-manager.ts +428 -0
  59. package/src/mcp/tool-registry.ts +566 -0
  60. package/src/mcp/transport/http.ts +557 -0
  61. package/src/mcp/transport/index.ts +294 -0
  62. package/src/mcp/transport/stdio.ts +324 -0
  63. package/src/mcp/transport/websocket.ts +484 -0
  64. package/src/mcp/types.ts +565 -0
  65. package/src/plugin-interface.ts +663 -0
  66. package/src/plugin-loader.ts +638 -0
  67. package/src/plugin-registry.ts +604 -0
  68. package/src/plugins/index.ts +34 -0
  69. package/src/plugins/official/hive-mind-plugin.ts +330 -0
  70. package/src/plugins/official/index.ts +24 -0
  71. package/src/plugins/official/maestro-plugin.ts +508 -0
  72. package/src/plugins/types.ts +108 -0
  73. package/src/resilience/bulkhead.ts +277 -0
  74. package/src/resilience/circuit-breaker.ts +326 -0
  75. package/src/resilience/index.ts +26 -0
  76. package/src/resilience/rate-limiter.ts +420 -0
  77. package/src/resilience/retry.ts +224 -0
  78. package/src/security/index.ts +39 -0
  79. package/src/security/input-validation.ts +265 -0
  80. package/src/security/secure-random.ts +159 -0
  81. package/src/services/index.ts +16 -0
  82. package/src/services/v3-progress.service.ts +505 -0
  83. package/src/types/agent.types.ts +144 -0
  84. package/src/types/index.ts +22 -0
  85. package/src/types/mcp.types.ts +300 -0
  86. package/src/types/memory.types.ts +263 -0
  87. package/src/types/swarm.types.ts +255 -0
  88. package/src/types/task.types.ts +205 -0
  89. package/src/types.ts +367 -0
  90. package/src/utils/secure-logger.d.ts +69 -0
  91. package/src/utils/secure-logger.d.ts.map +1 -0
  92. package/src/utils/secure-logger.js +208 -0
  93. package/src/utils/secure-logger.js.map +1 -0
  94. package/src/utils/secure-logger.ts +257 -0
  95. package/tmp.json +0 -0
  96. package/tsconfig.json +9 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Bulkhead Pattern
3
+ *
4
+ * Isolates failures by limiting concurrent executions.
5
+ *
6
+ * @module v3/shared/resilience/bulkhead
7
+ */
8
+
9
+ import { EventEmitter } from 'events';
10
+
11
+ /**
12
+ * Bulkhead options
13
+ */
14
+ export interface BulkheadOptions {
15
+ /** Name for identification */
16
+ name: string;
17
+
18
+ /** Maximum concurrent executions */
19
+ maxConcurrent: number;
20
+
21
+ /** Maximum queue size */
22
+ maxQueue: number;
23
+
24
+ /** Timeout for queued items in ms */
25
+ queueTimeout: number;
26
+
27
+ /** Callback when rejected */
28
+ onRejected?: (reason: 'full' | 'timeout') => void;
29
+ }
30
+
31
+ /**
32
+ * Bulkhead statistics
33
+ */
34
+ export interface BulkheadStats {
35
+ active: number;
36
+ queued: number;
37
+ maxConcurrent: number;
38
+ maxQueue: number;
39
+ completed: number;
40
+ rejected: number;
41
+ timedOut: number;
42
+ }
43
+
44
+ /**
45
+ * Queued item
46
+ */
47
+ interface QueuedItem<T> {
48
+ fn: () => Promise<T>;
49
+ resolve: (value: T) => void;
50
+ reject: (error: Error) => void;
51
+ queuedAt: number;
52
+ timeoutId?: ReturnType<typeof setTimeout>;
53
+ }
54
+
55
+ /**
56
+ * Default options
57
+ */
58
+ const DEFAULT_OPTIONS: Omit<BulkheadOptions, 'name'> = {
59
+ maxConcurrent: 10,
60
+ maxQueue: 100,
61
+ queueTimeout: 30000,
62
+ };
63
+
64
+ /**
65
+ * Bulkhead
66
+ *
67
+ * Limits concurrent executions to prevent resource exhaustion.
68
+ *
69
+ * @example
70
+ * const bulkhead = new Bulkhead({
71
+ * name: 'database',
72
+ * maxConcurrent: 10,
73
+ * maxQueue: 50,
74
+ * });
75
+ *
76
+ * try {
77
+ * const result = await bulkhead.execute(() => dbQuery());
78
+ * } catch (error) {
79
+ * if (error.message.includes('Bulkhead full')) {
80
+ * // Handle capacity exceeded
81
+ * }
82
+ * }
83
+ */
84
+ export class Bulkhead extends EventEmitter {
85
+ private readonly options: BulkheadOptions;
86
+ private active = 0;
87
+ private readonly queue: Array<QueuedItem<unknown>> = [];
88
+ private completed = 0;
89
+ private rejected = 0;
90
+ private timedOut = 0;
91
+
92
+ constructor(options: BulkheadOptions) {
93
+ super();
94
+ this.options = { ...DEFAULT_OPTIONS, ...options };
95
+ }
96
+
97
+ /**
98
+ * Execute a function within the bulkhead
99
+ */
100
+ async execute<T>(fn: () => Promise<T>): Promise<T> {
101
+ // If there's room for execution, run immediately
102
+ if (this.active < this.options.maxConcurrent) {
103
+ return this.runNow(fn);
104
+ }
105
+
106
+ // Check if queue is full
107
+ if (this.queue.length >= this.options.maxQueue) {
108
+ this.rejected++;
109
+ this.options.onRejected?.('full');
110
+ throw new Error(`Bulkhead '${this.options.name}' is full. Max concurrent: ${this.options.maxConcurrent}, queue: ${this.options.maxQueue}`);
111
+ }
112
+
113
+ // Add to queue
114
+ return this.addToQueue(fn);
115
+ }
116
+
117
+ /**
118
+ * Get current statistics
119
+ */
120
+ getStats(): BulkheadStats {
121
+ return {
122
+ active: this.active,
123
+ queued: this.queue.length,
124
+ maxConcurrent: this.options.maxConcurrent,
125
+ maxQueue: this.options.maxQueue,
126
+ completed: this.completed,
127
+ rejected: this.rejected,
128
+ timedOut: this.timedOut,
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Check if there's capacity available
134
+ */
135
+ hasCapacity(): boolean {
136
+ return this.active < this.options.maxConcurrent || this.queue.length < this.options.maxQueue;
137
+ }
138
+
139
+ /**
140
+ * Get available capacity (concurrent + queue)
141
+ */
142
+ availableCapacity(): number {
143
+ const concurrentAvailable = this.options.maxConcurrent - this.active;
144
+ const queueAvailable = this.options.maxQueue - this.queue.length;
145
+ return concurrentAvailable + queueAvailable;
146
+ }
147
+
148
+ /**
149
+ * Reset statistics
150
+ */
151
+ resetStats(): void {
152
+ this.completed = 0;
153
+ this.rejected = 0;
154
+ this.timedOut = 0;
155
+ }
156
+
157
+ /**
158
+ * Run function immediately
159
+ */
160
+ private async runNow<T>(fn: () => Promise<T>): Promise<T> {
161
+ this.active++;
162
+ this.emit('acquire');
163
+
164
+ try {
165
+ const result = await fn();
166
+ this.completed++;
167
+ return result;
168
+ } finally {
169
+ this.active--;
170
+ this.emit('release');
171
+ this.processQueue();
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Add function to queue
177
+ */
178
+ private addToQueue<T>(fn: () => Promise<T>): Promise<T> {
179
+ return new Promise((resolve, reject) => {
180
+ const item: QueuedItem<T> = {
181
+ fn,
182
+ resolve,
183
+ reject,
184
+ queuedAt: Date.now(),
185
+ };
186
+
187
+ // Set timeout for queued item
188
+ item.timeoutId = setTimeout(() => {
189
+ const index = this.queue.indexOf(item as QueuedItem<unknown>);
190
+ if (index !== -1) {
191
+ this.queue.splice(index, 1);
192
+ this.timedOut++;
193
+ this.options.onRejected?.('timeout');
194
+ reject(new Error(`Bulkhead '${this.options.name}' queue timeout after ${this.options.queueTimeout}ms`));
195
+ }
196
+ }, this.options.queueTimeout);
197
+
198
+ this.queue.push(item as QueuedItem<unknown>);
199
+ this.emit('queued', { queueLength: this.queue.length });
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Process next item in queue
205
+ */
206
+ private processQueue(): void {
207
+ if (this.active >= this.options.maxConcurrent) {
208
+ return;
209
+ }
210
+
211
+ const item = this.queue.shift();
212
+ if (!item) {
213
+ return;
214
+ }
215
+
216
+ // Clear timeout
217
+ if (item.timeoutId) {
218
+ clearTimeout(item.timeoutId);
219
+ }
220
+
221
+ // Execute the queued function
222
+ this.active++;
223
+ this.emit('acquire');
224
+
225
+ item.fn()
226
+ .then((result) => {
227
+ this.completed++;
228
+ item.resolve(result);
229
+ })
230
+ .catch((error) => {
231
+ item.reject(error);
232
+ })
233
+ .finally(() => {
234
+ this.active--;
235
+ this.emit('release');
236
+ this.processQueue();
237
+ });
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Create a semaphore for limiting concurrent access
243
+ */
244
+ export function createSemaphore(maxConcurrent: number): {
245
+ acquire: () => Promise<void>;
246
+ release: () => void;
247
+ available: () => number;
248
+ } {
249
+ let current = 0;
250
+ const waiting: Array<() => void> = [];
251
+
252
+ return {
253
+ async acquire(): Promise<void> {
254
+ if (current < maxConcurrent) {
255
+ current++;
256
+ return;
257
+ }
258
+
259
+ return new Promise<void>((resolve) => {
260
+ waiting.push(resolve);
261
+ });
262
+ },
263
+
264
+ release(): void {
265
+ const next = waiting.shift();
266
+ if (next) {
267
+ next();
268
+ } else {
269
+ current = Math.max(0, current - 1);
270
+ }
271
+ },
272
+
273
+ available(): number {
274
+ return maxConcurrent - current;
275
+ },
276
+ };
277
+ }
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Circuit Breaker Pattern
3
+ *
4
+ * Prevents cascading failures by breaking the circuit after failures.
5
+ *
6
+ * @module v3/shared/resilience/circuit-breaker
7
+ */
8
+
9
+ import { EventEmitter } from 'events';
10
+
11
+ /**
12
+ * Circuit breaker states
13
+ */
14
+ export enum CircuitBreakerState {
15
+ /** Circuit is closed, requests flow normally */
16
+ CLOSED = 'CLOSED',
17
+
18
+ /** Circuit is open, requests are rejected immediately */
19
+ OPEN = 'OPEN',
20
+
21
+ /** Circuit is testing if service recovered */
22
+ HALF_OPEN = 'HALF_OPEN',
23
+ }
24
+
25
+ /**
26
+ * Circuit breaker options
27
+ */
28
+ export interface CircuitBreakerOptions {
29
+ /** Name for identification */
30
+ name: string;
31
+
32
+ /** Failure threshold before opening circuit (default: 5) */
33
+ failureThreshold: number;
34
+
35
+ /** Success threshold in half-open state to close circuit (default: 3) */
36
+ successThreshold: number;
37
+
38
+ /** Time to wait before testing again in ms (default: 30000) */
39
+ timeout: number;
40
+
41
+ /** Time window to track failures in ms (default: 60000) */
42
+ rollingWindow: number;
43
+
44
+ /** Volume threshold - minimum requests before tripping (default: 10) */
45
+ volumeThreshold: number;
46
+
47
+ /** Custom failure detection */
48
+ isFailure?: (error: Error) => boolean;
49
+
50
+ /** Fallback function when circuit is open */
51
+ fallback?: <T>(error: Error) => T | Promise<T>;
52
+
53
+ /** Callback when state changes */
54
+ onStateChange?: (from: CircuitBreakerState, to: CircuitBreakerState) => void;
55
+ }
56
+
57
+ /**
58
+ * Circuit breaker statistics
59
+ */
60
+ export interface CircuitBreakerStats {
61
+ state: CircuitBreakerState;
62
+ failures: number;
63
+ successes: number;
64
+ totalRequests: number;
65
+ rejectedRequests: number;
66
+ lastFailure: Date | null;
67
+ lastSuccess: Date | null;
68
+ openSince: Date | null;
69
+ }
70
+
71
+ /**
72
+ * Default options
73
+ */
74
+ const DEFAULT_OPTIONS: Omit<CircuitBreakerOptions, 'name'> = {
75
+ failureThreshold: 5,
76
+ successThreshold: 3,
77
+ timeout: 30000,
78
+ rollingWindow: 60000,
79
+ volumeThreshold: 10,
80
+ };
81
+
82
+ /**
83
+ * Request tracking entry
84
+ */
85
+ interface RequestEntry {
86
+ timestamp: number;
87
+ success: boolean;
88
+ }
89
+
90
+ /**
91
+ * Circuit Breaker
92
+ *
93
+ * Implements the circuit breaker pattern to prevent cascading failures.
94
+ *
95
+ * @example
96
+ * const breaker = new CircuitBreaker({
97
+ * name: 'external-api',
98
+ * failureThreshold: 5,
99
+ * timeout: 30000,
100
+ * });
101
+ *
102
+ * try {
103
+ * const result = await breaker.execute(() => fetchExternalAPI());
104
+ * } catch (error) {
105
+ * if (error.message === 'Circuit is open') {
106
+ * // Handle circuit open case
107
+ * }
108
+ * }
109
+ */
110
+ export class CircuitBreaker extends EventEmitter {
111
+ private readonly options: CircuitBreakerOptions;
112
+ private state: CircuitBreakerState = CircuitBreakerState.CLOSED;
113
+ private requests: RequestEntry[] = [];
114
+ private halfOpenSuccesses = 0;
115
+ private openedAt: Date | null = null;
116
+ private lastFailure: Date | null = null;
117
+ private lastSuccess: Date | null = null;
118
+ private rejectedCount = 0;
119
+ private timeoutId?: ReturnType<typeof setTimeout>;
120
+
121
+ constructor(options: CircuitBreakerOptions) {
122
+ super();
123
+ this.options = { ...DEFAULT_OPTIONS, ...options };
124
+ }
125
+
126
+ /**
127
+ * Execute a function through the circuit breaker
128
+ */
129
+ async execute<T>(fn: () => Promise<T>): Promise<T> {
130
+ // Clean up old requests
131
+ this.cleanOldRequests();
132
+
133
+ // Check if circuit should be tested
134
+ this.checkState();
135
+
136
+ // If open, reject immediately or use fallback
137
+ if (this.state === CircuitBreakerState.OPEN) {
138
+ this.rejectedCount++;
139
+ const error = new Error(`Circuit breaker '${this.options.name}' is open`);
140
+
141
+ if (this.options.fallback) {
142
+ return this.options.fallback(error);
143
+ }
144
+
145
+ throw error;
146
+ }
147
+
148
+ try {
149
+ const result = await fn();
150
+ this.onSuccess();
151
+ return result;
152
+ } catch (error) {
153
+ const err = error instanceof Error ? error : new Error(String(error));
154
+
155
+ // Check if this should be counted as failure
156
+ const isFailure = this.options.isFailure?.(err) ?? true;
157
+
158
+ if (isFailure) {
159
+ this.onFailure(err);
160
+ }
161
+
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get current state
168
+ */
169
+ getState(): CircuitBreakerState {
170
+ this.checkState();
171
+ return this.state;
172
+ }
173
+
174
+ /**
175
+ * Get statistics
176
+ */
177
+ getStats(): CircuitBreakerStats {
178
+ this.cleanOldRequests();
179
+
180
+ return {
181
+ state: this.state,
182
+ failures: this.requests.filter((r) => !r.success).length,
183
+ successes: this.requests.filter((r) => r.success).length,
184
+ totalRequests: this.requests.length,
185
+ rejectedRequests: this.rejectedCount,
186
+ lastFailure: this.lastFailure,
187
+ lastSuccess: this.lastSuccess,
188
+ openSince: this.openedAt,
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Force reset the circuit breaker
194
+ */
195
+ reset(): void {
196
+ const previousState = this.state;
197
+ this.state = CircuitBreakerState.CLOSED;
198
+ this.requests = [];
199
+ this.halfOpenSuccesses = 0;
200
+ this.openedAt = null;
201
+
202
+ if (this.timeoutId) {
203
+ clearTimeout(this.timeoutId);
204
+ this.timeoutId = undefined;
205
+ }
206
+
207
+ if (previousState !== this.state) {
208
+ this.notifyStateChange(previousState, this.state);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Handle successful request
214
+ */
215
+ private onSuccess(): void {
216
+ this.lastSuccess = new Date();
217
+ this.requests.push({ timestamp: Date.now(), success: true });
218
+
219
+ if (this.state === CircuitBreakerState.HALF_OPEN) {
220
+ this.halfOpenSuccesses++;
221
+
222
+ if (this.halfOpenSuccesses >= this.options.successThreshold) {
223
+ this.transitionTo(CircuitBreakerState.CLOSED);
224
+ this.halfOpenSuccesses = 0;
225
+ }
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Handle failed request
231
+ */
232
+ private onFailure(error: Error): void {
233
+ this.lastFailure = new Date();
234
+ this.requests.push({ timestamp: Date.now(), success: false });
235
+
236
+ if (this.state === CircuitBreakerState.HALF_OPEN) {
237
+ // Failed during half-open, go back to open
238
+ this.transitionTo(CircuitBreakerState.OPEN);
239
+ this.halfOpenSuccesses = 0;
240
+ return;
241
+ }
242
+
243
+ // Check if we should open the circuit
244
+ const failures = this.requests.filter((r) => !r.success).length;
245
+ const totalRequests = this.requests.length;
246
+
247
+ if (
248
+ totalRequests >= this.options.volumeThreshold &&
249
+ failures >= this.options.failureThreshold
250
+ ) {
251
+ this.transitionTo(CircuitBreakerState.OPEN);
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Check if state should change based on timeout
257
+ */
258
+ private checkState(): void {
259
+ if (this.state === CircuitBreakerState.OPEN && this.openedAt) {
260
+ const elapsed = Date.now() - this.openedAt.getTime();
261
+
262
+ if (elapsed >= this.options.timeout) {
263
+ this.transitionTo(CircuitBreakerState.HALF_OPEN);
264
+ }
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Transition to new state
270
+ */
271
+ private transitionTo(newState: CircuitBreakerState): void {
272
+ const previousState = this.state;
273
+
274
+ if (previousState === newState) {
275
+ return;
276
+ }
277
+
278
+ this.state = newState;
279
+
280
+ if (newState === CircuitBreakerState.OPEN) {
281
+ this.openedAt = new Date();
282
+ this.scheduleHalfOpen();
283
+ } else if (newState === CircuitBreakerState.CLOSED) {
284
+ this.openedAt = null;
285
+ this.requests = [];
286
+
287
+ if (this.timeoutId) {
288
+ clearTimeout(this.timeoutId);
289
+ this.timeoutId = undefined;
290
+ }
291
+ }
292
+
293
+ this.notifyStateChange(previousState, newState);
294
+ }
295
+
296
+ /**
297
+ * Schedule transition to half-open
298
+ */
299
+ private scheduleHalfOpen(): void {
300
+ if (this.timeoutId) {
301
+ clearTimeout(this.timeoutId);
302
+ }
303
+
304
+ this.timeoutId = setTimeout(() => {
305
+ if (this.state === CircuitBreakerState.OPEN) {
306
+ this.transitionTo(CircuitBreakerState.HALF_OPEN);
307
+ }
308
+ }, this.options.timeout);
309
+ }
310
+
311
+ /**
312
+ * Notify state change
313
+ */
314
+ private notifyStateChange(from: CircuitBreakerState, to: CircuitBreakerState): void {
315
+ this.emit('stateChange', { from, to });
316
+ this.options.onStateChange?.(from, to);
317
+ }
318
+
319
+ /**
320
+ * Clean old requests outside rolling window
321
+ */
322
+ private cleanOldRequests(): void {
323
+ const cutoff = Date.now() - this.options.rollingWindow;
324
+ this.requests = this.requests.filter((r) => r.timestamp >= cutoff);
325
+ }
326
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Resilience Patterns
3
+ *
4
+ * Production-ready resilience utilities:
5
+ * - Retry with exponential backoff
6
+ * - Circuit breaker pattern
7
+ * - Rate limiting
8
+ *
9
+ * @module v3/shared/resilience
10
+ */
11
+
12
+ // Retry
13
+ export { retry, RetryError } from './retry.js';
14
+ export type { RetryOptions, RetryResult } from './retry.js';
15
+
16
+ // Circuit Breaker
17
+ export { CircuitBreaker } from './circuit-breaker.js';
18
+ export type { CircuitBreakerOptions, CircuitBreakerStats } from './circuit-breaker.js';
19
+
20
+ // Rate Limiter
21
+ export { SlidingWindowRateLimiter, TokenBucketRateLimiter } from './rate-limiter.js';
22
+ export type { RateLimiter, RateLimiterOptions, RateLimitResult } from './rate-limiter.js';
23
+
24
+ // Bulkhead
25
+ export { Bulkhead } from './bulkhead.js';
26
+ export type { BulkheadOptions, BulkheadStats } from './bulkhead.js';