breaker-box 8.1.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -182,7 +182,7 @@ Creates a circuit breaker around the provided async function.
182
182
 
183
183
  - `fn`: The async function to protect
184
184
  - `options`: Configuration object (optional)
185
- - `errorIsFailure`: Function to determine if an error is a non-retryable failure; when true, the error is thrown immediately without counting toward metrics (default: `() => false`)
185
+ - `errorIsTransient`: Function to determine if an error is transient; when true, the error is thrown to the caller but does NOT count toward the circuit breaker's failure rate (default: `() => false`)
186
186
  - `errorThreshold`: Percentage (0-1) of errors that triggers circuit opening (default: `0`)
187
187
  - `errorWindow`: Time window in ms for tracking errors (default: `10_000`)
188
188
  - `fallback`: Function to call when an error occurs or circuit is open (default: undefined)
@@ -208,41 +208,15 @@ A function with the same signature as `fn` and additional methods:
208
208
 
209
209
  ### Helper Functions
210
210
 
211
- #### `withRetry(fn, options?)` *(Deprecated)*
211
+ #### `CircuitError`
212
212
 
213
- > **Deprecated:** Use the `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead.
213
+ Error class thrown by the circuit breaker. All errors from `createCircuitBreaker` are instances of `CircuitError` with a prefixed message (e.g., `ERR_CIRCUIT_BREAKER_CALL_FAILURE`, `ERR_CIRCUIT_BREAKER_MAX_RETRIES`).
214
214
 
215
- Wraps a function with retry logic. Failures will be retried according to the provided options.
215
+ **Properties:**
216
216
 
217
- **Parameters:**
218
-
219
- - `fn`: The async function to wrap with retry logic
220
- - `options`: Configuration object (optional)
221
- - `maxAttempts`: Maximum number of attempts (default: `3`)
222
- - `retryDelay`: Function `(attempt: number, signal: AbortSignal) => Promise<void>` for delay before retry (default: immediate)
223
- - `shouldRetry`: Function `(error: unknown, attempt: number) => boolean` to determine if error should be retried (default: `() => true`)
224
-
225
- **Example:**
226
-
227
- ```typescript
228
- const retryCall = withRetry(apiCall, {
229
- maxAttempts: 5,
230
- retryDelay: useExponentialBackoff(30),
231
- shouldRetry: (error) => error.statusCode !== 404,
232
- })
233
- ```
234
-
235
- #### `withTimeout(fn, timeoutMs, message?)` *(Deprecated)*
236
-
237
- > **Deprecated:** Use the `timeout` option on `createCircuitBreaker` instead.
238
-
239
- Wraps a function with a timeout. Rejects with `Error(message)` if execution exceeds `timeoutMs`.
240
-
241
- **Parameters:**
242
-
243
- - `fn`: The async function to wrap with timeout
244
- - `timeoutMs`: Timeout in milliseconds
245
- - `message`: Error message to use when timeout occurs (default: `"ERR_CIRCUIT_BREAKER_TIMEOUT"`)
217
+ - `message`: Prefixed error code (e.g., `"ERR_CIRCUIT_BREAKER_OPEN"`)
218
+ - `cause`: The underlying error that triggered the circuit breaker error
219
+ - `isTransient`: `true` if the error was classified as transient via `errorIsTransient`
246
220
 
247
221
  #### `useExponentialBackoff(maxSeconds)`
248
222
 
package/dist/index.cjs CHANGED
@@ -9,13 +9,6 @@ const abortable = (signal, pending) => new Promise((resolve, reject) => {
9
9
  function assert(value, message) {
10
10
  if (!value) throw new TypeError(message);
11
11
  }
12
- class CircuitError extends Error {
13
- isTransient;
14
- constructor(message, options) {
15
- super(`ERR_CIRCUIT_BREAKER_${message}`, options);
16
- this.isTransient = options?.isTransient ?? false;
17
- }
18
- }
19
12
  const delayMs = (ms, signal) => {
20
13
  if (!Number.isFinite(ms) || ms < 0) {
21
14
  throw new RangeError(
@@ -35,16 +28,6 @@ const delayMs = (ms, signal) => {
35
28
  signal.addEventListener("abort", onAbort, { once: true });
36
29
  }) : new Promise((next) => setTimeout(next, ms));
37
30
  };
38
- const deprecated = (fn, method, message) => {
39
- let warned = false;
40
- return ((...args) => {
41
- if (!warned) {
42
- console.warn(`[breaker-box] ${method} Deprecation: ${message}`);
43
- warned = true;
44
- }
45
- return fn(...args);
46
- });
47
- };
48
31
  const noop = () => {
49
32
  };
50
33
  function promiseTry(fn) {
@@ -54,65 +37,6 @@ function promiseTry(fn) {
54
37
  return Promise.reject(error);
55
38
  }
56
39
  }
57
- async function shouldContinue(options) {
58
- const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
59
- if (retries >= retryLimit)
60
- throw new CircuitError("MAX_RETRIES", { cause: lastError });
61
- if (!retryTest(lastError))
62
- throw new CircuitError("NON_RETRYABLE", { cause: lastError });
63
- try {
64
- if (!retryDelay) return true;
65
- else if (typeof retryDelay === "number") await delayMs(retryDelay, signal);
66
- else if (typeof retryDelay === "function") await retryDelay(retries, signal);
67
- } catch {
68
- }
69
- return true;
70
- }
71
-
72
- function withRetry$1(main, options = {}) {
73
- const {
74
- shouldRetry = () => true,
75
- maxAttempts = 3,
76
- retryDelay = () => Promise.resolve()
77
- } = options;
78
- assert(maxAttempts >= 1, "maxAttempts must be a number greater than 0");
79
- const controller = new AbortController();
80
- const { signal } = controller;
81
- async function withRetryFunction(...args) {
82
- let attempt = 1;
83
- while (true) {
84
- try {
85
- return await main(...args);
86
- } catch (cause) {
87
- if (attempt >= maxAttempts) {
88
- throw new Error(`ERR_CIRCUIT_BREAKER_MAX_ATTEMPTS (${maxAttempts})`, {
89
- cause
90
- });
91
- }
92
- if (!shouldRetry(cause, attempt)) throw cause;
93
- }
94
- attempt++;
95
- await abortable(signal, retryDelay(attempt, signal));
96
- }
97
- }
98
- return Object.assign(withRetryFunction, {
99
- [Symbol.dispose]: () => controller.abort()
100
- });
101
- }
102
-
103
- function withTimeout$1(main, timeoutMs, timeoutMessage = "ERR_CIRCUIT_BREAKER_TIMEOUT") {
104
- const controller = new AbortController();
105
- const { signal } = controller;
106
- function withTimeoutFunction(...args) {
107
- return new Promise((resolve, reject) => {
108
- const timer = setTimeout(reject, timeoutMs, new Error(timeoutMessage));
109
- abortable(signal, main(...args)).then(resolve, reject).finally(() => clearTimeout(timer));
110
- });
111
- }
112
- return Object.assign(withTimeoutFunction, {
113
- [Symbol.dispose]: () => controller.abort()
114
- });
115
- }
116
40
 
117
41
  function useExponentialBackoff(maxSeconds) {
118
42
  return function exponentialBackoff(attempt, signal) {
@@ -130,9 +54,18 @@ function useFibonacciBackoff(maxSeconds) {
130
54
  };
131
55
  }
132
56
 
57
+ class CircuitError extends Error {
58
+ isTransient;
59
+ constructor(message, options) {
60
+ super(`ERR_CIRCUIT_BREAKER_${message}`, options);
61
+ this.isTransient = options?.isTransient ?? false;
62
+ }
63
+ }
64
+
65
+ let warnedErrorIsFailure = false;
133
66
  function parseOptions(options) {
134
67
  const {
135
- errorIsFailure = () => false,
68
+ errorIsTransient = options.errorIsFailure ?? (() => false),
136
69
  errorThreshold = 0,
137
70
  errorWindow = 1e4,
138
71
  fallback,
@@ -146,9 +79,15 @@ function parseOptions(options) {
146
79
  retryTest = () => true,
147
80
  timeout = 0
148
81
  } = options;
82
+ if ("errorIsFailure" in options && !("errorIsTransient" in options) && !warnedErrorIsFailure) {
83
+ warnedErrorIsFailure = true;
84
+ console.warn(
85
+ 'breaker-box: "errorIsFailure" is deprecated. Use "errorIsTransient" instead.'
86
+ );
87
+ }
149
88
  assert(
150
- typeof errorIsFailure === "function",
151
- `"errorIsFailure" must be a function (received ${typeof errorIsFailure})`
89
+ typeof errorIsTransient === "function",
90
+ `"errorIsTransient" must be a function (received ${typeof errorIsTransient})`
152
91
  );
153
92
  assert(
154
93
  errorThreshold >= 0 && errorThreshold <= 1,
@@ -203,7 +142,7 @@ function parseOptions(options) {
203
142
  `"timeout" must be a finite, non-negative number (received ${timeout})`
204
143
  );
205
144
  return {
206
- errorIsFailure,
145
+ errorIsTransient,
207
146
  errorThreshold,
208
147
  errorWindow,
209
148
  fallback,
@@ -219,6 +158,20 @@ function parseOptions(options) {
219
158
  };
220
159
  }
221
160
 
161
+ async function shouldContinue(options) {
162
+ const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
163
+ if (retries >= retryLimit)
164
+ throw new CircuitError("MAX_RETRIES", { cause: lastError });
165
+ if (!retryTest(lastError))
166
+ throw new CircuitError("NON_RETRYABLE", { cause: lastError });
167
+ try {
168
+ if (!retryDelay) return true;
169
+ else if (typeof retryDelay === "number") await delayMs(retryDelay, signal);
170
+ else if (typeof retryDelay === "function") await retryDelay(retries, signal);
171
+ } catch {
172
+ }
173
+ return true;
174
+ }
222
175
  const validTransitions = {
223
176
  closed: ["open", "disposed"],
224
177
  open: ["halfOpen", "disposed"],
@@ -243,7 +196,7 @@ function createState(status, failureCause) {
243
196
  }
244
197
  function createCircuitBreaker(main, options = {}) {
245
198
  const {
246
- errorIsFailure,
199
+ errorIsTransient,
247
200
  errorThreshold,
248
201
  errorWindow,
249
202
  fallback,
@@ -269,7 +222,7 @@ function createCircuitBreaker(main, options = {}) {
269
222
  return result;
270
223
  } catch (cause) {
271
224
  historyItem.status = "rejected";
272
- const isTransient = errorIsFailure(cause);
225
+ const isTransient = errorIsTransient(cause);
273
226
  if (isTransient) historyItem = void 0;
274
227
  throw new CircuitError("CALL_FAILURE", { cause, isTransient });
275
228
  } finally {
@@ -381,21 +334,9 @@ function createCircuitBreaker(main, options = {}) {
381
334
  return wrapped;
382
335
  }
383
336
 
384
- const withRetry = deprecated(
385
- withRetry$1,
386
- "withRetry",
387
- "Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead."
388
- );
389
- const withTimeout = deprecated(
390
- withTimeout$1,
391
- "withTimeout",
392
- "Use `options.timeout` on`createCircuitBreaker` instead."
393
- );
394
-
337
+ exports.CircuitError = CircuitError;
395
338
  exports.createCircuitBreaker = createCircuitBreaker;
396
339
  exports.delayMs = delayMs;
397
340
  exports.useExponentialBackoff = useExponentialBackoff;
398
341
  exports.useFibonacciBackoff = useFibonacciBackoff;
399
- exports.withRetry = withRetry;
400
- exports.withTimeout = withTimeout;
401
342
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../lib/util.ts","../lib/retry.ts","../lib/timeout.ts","../lib/backoff.ts","../lib/options.ts","../lib/circuit-breaker.ts","../lib/index.ts"],"sourcesContent":["import type { AnyFn, RetryDelayFn } from \"./types.js\"\n\n/**\n * Returns a promise which rejects when the abort signal is triggered or\n * resolves when the promise is fulfilled.\n */\nexport const abortable = <T>(\n\tsignal: AbortSignal,\n\tpending: PromiseLike<T>,\n): Promise<T> =>\n\tnew Promise((resolve, reject) => {\n\t\tsignal.throwIfAborted()\n\n\t\tconst onAbort = () => reject(signal.reason)\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\n\t\tPromise.resolve(pending)\n\t\t\t.finally(() => signal.removeEventListener(\"abort\", onAbort))\n\t\t\t.then(resolve, reject)\n\t})\n\n/**\n * Asserts that the given value is truthy. If not, throws a `TypeError`.\n */\nexport function assert(value: unknown, message?: string): asserts value {\n\tif (!value) throw new TypeError(message)\n}\n\nexport class CircuitError extends Error {\n\tisTransient: boolean\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: unknown; isTransient?: boolean },\n\t) {\n\t\tsuper(`ERR_CIRCUIT_BREAKER_${message}`, options)\n\t\tthis.isTransient = options?.isTransient ?? false\n\t}\n}\n\n/**\n * Returns a promise that resolves after the specified number of milliseconds.\n */\nexport const delayMs = (ms: number, signal?: AbortSignal): Promise<void> => {\n\tif (!Number.isFinite(ms) || ms < 0) {\n\t\tthrow new RangeError(\n\t\t\t`\"ms\" must be a finite, non-negative number (received ${ms})`,\n\t\t)\n\t}\n\n\treturn signal\n\t\t? new Promise((resolve, reject) => {\n\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\tconst timer = setTimeout(() => {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort)\n\t\t\t\t\tresolve()\n\t\t\t\t}, ms)\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\treject(signal.reason)\n\t\t\t\t}\n\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\t\t\t})\n\t\t: new Promise((next) => setTimeout(next, ms))\n}\n\nexport const deprecated = <T extends AnyFn>(\n\tfn: T,\n\tmethod: string,\n\tmessage: string,\n): T => {\n\tlet warned = false\n\treturn ((...args) => {\n\t\tif (!warned) {\n\t\t\tconsole.warn(`[breaker-box] ${method} Deprecation: ${message}`)\n\t\t\twarned = true\n\t\t}\n\t\treturn fn(...args)\n\t}) as T\n}\n\nexport const identity = <T>(value: T): T => value\n\nexport const noop: (...args: unknown[]) => void = () => {}\n\n/**\n * Polyfill for `Promise.try()`\n */\nexport function promiseTry<T>(fn: () => T): Promise<T> {\n\ttry {\n\t\treturn Promise.resolve(fn())\n\t} catch (error) {\n\t\treturn Promise.reject(error)\n\t}\n}\n\nexport async function shouldContinue(options: {\n\tretries: number\n\tlastError: unknown\n\tretryDelay: number | RetryDelayFn\n\tretryLimit: number\n\tretryTest: (error: unknown) => boolean\n\tsignal: AbortSignal\n}): Promise<true> {\n\tconst { retries, lastError, retryDelay, retryLimit, retryTest, signal } =\n\t\toptions\n\n\tif (retries >= retryLimit)\n\t\tthrow new CircuitError(\"MAX_RETRIES\", { cause: lastError })\n\tif (!retryTest(lastError))\n\t\tthrow new CircuitError(\"NON_RETRYABLE\", { cause: lastError })\n\n\ttry {\n\t\tif (!retryDelay) return true\n\t\telse if (typeof retryDelay === \"number\") await delayMs(retryDelay, signal)\n\t\telse if (typeof retryDelay === \"function\") await retryDelay(retries, signal)\n\t} catch {\n\t\t/* empty */\n\t}\n\n\treturn true\n}\n","import { type MainFn, type RetryOptions } from \"./types.js\"\nimport { assert, abortable } from \"./util.js\"\n\n/**\n * Wrap a function with retry logic. Errors will be retried according to the\n * provided options.\n *\n * @example\n * ```ts\n * // Compose with circuit breaker. Retry up to 3 times with no delay\n * const protectedA = createCircuitBreaker(\n * withRetry(unreliableApiCall, { maxAttempts: 3 })\n * )\n *\n * // Retry up to 5 times with exponential backoff\n * const protectedB = createCircuitBreaker(\n * withRetry(unreliableApiCall, {\n * maxAttempts: 5,\n * retryDelay: useExponentialBackoff(30),\n * })\n * )\n * ```\n */\nexport function withRetry<Ret, Args extends readonly unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\toptions: Readonly<RetryOptions> = {},\n): MainFn<Ret, Args> & Disposable {\n\tconst {\n\t\tshouldRetry = () => true,\n\t\tmaxAttempts = 3,\n\t\tretryDelay = () => Promise.resolve(),\n\t} = options\n\n\tassert(maxAttempts >= 1, \"maxAttempts must be a number greater than 0\")\n\n\tconst controller = new AbortController()\n\tconst { signal } = controller\n\n\tasync function withRetryFunction(...args: Args): Promise<Ret> {\n\t\tlet attempt = 1\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\treturn await main(...args)\n\t\t\t} catch (cause) {\n\t\t\t\tif (attempt >= maxAttempts) {\n\t\t\t\t\tthrow new Error(`ERR_CIRCUIT_BREAKER_MAX_ATTEMPTS (${maxAttempts})`, {\n\t\t\t\t\t\tcause,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif (!shouldRetry(cause, attempt)) throw cause\n\t\t\t}\n\n\t\t\tattempt++\n\t\t\tawait abortable(signal, retryDelay(attempt, signal))\n\t\t}\n\t}\n\n\treturn Object.assign(withRetryFunction, {\n\t\t[Symbol.dispose]: () => controller.abort(),\n\t})\n}\n","import { type MainFn } from \"./types.js\"\nimport { abortable } from \"./util.js\"\n\n/**\n * Wraps an async function with a timeout constraint. Rejects with an Error if\n * execution exceeds the specified timeout.\n *\n * @example\n * ```ts\n * const fetchWithTimeout = withTimeout(fetchData, 5000, \"Fetch timed out\")\n * try {\n * const data = await fetchWithTimeout(url)\n * } catch (error) {\n * console.error(error.message) // \"Fetch timed out\" after 5 seconds\n * }\n * ```\n */\nexport function withTimeout<Ret, Args extends readonly unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\ttimeoutMs: number,\n\ttimeoutMessage = \"ERR_CIRCUIT_BREAKER_TIMEOUT\",\n): MainFn<Ret, Args> & Disposable {\n\tconst controller = new AbortController()\n\tconst { signal } = controller\n\n\tfunction withTimeoutFunction(...args: Args): Promise<Ret> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(reject, timeoutMs, new Error(timeoutMessage))\n\n\t\t\tabortable(signal, main(...args))\n\t\t\t\t.then(resolve, reject)\n\t\t\t\t.finally(() => clearTimeout(timer))\n\t\t})\n\t}\n\n\treturn Object.assign(withTimeoutFunction, {\n\t\t[Symbol.dispose]: () => controller.abort(),\n\t})\n}\n","import type { RetryDelayFn } from \"./types.js\"\nimport { delayMs } from \"./util.js\"\n\n/**\n * Creates an exponential backoff strategy for retry delays.\n * Delay grows as 2^(attempt-2) seconds, capped at maxSeconds.\n *\n * The sequence is: 1s, 2s, 4s, 8s, 16s, 32s, etc.\n *\n * @example\n * ```ts\n * const backoff = useExponentialBackoff(30)\n * await backoff(2) // waits 1 second\n * await backoff(3) // waits 2 seconds\n * await backoff(10) // waits 30 seconds (capped)\n * ```\n */\nexport function useExponentialBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function exponentialBackoff(attempt, signal) {\n\t\tconst num = Math.max(attempt - 2, 0)\n\t\tconst delay = Math.min(2 ** num, maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n\nconst sqrt5 = /* @__PURE__ */ Math.sqrt(5)\n/**\n * Binet's formula for calculating Fibonacci numbers in constant time.\n * @see https://en.wikipedia.org/wiki/Fibonacci_sequence#Closed-form_expression\n */\nconst binet = (n: number) =>\n\tMath.round(((1 + sqrt5) ** n - (1 - sqrt5) ** n) / (2 ** n * sqrt5))\n\n/**\n * Creates a Fibonacci backoff strategy for retry delays. It is more gradual\n * than exponential backoff, useful for more aggressive retry patterns.\n *\n * The sequence is: 1s, 2s, 3s, 5s, 8s, 13s, etc.\n *\n * @example\n * ```ts\n * const backoff = useFibonacciBackoff(60)\n * await backoff(2) // waits 1 second\n * await backoff(5) // waits 5 seconds\n * await backoff(10) // waits 55 seconds\n * ```\n */\nexport function useFibonacciBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function fibonacciBackoff(attempt, signal) {\n\t\tconst delay = Math.min(binet(attempt), maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n","import type { AnyFn, CircuitBreakerOptions } from \"./types.js\"\nimport { assert } from \"./util.js\"\n\nexport function parseOptions<Fallback extends AnyFn>(\n\toptions: CircuitBreakerOptions<Fallback>,\n) {\n\tconst {\n\t\terrorIsFailure = () => false,\n\t\terrorThreshold = 0,\n\t\terrorWindow = 10_000,\n\t\tfallback,\n\t\tminimumCandidates = 1,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter = 30_000,\n\t\tretryDelay = 0,\n\t\tretryLimit = Infinity,\n\t\tretryTest = () => true,\n\t\ttimeout = 0,\n\t} = options\n\n\t// errorIsFailure\n\tassert(\n\t\ttypeof errorIsFailure === \"function\",\n\t\t`\"errorIsFailure\" must be a function (received ${typeof errorIsFailure})`,\n\t)\n\n\t// errorThreshold\n\tassert(\n\t\terrorThreshold >= 0 && errorThreshold <= 1,\n\t\t`\"errorThreshold\" must be between 0 and 1 (received ${errorThreshold})`,\n\t)\n\n\t// errorWindow\n\tassert(\n\t\terrorWindow >= 1_000,\n\t\t`\"errorWindow\" must be milliseconds of at least 1 second (received ${errorWindow})`,\n\t)\n\n\t// (optional) fallback\n\tassert(\n\t\t!fallback || typeof fallback === \"function\",\n\t\t`\"fallback\" must be a function (received ${typeof fallback})`,\n\t)\n\n\t// minimumCandidates\n\tassert(\n\t\tminimumCandidates >= 1,\n\t\t`\"minimumCandidates\" must be greater than 0 (received ${minimumCandidates})`,\n\t)\n\n\t// (optional) onClose\n\tassert(\n\t\t!onClose || typeof onClose === \"function\",\n\t\t`\"onClose\" must be a function (received ${typeof onClose})`,\n\t)\n\n\t// (optional) onHalfOpen\n\tassert(\n\t\t!onHalfOpen || typeof onHalfOpen === \"function\",\n\t\t`\"onHalfOpen\" must be a function (received ${typeof onHalfOpen})`,\n\t)\n\n\t// (optional) onOpen\n\tassert(\n\t\t!onOpen || typeof onOpen === \"function\",\n\t\t`\"onOpen\" must be a function (received ${typeof onOpen})`,\n\t)\n\n\t// resetAfter\n\tassert(\n\t\tresetAfter >= 1_000,\n\t\t`\"resetAfter\" must be milliseconds of at least 1 second (received ${resetAfter})`,\n\t)\n\tassert(\n\t\tresetAfter >= errorWindow,\n\t\t`\"resetAfter\" must be greater than or equal to \"errorWindow\" (received ${resetAfter}, expected >= ${errorWindow})`,\n\t)\n\n\t// retryDelay\n\tassert(\n\t\ttypeof retryDelay === \"function\" ||\n\t\t\t(typeof retryDelay === \"number\" &&\n\t\t\t\tretryDelay >= 0 &&\n\t\t\t\tNumber.isFinite(retryDelay)),\n\t\t`\"retryDelay\" must be a function or a finite, non-negative number (received ${typeof retryDelay})`,\n\t)\n\n\t// retryLimit\n\tassert(\n\t\ttypeof retryLimit === \"number\" && retryLimit >= 1,\n\t\t`\"retryLimit\" must be greater than 0 (received ${retryLimit})`,\n\t)\n\n\t// retryTest\n\tassert(\n\t\ttypeof retryTest === \"function\",\n\t\t`\"retryTest\" must be a function (received ${typeof retryTest})`,\n\t)\n\n\t// timeout\n\tassert(\n\t\tNumber.isFinite(timeout) && timeout >= 0,\n\t\t`\"timeout\" must be a finite, non-negative number (received ${timeout})`,\n\t)\n\n\treturn {\n\t\terrorIsFailure,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t}\n}\n","import { parseOptions } from \"./options.js\"\nimport type {\n\tCircuitBreakerOptions,\n\tCircuitBreakerProtectedFn,\n\tHistoryEntry,\n\tHistoryMap,\n\tMainFn,\n\tStateName,\n} from \"./types.js\"\nimport {\n\tCircuitError,\n\tabortable,\n\tassert,\n\tdelayMs,\n\tnoop,\n\tpromiseTry,\n\tshouldContinue,\n} from \"./util.js\"\n\nconst validTransitions: Record<StateName, StateName[]> = {\n\tclosed: [\"open\", \"disposed\"],\n\topen: [\"halfOpen\", \"disposed\"],\n\thalfOpen: [\"closed\", \"open\", \"disposed\"],\n\tdisposed: [],\n}\n\nfunction assertTransition(from: StateName, to: StateName): void {\n\tassert(\n\t\tvalidTransitions[from].includes(to),\n\t\t`Invalid transition from ${from} to ${to}`,\n\t)\n}\n\ninterface CircuitInternalState<T extends StateName = StateName> {\n\tcontroller: AbortController\n\tfailureCause: unknown\n\tfailureRate: number\n\thistory: HistoryMap\n\tstatus: T\n}\n\nfunction createState(\n\tstatus: StateName,\n\tfailureCause?: unknown,\n): CircuitInternalState {\n\tconst controller = new AbortController()\n\treturn {\n\t\tcontroller,\n\t\tfailureCause,\n\t\tfailureRate: 0,\n\t\thistory: new Map(),\n\t\tstatus,\n\t}\n}\n\n/**\n * Creates a circuit breaker that wraps an async function with failure tracking\n * and automatic fallback behavior.\n *\n * The circuit breaker operates in four states:\n *\n * - `closed`: Normal operation, tracks failures in a sliding window\n * - `open`: Failed state, fallback is used until `resetAfter` milliseconds\n * - `halfOpen`: Testing recovery, allows trial calls\n * - `disposed`: Terminal state, all calls rejected\n *\n * When the failure rate exceeds `errorThreshold` within the `errorWindow`, the\n * circuit opens and rejects calls (using fallback if provided) for `resetAfter`\n * milliseconds. After this period, it transitions to half-open and allows up\n * to `minimumCandidates` concurrent trial calls. If their failure rate stays\n * at or below the threshold, the circuit closes; otherwise it reopens.\n *\n * @example\n * ```ts\n * const protectedFn = createCircuitBreaker(unreliableApiCall, {\n * errorThreshold: 0.5,\n * errorWindow: 10_000,\n * resetAfter: 30_000,\n * fallback: () => cachedResponse,\n * })\n *\n * try {\n * const result = await protectedFn(arg1, arg2)\n * } catch (error) {\n * console.error('Circuit breaker rejected call:', error)\n * }\n *\n * console.log(protectedFn.getState()) // 'closed' | 'open' | 'halfOpen' | 'disposed'\n * protectedFn[Symbol.dispose]() // Clean up timers and resources\n * ```\n */\nexport function createCircuitBreaker<Ret, Args extends unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\toptions: CircuitBreakerOptions<MainFn<Ret, Args>> = {},\n): CircuitBreakerProtectedFn<Ret, Args> {\n\tconst {\n\t\terrorIsFailure,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t} = parseOptions(options)\n\n\tlet state = createState(\"closed\")\n\n\tasync function tryCall(\n\t\tcurrent: CircuitInternalState,\n\t\targs: Args,\n\t): Promise<Ret> {\n\t\tconst { history } = current\n\t\tconst request = promiseTry(() => main(...args))\n\n\t\tlet historyItem: HistoryEntry | undefined = { status: \"pending\" }\n\t\thistory.set(request, historyItem)\n\n\t\ttry {\n\t\t\tconst result =\n\t\t\t\ttimeout > 0\n\t\t\t\t\t? await abortable(AbortSignal.timeout(timeout), request)\n\t\t\t\t\t: await request\n\t\t\thistoryItem.status = \"resolved\"\n\t\t\treturn result\n\t\t} catch (cause) {\n\t\t\thistoryItem.status = \"rejected\"\n\t\t\t// Drop this request if it's a transient error that shouldn't count\n\t\t\t// towards the failure rate\n\t\t\tconst isTransient = errorIsFailure(cause)\n\t\t\tif (isTransient) historyItem = undefined\n\n\t\t\t// Wrap the error in a CircuitError to provide additional context and\n\t\t\t// control flow handling.\n\t\t\tthrow new CircuitError(\"CALL_FAILURE\", { cause, isTransient })\n\t\t} finally {\n\t\t\t// Remove the request if it was a transient failure, or if it's stale.\n\t\t\tif (!historyItem || state !== current) history.delete(request)\n\t\t\t// Keep the request in history until the end of the error window, or until\n\t\t\t// the circuit transitions.\n\t\t\telse {\n\t\t\t\tconst { signal } = current.controller\n\t\t\t\tdelayMs(errorWindow, signal)\n\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t.finally(() => history.delete(request))\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction calculateFailureRate(): number {\n\t\tlet failures = 0\n\t\tlet total = 0\n\t\tfor (const { status } of state.history.values()) {\n\t\t\tif (status === \"rejected\") failures++\n\t\t\tif (status !== \"pending\") total++\n\t\t}\n\t\tif (!total || total < minimumCandidates) return 0\n\t\treturn failures / total\n\t}\n\n\tfunction transitionTo(\n\t\ttoStatus: StateName,\n\t\tfailureCause?: unknown,\n\t): CircuitInternalState {\n\t\tassertTransition(state.status, toStatus)\n\t\tstate.controller.abort()\n\t\treturn (state = createState(toStatus, failureCause))\n\t}\n\n\tasync function transitionToOpen(error: CircuitError): Promise<void> {\n\t\t// Race guard: a concurrent failure may have already changed state.\n\t\tif (state.status !== \"closed\" && state.status !== \"halfOpen\") return\n\n\t\tconst cause = error.cause ?? error\n\t\tconst nextState = transitionTo(\"open\", cause)\n\t\tif (onOpen) setImmediate(onOpen, cause)\n\n\t\tconst { signal } = nextState.controller\n\t\tawait delayMs(resetAfter, signal)\n\t\tif (state === nextState) transitionToHalfOpen()\n\t}\n\n\tfunction transitionToHalfOpen(): void {\n\t\ttransitionTo(\"halfOpen\", state.failureCause)\n\t\tif (onHalfOpen) setImmediate(onHalfOpen)\n\t}\n\n\tfunction transitionToClosed(): void {\n\t\ttransitionTo(\"closed\")\n\t\tif (onClose) setImmediate(onClose)\n\t}\n\n\tfunction guardIsCurrent(\n\t\tcurrent: CircuitInternalState,\n\t\terror: unknown,\n\t): error is CircuitError {\n\t\tif (!(error instanceof CircuitError)) throw error\n\t\t// Transient errors shouldn't affect the circuit breaker's state. Re-throw\n\t\t// the original cause of the error.\n\t\tif (error.isTransient) throw error.cause\n\n\t\t// If the circuit breaker was disposed mid-flight, surface the underlying\n\t\t// cause of the in-flight call rather than the dispose error.\n\t\tif (state.status === \"disposed\")\n\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\tthrow error.cause ?? new CircuitError(\"DISPOSED\")\n\n\t\t// If the circuit breaker transitioned states, try again.\n\t\treturn state === current\n\t}\n\n\tasync function protectedFn(...args: Args): Promise<Ret> {\n\t\tlet lastError: CircuitError | undefined\n\t\tlet retries = 0\n\t\tdo {\n\t\t\tconst current = state\n\t\t\tlastError = undefined\n\n\t\t\t// Closed: Normal Operation\n\t\t\tif (current.status === \"closed\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) {\n\t\t\t\t\t\tlastError = error\n\t\t\t\t\t\t// Determine if the failure rate should open the circuit.\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\tif (rate > errorThreshold) transitionToOpen(error).catch(noop)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Half-Open: Execute trial calls until we have enough candidates.\n\t\t\telse if (\n\t\t\t\tcurrent.status === \"halfOpen\" &&\n\t\t\t\tcurrent.history.size < minimumCandidates\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) lastError = error\n\t\t\t\t\tbreak\n\t\t\t\t} finally {\n\t\t\t\t\t// Do nothing until we have enough candidates to make a decision.\n\t\t\t\t\tif (state === current && current.history.size >= minimumCandidates) {\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\t// Determine if the failure rate should re-open the circuit or\n\t\t\t\t\t\t// if it is healthy enough to close it again.\n\t\t\t\t\t\tif (rate > errorThreshold && lastError)\n\t\t\t\t\t\t\ttransitionToOpen(lastError).catch(noop)\n\t\t\t\t\t\telse if (rate <= errorThreshold) transitionToClosed()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Open: Skip calls and immediately return fallback if available.\n\t\t\telse if (current.status === \"open\" || current.status === \"halfOpen\") {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Disposed: Reject all calls with dispose error.\n\t\t\telse throw current.failureCause\n\t\t} while (\n\t\t\tawait shouldContinue({\n\t\t\t\tretries: ++retries,\n\t\t\t\tlastError: lastError?.cause ?? lastError,\n\t\t\t\tretryDelay,\n\t\t\t\tretryLimit,\n\t\t\t\tretryTest,\n\t\t\t\tsignal: state.controller.signal,\n\t\t\t}).catch((error: CircuitError) => {\n\t\t\t\tlastError = error\n\t\t\t\treturn false\n\t\t\t})\n\t\t)\n\n\t\tif (!fallback) throw lastError ?? state.failureCause\n\t\treturn fallback(...args)\n\t}\n\n\tfunction dispose(disposeMessage = \"ERR_CIRCUIT_BREAKER_DISPOSED\"): void {\n\t\tif (state.status === \"disposed\") return\n\t\ttransitionTo(\"disposed\", new ReferenceError(disposeMessage))\n\t\tmain[Symbol.dispose]?.()\n\t}\n\n\tconst wrapped = protectedFn as CircuitBreakerProtectedFn<Ret, Args>\n\twrapped[Symbol.dispose] = () => dispose()\n\twrapped.dispose = dispose\n\twrapped.getFailureRate = () => state.failureRate\n\twrapped.getLatestError = () => state.failureCause\n\twrapped.getState = () => state.status\n\n\treturn wrapped\n}\n","import { withRetry as internalWithRetry } from \"./retry.js\"\nimport { withTimeout as internalWithTimeout } from \"./timeout.js\"\nimport type { StateName } from \"./types.js\"\n\nexport { useExponentialBackoff, useFibonacciBackoff } from \"./backoff.js\"\nexport { createCircuitBreaker } from \"./circuit-breaker.js\"\n\nexport type {\n\tCircuitBreakerOptions,\n\tCircuitBreakerProtectedFn,\n\tMainFn,\n\tRetryOptions,\n\tStateName,\n} from \"./types.js\"\nexport { delayMs } from \"./util.js\"\n\n// =============================================================================\n// Deprecated API properties\nimport { deprecated } from \"./util.js\"\n\n/** @deprecated Use `StateName` instead. */\nexport type CircuitState = StateName\n\n/** @deprecated Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead. */\nexport const withRetry = deprecated(\n\tinternalWithRetry,\n\t\"withRetry\",\n\t\"Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead.\",\n)\n\n/** @deprecated Use `options.timeout` on `createCircuitBreaker` instead. */\nexport const withTimeout = deprecated(\n\tinternalWithTimeout,\n\t\"withTimeout\",\n\t\"Use `options.timeout` on`createCircuitBreaker` instead.\",\n)\n"],"names":["withRetry","withTimeout","internalWithRetry","internalWithTimeout"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../lib/util.ts","../lib/backoff.ts","../lib/circuit-error.ts","../lib/options.ts","../lib/circuit-breaker.ts"],"sourcesContent":["\n/**\n * Returns a promise which rejects when the abort signal is triggered or\n * resolves when the promise is fulfilled.\n */\nexport const abortable = <T>(\n\tsignal: AbortSignal,\n\tpending: PromiseLike<T>,\n): Promise<T> =>\n\tnew Promise((resolve, reject) => {\n\t\tsignal.throwIfAborted()\n\n\t\tconst onAbort = () => reject(signal.reason)\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\n\t\tPromise.resolve(pending)\n\t\t\t.finally(() => signal.removeEventListener(\"abort\", onAbort))\n\t\t\t.then(resolve, reject)\n\t})\n\n/**\n * Asserts that the given value is truthy. If not, throws a `TypeError`.\n */\nexport function assert(value: unknown, message?: string): asserts value {\n\tif (!value) throw new TypeError(message)\n}\n\n/**\n * Returns a promise that resolves after the specified number of milliseconds.\n */\nexport const delayMs = (ms: number, signal?: AbortSignal): Promise<void> => {\n\tif (!Number.isFinite(ms) || ms < 0) {\n\t\tthrow new RangeError(\n\t\t\t`\"ms\" must be a finite, non-negative number (received ${ms})`,\n\t\t)\n\t}\n\n\treturn signal\n\t\t? new Promise((resolve, reject) => {\n\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\tconst timer = setTimeout(() => {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort)\n\t\t\t\t\tresolve()\n\t\t\t\t}, ms)\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\treject(signal.reason)\n\t\t\t\t}\n\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\t\t\t})\n\t\t: new Promise((next) => setTimeout(next, ms))\n}\n\nexport const noop: (...args: unknown[]) => void = () => {}\n\n/**\n * Polyfill for `Promise.try()`\n */\nexport function promiseTry<T>(fn: () => T): Promise<T> {\n\ttry {\n\t\treturn Promise.resolve(fn())\n\t} catch (error) {\n\t\treturn Promise.reject(error)\n\t}\n}\n\n\n","import type { RetryDelayFn } from \"./types.js\"\nimport { delayMs } from \"./util.js\"\n\n/**\n * Creates an exponential backoff strategy for retry delays.\n * Delay grows as 2^(attempt-2) seconds, capped at maxSeconds.\n *\n * The sequence is: 1s, 2s, 4s, 8s, 16s, 32s, etc.\n *\n * @example\n * ```ts\n * const backoff = useExponentialBackoff(30)\n * await backoff(2) // waits 1 second\n * await backoff(3) // waits 2 seconds\n * await backoff(10) // waits 30 seconds (capped)\n * ```\n */\nexport function useExponentialBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function exponentialBackoff(attempt, signal) {\n\t\tconst num = Math.max(attempt - 2, 0)\n\t\tconst delay = Math.min(2 ** num, maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n\nconst sqrt5 = /* @__PURE__ */ Math.sqrt(5)\n/**\n * Binet's formula for calculating Fibonacci numbers in constant time.\n * @see https://en.wikipedia.org/wiki/Fibonacci_sequence#Closed-form_expression\n */\nconst binet = (n: number) =>\n\tMath.round(((1 + sqrt5) ** n - (1 - sqrt5) ** n) / (2 ** n * sqrt5))\n\n/**\n * Creates a Fibonacci backoff strategy for retry delays. It is more gradual\n * than exponential backoff, useful for more aggressive retry patterns.\n *\n * The sequence is: 1s, 2s, 3s, 5s, 8s, 13s, etc.\n *\n * @example\n * ```ts\n * const backoff = useFibonacciBackoff(60)\n * await backoff(2) // waits 1 second\n * await backoff(5) // waits 5 seconds\n * await backoff(10) // waits 55 seconds\n * ```\n */\nexport function useFibonacciBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function fibonacciBackoff(attempt, signal) {\n\t\tconst delay = Math.min(binet(attempt), maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n","export class CircuitError extends Error {\n\tisTransient: boolean\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: unknown; isTransient?: boolean },\n\t) {\n\t\tsuper(`ERR_CIRCUIT_BREAKER_${message}`, options)\n\t\tthis.isTransient = options?.isTransient ?? false\n\t}\n}\n","import type { AnyFn, CircuitBreakerOptions } from \"./types.js\"\nimport { assert } from \"./util.js\"\n\nlet warnedErrorIsFailure = false\n\nexport function parseOptions<Fallback extends AnyFn>(\n\toptions: CircuitBreakerOptions<Fallback>,\n) {\n\tconst {\n\t\terrorIsTransient = options.errorIsFailure ?? (() => false),\n\t\terrorThreshold = 0,\n\t\terrorWindow = 10_000,\n\t\tfallback,\n\t\tminimumCandidates = 1,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter = 30_000,\n\t\tretryDelay = 0,\n\t\tretryLimit = Infinity,\n\t\tretryTest = () => true,\n\t\ttimeout = 0,\n\t} = options\n\n\tif (\n\t\t\"errorIsFailure\" in options &&\n\t\t!(\"errorIsTransient\" in options) &&\n\t\t!warnedErrorIsFailure\n\t) {\n\t\twarnedErrorIsFailure = true\n\t\tconsole.warn(\n\t\t\t'breaker-box: \"errorIsFailure\" is deprecated. Use \"errorIsTransient\" instead.',\n\t\t)\n\t}\n\n\t// errorIsTransient\n\tassert(\n\t\ttypeof errorIsTransient === \"function\",\n\t\t`\"errorIsTransient\" must be a function (received ${typeof errorIsTransient})`,\n\t)\n\n\t// errorThreshold\n\tassert(\n\t\terrorThreshold >= 0 && errorThreshold <= 1,\n\t\t`\"errorThreshold\" must be between 0 and 1 (received ${errorThreshold})`,\n\t)\n\n\t// errorWindow\n\tassert(\n\t\terrorWindow >= 1_000,\n\t\t`\"errorWindow\" must be milliseconds of at least 1 second (received ${errorWindow})`,\n\t)\n\n\t// (optional) fallback\n\tassert(\n\t\t!fallback || typeof fallback === \"function\",\n\t\t`\"fallback\" must be a function (received ${typeof fallback})`,\n\t)\n\n\t// minimumCandidates\n\tassert(\n\t\tminimumCandidates >= 1,\n\t\t`\"minimumCandidates\" must be greater than 0 (received ${minimumCandidates})`,\n\t)\n\n\t// (optional) onClose\n\tassert(\n\t\t!onClose || typeof onClose === \"function\",\n\t\t`\"onClose\" must be a function (received ${typeof onClose})`,\n\t)\n\n\t// (optional) onHalfOpen\n\tassert(\n\t\t!onHalfOpen || typeof onHalfOpen === \"function\",\n\t\t`\"onHalfOpen\" must be a function (received ${typeof onHalfOpen})`,\n\t)\n\n\t// (optional) onOpen\n\tassert(\n\t\t!onOpen || typeof onOpen === \"function\",\n\t\t`\"onOpen\" must be a function (received ${typeof onOpen})`,\n\t)\n\n\t// resetAfter\n\tassert(\n\t\tresetAfter >= 1_000,\n\t\t`\"resetAfter\" must be milliseconds of at least 1 second (received ${resetAfter})`,\n\t)\n\tassert(\n\t\tresetAfter >= errorWindow,\n\t\t`\"resetAfter\" must be greater than or equal to \"errorWindow\" (received ${resetAfter}, expected >= ${errorWindow})`,\n\t)\n\n\t// retryDelay\n\tassert(\n\t\ttypeof retryDelay === \"function\" ||\n\t\t\t(typeof retryDelay === \"number\" &&\n\t\t\t\tretryDelay >= 0 &&\n\t\t\t\tNumber.isFinite(retryDelay)),\n\t\t`\"retryDelay\" must be a function or a finite, non-negative number (received ${typeof retryDelay})`,\n\t)\n\n\t// retryLimit\n\tassert(\n\t\ttypeof retryLimit === \"number\" && retryLimit >= 1,\n\t\t`\"retryLimit\" must be greater than 0 (received ${retryLimit})`,\n\t)\n\n\t// retryTest\n\tassert(\n\t\ttypeof retryTest === \"function\",\n\t\t`\"retryTest\" must be a function (received ${typeof retryTest})`,\n\t)\n\n\t// timeout\n\tassert(\n\t\tNumber.isFinite(timeout) && timeout >= 0,\n\t\t`\"timeout\" must be a finite, non-negative number (received ${timeout})`,\n\t)\n\n\treturn {\n\t\terrorIsTransient,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t}\n}\n","import { parseOptions } from \"./options.js\"\nimport type {\n\tCircuitBreakerOptions,\n\tCircuitBreakerProtectedFn,\n\tHistoryEntry,\n\tHistoryMap,\n\tMainFn,\n\tRetryDelayFn,\n\tStateName,\n} from \"./types.js\"\nimport { CircuitError } from \"./circuit-error.js\"\nimport {\n\tabortable,\n\tassert,\n\tdelayMs,\n\tnoop,\n\tpromiseTry,\n} from \"./util.js\"\n\nasync function shouldContinue(options: {\n\tretries: number\n\tlastError: unknown\n\tretryDelay: number | RetryDelayFn\n\tretryLimit: number\n\tretryTest: (error: unknown) => boolean\n\tsignal: AbortSignal\n}): Promise<true> {\n\tconst { retries, lastError, retryDelay, retryLimit, retryTest, signal } =\n\t\toptions\n\n\tif (retries >= retryLimit)\n\t\tthrow new CircuitError(\"MAX_RETRIES\", { cause: lastError })\n\tif (!retryTest(lastError))\n\t\tthrow new CircuitError(\"NON_RETRYABLE\", { cause: lastError })\n\n\ttry {\n\t\tif (!retryDelay) return true\n\t\telse if (typeof retryDelay === \"number\") await delayMs(retryDelay, signal)\n\t\telse if (typeof retryDelay === \"function\") await retryDelay(retries, signal)\n\t} catch {\n\t\t/* empty */\n\t}\n\n\treturn true\n}\n\nconst validTransitions: Record<StateName, StateName[]> = {\n\tclosed: [\"open\", \"disposed\"],\n\topen: [\"halfOpen\", \"disposed\"],\n\thalfOpen: [\"closed\", \"open\", \"disposed\"],\n\tdisposed: [],\n}\n\nfunction assertTransition(from: StateName, to: StateName): void {\n\tassert(\n\t\tvalidTransitions[from].includes(to),\n\t\t`Invalid transition from ${from} to ${to}`,\n\t)\n}\n\ninterface CircuitInternalState<T extends StateName = StateName> {\n\tcontroller: AbortController\n\tfailureCause: unknown\n\tfailureRate: number\n\thistory: HistoryMap\n\tstatus: T\n}\n\nfunction createState(\n\tstatus: StateName,\n\tfailureCause?: unknown,\n): CircuitInternalState {\n\tconst controller = new AbortController()\n\treturn {\n\t\tcontroller,\n\t\tfailureCause,\n\t\tfailureRate: 0,\n\t\thistory: new Map(),\n\t\tstatus,\n\t}\n}\n\n/**\n * Creates a circuit breaker that wraps an async function with failure tracking\n * and automatic fallback behavior.\n *\n * The circuit breaker operates in four states:\n *\n * - `closed`: Normal operation, tracks failures in a sliding window\n * - `open`: Failed state, fallback is used until `resetAfter` milliseconds\n * - `halfOpen`: Testing recovery, allows trial calls\n * - `disposed`: Terminal state, all calls rejected\n *\n * When the failure rate exceeds `errorThreshold` within the `errorWindow`, the\n * circuit opens and rejects calls (using fallback if provided) for `resetAfter`\n * milliseconds. After this period, it transitions to half-open and allows up\n * to `minimumCandidates` concurrent trial calls. If their failure rate stays\n * at or below the threshold, the circuit closes; otherwise it reopens.\n *\n * @example\n * ```ts\n * const protectedFn = createCircuitBreaker(unreliableApiCall, {\n * errorThreshold: 0.5,\n * errorWindow: 10_000,\n * resetAfter: 30_000,\n * fallback: () => cachedResponse,\n * })\n *\n * try {\n * const result = await protectedFn(arg1, arg2)\n * } catch (error) {\n * console.error('Circuit breaker rejected call:', error)\n * }\n *\n * console.log(protectedFn.getState()) // 'closed' | 'open' | 'halfOpen' | 'disposed'\n * protectedFn[Symbol.dispose]() // Clean up timers and resources\n * ```\n */\nexport function createCircuitBreaker<Ret, Args extends unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\toptions: CircuitBreakerOptions<MainFn<Ret, Args>> = {},\n): CircuitBreakerProtectedFn<Ret, Args> {\n\tconst {\n\t\terrorIsTransient,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t} = parseOptions(options)\n\n\tlet state = createState(\"closed\")\n\n\tasync function tryCall(\n\t\tcurrent: CircuitInternalState,\n\t\targs: Args,\n\t): Promise<Ret> {\n\t\tconst { history } = current\n\t\tconst request = promiseTry(() => main(...args))\n\n\t\tlet historyItem: HistoryEntry | undefined = { status: \"pending\" }\n\t\thistory.set(request, historyItem)\n\n\t\ttry {\n\t\t\tconst result =\n\t\t\t\ttimeout > 0\n\t\t\t\t\t? await abortable(AbortSignal.timeout(timeout), request)\n\t\t\t\t\t: await request\n\t\t\thistoryItem.status = \"resolved\"\n\t\t\treturn result\n\t\t} catch (cause) {\n\t\t\thistoryItem.status = \"rejected\"\n\t\t\t// Drop this request if it's a transient error that shouldn't count\n\t\t\t// towards the failure rate\n\t\t\tconst isTransient = errorIsTransient(cause)\n\t\t\tif (isTransient) historyItem = undefined\n\n\t\t\t// Wrap the error in a CircuitError to provide additional context and\n\t\t\t// control flow handling.\n\t\t\tthrow new CircuitError(\"CALL_FAILURE\", { cause, isTransient })\n\t\t} finally {\n\t\t\t// Remove the request if it was a transient failure, or if it's stale.\n\t\t\tif (!historyItem || state !== current) history.delete(request)\n\t\t\t// Keep the request in history until the end of the error window, or until\n\t\t\t// the circuit transitions.\n\t\t\telse {\n\t\t\t\tconst { signal } = current.controller\n\t\t\t\tdelayMs(errorWindow, signal)\n\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t.finally(() => history.delete(request))\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction calculateFailureRate(): number {\n\t\tlet failures = 0\n\t\tlet total = 0\n\t\tfor (const { status } of state.history.values()) {\n\t\t\tif (status === \"rejected\") failures++\n\t\t\tif (status !== \"pending\") total++\n\t\t}\n\t\tif (!total || total < minimumCandidates) return 0\n\t\treturn failures / total\n\t}\n\n\tfunction transitionTo(\n\t\ttoStatus: StateName,\n\t\tfailureCause?: unknown,\n\t): CircuitInternalState {\n\t\tassertTransition(state.status, toStatus)\n\t\tstate.controller.abort()\n\t\treturn (state = createState(toStatus, failureCause))\n\t}\n\n\tasync function transitionToOpen(error: CircuitError): Promise<void> {\n\t\t// Race guard: a concurrent failure may have already changed state.\n\t\tif (state.status !== \"closed\" && state.status !== \"halfOpen\") return\n\n\t\tconst cause = error.cause ?? error\n\t\tconst nextState = transitionTo(\"open\", cause)\n\t\tif (onOpen) setImmediate(onOpen, cause)\n\n\t\tconst { signal } = nextState.controller\n\t\tawait delayMs(resetAfter, signal)\n\t\tif (state === nextState) transitionToHalfOpen()\n\t}\n\n\tfunction transitionToHalfOpen(): void {\n\t\ttransitionTo(\"halfOpen\", state.failureCause)\n\t\tif (onHalfOpen) setImmediate(onHalfOpen)\n\t}\n\n\tfunction transitionToClosed(): void {\n\t\ttransitionTo(\"closed\")\n\t\tif (onClose) setImmediate(onClose)\n\t}\n\n\tfunction guardIsCurrent(\n\t\tcurrent: CircuitInternalState,\n\t\terror: unknown,\n\t): error is CircuitError {\n\t\tif (!(error instanceof CircuitError)) throw error\n\t\t// Transient errors shouldn't affect the circuit breaker's state. Re-throw\n\t\t// the original cause of the error.\n\t\tif (error.isTransient) throw error.cause\n\n\t\t// If the circuit breaker was disposed mid-flight, surface the underlying\n\t\t// cause of the in-flight call rather than the dispose error.\n\t\tif (state.status === \"disposed\")\n\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\tthrow error.cause ?? new CircuitError(\"DISPOSED\")\n\n\t\t// If the circuit breaker transitioned states, try again.\n\t\treturn state === current\n\t}\n\n\tasync function protectedFn(...args: Args): Promise<Ret> {\n\t\tlet lastError: CircuitError | undefined\n\t\tlet retries = 0\n\t\tdo {\n\t\t\tconst current = state\n\t\t\tlastError = undefined\n\n\t\t\t// Closed: Normal Operation\n\t\t\tif (current.status === \"closed\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) {\n\t\t\t\t\t\tlastError = error\n\t\t\t\t\t\t// Determine if the failure rate should open the circuit.\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\tif (rate > errorThreshold) transitionToOpen(error).catch(noop)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Half-Open: Execute trial calls until we have enough candidates.\n\t\t\telse if (\n\t\t\t\tcurrent.status === \"halfOpen\" &&\n\t\t\t\tcurrent.history.size < minimumCandidates\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) lastError = error\n\t\t\t\t\tbreak\n\t\t\t\t} finally {\n\t\t\t\t\t// Do nothing until we have enough candidates to make a decision.\n\t\t\t\t\tif (state === current && current.history.size >= minimumCandidates) {\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\t// Determine if the failure rate should re-open the circuit or\n\t\t\t\t\t\t// if it is healthy enough to close it again.\n\t\t\t\t\t\tif (rate > errorThreshold && lastError)\n\t\t\t\t\t\t\ttransitionToOpen(lastError).catch(noop)\n\t\t\t\t\t\telse if (rate <= errorThreshold) transitionToClosed()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Open: Skip calls and immediately return fallback if available.\n\t\t\telse if (current.status === \"open\" || current.status === \"halfOpen\") {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Disposed: Reject all calls with dispose error.\n\t\t\telse throw current.failureCause\n\t\t} while (\n\t\t\tawait shouldContinue({\n\t\t\t\tretries: ++retries,\n\t\t\t\tlastError: lastError?.cause ?? lastError,\n\t\t\t\tretryDelay,\n\t\t\t\tretryLimit,\n\t\t\t\tretryTest,\n\t\t\t\tsignal: state.controller.signal,\n\t\t\t}).catch((error: CircuitError) => {\n\t\t\t\tlastError = error\n\t\t\t\treturn false\n\t\t\t})\n\t\t)\n\n\t\tif (!fallback) throw lastError ?? state.failureCause\n\t\treturn fallback(...args)\n\t}\n\n\tfunction dispose(disposeMessage = \"ERR_CIRCUIT_BREAKER_DISPOSED\"): void {\n\t\tif (state.status === \"disposed\") return\n\t\ttransitionTo(\"disposed\", new ReferenceError(disposeMessage))\n\t\tmain[Symbol.dispose]?.()\n\t}\n\n\tconst wrapped = protectedFn as CircuitBreakerProtectedFn<Ret, Args>\n\twrapped[Symbol.dispose] = () => dispose()\n\twrapped.dispose = dispose\n\twrapped.getFailureRate = () => state.failureRate\n\twrapped.getLatestError = () => state.failureCause\n\twrapped.getState = () => state.status\n\n\treturn wrapped\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -14,13 +14,16 @@ type StateName = "closed" | "halfOpen" | "open" | "disposed";
14
14
  */
15
15
  interface CircuitBreakerOptions<Fallback extends AnyFn = AnyFn> {
16
16
  /**
17
- * Whether an error should be treated as non-retryable failure. When used and
18
- * when an error is considered a failure, the error will be thrown to the
19
- * caller and the request will *not* count tawards the error rate for circuit
20
- * breaker decisions.
17
+ * When this returns true, the error is treated as transient it will be
18
+ * thrown to the caller but will NOT count towards the circuit breaker's
19
+ * failure rate.
21
20
  *
22
21
  * @default () => false // No errors are excluded
23
22
  */
23
+ errorIsTransient?: ErrorTest;
24
+ /**
25
+ * @deprecated Use `errorIsTransient` instead.
26
+ */
24
27
  errorIsFailure?: ErrorTest;
25
28
  /**
26
29
  * The percentage of errors (as a number between 0 and 1) which must occur
@@ -104,7 +107,7 @@ interface CircuitBreakerOptions<Fallback extends AnyFn = AnyFn> {
104
107
  * If greater than zero, each call to `main` is raced against an
105
108
  * `AbortSignal.timeout` of this many milliseconds. When the timeout fires
106
109
  * first, the call rejects with the signal's reason and is counted as a
107
- * failure (subject to `errorIsFailure`).
110
+ * failure (subject to `errorIsTransient`).
108
111
  *
109
112
  * @default 0 // No per-call timeout
110
113
  */
@@ -139,69 +142,6 @@ interface MainFn<Ret = unknown, Args extends readonly unknown[] = never[]> {
139
142
  interface RetryDelayFn {
140
143
  (attempt: number, signal?: AbortSignal): Promise<void>;
141
144
  }
142
- /**
143
- * Configuration options for retry behavior.
144
- */
145
- interface RetryOptions {
146
- /**
147
- * Whether an error should be treated as non-retryable. When this returns
148
- * true, the error will be thrown immediately without retrying.
149
- *
150
- * @default () => true // All errors are retried
151
- */
152
- shouldRetry?: (error: unknown, attempt: number) => boolean;
153
- /**
154
- * Maximum number of retries
155
- *
156
- * @default 3
157
- */
158
- maxAttempts?: number;
159
- /**
160
- * Function that returns a promise resolving when the next retry should occur.
161
- * Receives the attempt number (starting at 2) and an abort signal.
162
- *
163
- * @default () => Promise.resolve() // Immediate retry
164
- */
165
- retryDelay?: RetryDelayFn;
166
- }
167
-
168
- /**
169
- * Wrap a function with retry logic. Errors will be retried according to the
170
- * provided options.
171
- *
172
- * @example
173
- * ```ts
174
- * // Compose with circuit breaker. Retry up to 3 times with no delay
175
- * const protectedA = createCircuitBreaker(
176
- * withRetry(unreliableApiCall, { maxAttempts: 3 })
177
- * )
178
- *
179
- * // Retry up to 5 times with exponential backoff
180
- * const protectedB = createCircuitBreaker(
181
- * withRetry(unreliableApiCall, {
182
- * maxAttempts: 5,
183
- * retryDelay: useExponentialBackoff(30),
184
- * })
185
- * )
186
- * ```
187
- */
188
- declare function withRetry$1<Ret, Args extends readonly unknown[]>(main: MainFn<Ret, Args>, options?: Readonly<RetryOptions>): MainFn<Ret, Args> & Disposable;
189
-
190
- /**
191
- * Wraps an async function with a timeout constraint. Rejects with an Error if
192
- * execution exceeds the specified timeout.
193
- *
194
- * @example
195
- * ```ts
196
- * const fetchWithTimeout = withTimeout(fetchData, 5000, "Fetch timed out")
197
- * try {
198
- * const data = await fetchWithTimeout(url)
199
- * } catch (error) {
200
- * console.error(error.message) // "Fetch timed out" after 5 seconds
201
- * }
202
- * ```
203
- */
204
- declare function withTimeout$1<Ret, Args extends readonly unknown[]>(main: MainFn<Ret, Args>, timeoutMs: number, timeoutMessage?: string): MainFn<Ret, Args> & Disposable;
205
145
 
206
146
  /**
207
147
  * Creates an exponential backoff strategy for retry delays.
@@ -234,6 +174,14 @@ declare function useExponentialBackoff(maxSeconds: number): RetryDelayFn;
234
174
  */
235
175
  declare function useFibonacciBackoff(maxSeconds: number): RetryDelayFn;
236
176
 
177
+ declare class CircuitError extends Error {
178
+ isTransient: boolean;
179
+ constructor(message: string, options?: {
180
+ cause?: unknown;
181
+ isTransient?: boolean;
182
+ });
183
+ }
184
+
237
185
  /**
238
186
  * Creates a circuit breaker that wraps an async function with failure tracking
239
187
  * and automatic fallback behavior.
@@ -277,12 +225,5 @@ declare function createCircuitBreaker<Ret, Args extends unknown[]>(main: MainFn<
277
225
  */
278
226
  declare const delayMs: (ms: number, signal?: AbortSignal) => Promise<void>;
279
227
 
280
- /** @deprecated Use `StateName` instead. */
281
- type CircuitState = StateName;
282
- /** @deprecated Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead. */
283
- declare const withRetry: typeof withRetry$1;
284
- /** @deprecated Use `options.timeout` on `createCircuitBreaker` instead. */
285
- declare const withTimeout: typeof withTimeout$1;
286
-
287
- export { createCircuitBreaker, delayMs, useExponentialBackoff, useFibonacciBackoff, withRetry, withTimeout };
288
- export type { CircuitBreakerOptions, CircuitBreakerProtectedFn, CircuitState, MainFn, RetryOptions, StateName };
228
+ export { CircuitError, createCircuitBreaker, delayMs, useExponentialBackoff, useFibonacciBackoff };
229
+ export type { CircuitBreakerOptions, CircuitBreakerProtectedFn, MainFn, StateName };
package/dist/index.d.mts CHANGED
@@ -14,13 +14,16 @@ type StateName = "closed" | "halfOpen" | "open" | "disposed";
14
14
  */
15
15
  interface CircuitBreakerOptions<Fallback extends AnyFn = AnyFn> {
16
16
  /**
17
- * Whether an error should be treated as non-retryable failure. When used and
18
- * when an error is considered a failure, the error will be thrown to the
19
- * caller and the request will *not* count tawards the error rate for circuit
20
- * breaker decisions.
17
+ * When this returns true, the error is treated as transient it will be
18
+ * thrown to the caller but will NOT count towards the circuit breaker's
19
+ * failure rate.
21
20
  *
22
21
  * @default () => false // No errors are excluded
23
22
  */
23
+ errorIsTransient?: ErrorTest;
24
+ /**
25
+ * @deprecated Use `errorIsTransient` instead.
26
+ */
24
27
  errorIsFailure?: ErrorTest;
25
28
  /**
26
29
  * The percentage of errors (as a number between 0 and 1) which must occur
@@ -104,7 +107,7 @@ interface CircuitBreakerOptions<Fallback extends AnyFn = AnyFn> {
104
107
  * If greater than zero, each call to `main` is raced against an
105
108
  * `AbortSignal.timeout` of this many milliseconds. When the timeout fires
106
109
  * first, the call rejects with the signal's reason and is counted as a
107
- * failure (subject to `errorIsFailure`).
110
+ * failure (subject to `errorIsTransient`).
108
111
  *
109
112
  * @default 0 // No per-call timeout
110
113
  */
@@ -139,69 +142,6 @@ interface MainFn<Ret = unknown, Args extends readonly unknown[] = never[]> {
139
142
  interface RetryDelayFn {
140
143
  (attempt: number, signal?: AbortSignal): Promise<void>;
141
144
  }
142
- /**
143
- * Configuration options for retry behavior.
144
- */
145
- interface RetryOptions {
146
- /**
147
- * Whether an error should be treated as non-retryable. When this returns
148
- * true, the error will be thrown immediately without retrying.
149
- *
150
- * @default () => true // All errors are retried
151
- */
152
- shouldRetry?: (error: unknown, attempt: number) => boolean;
153
- /**
154
- * Maximum number of retries
155
- *
156
- * @default 3
157
- */
158
- maxAttempts?: number;
159
- /**
160
- * Function that returns a promise resolving when the next retry should occur.
161
- * Receives the attempt number (starting at 2) and an abort signal.
162
- *
163
- * @default () => Promise.resolve() // Immediate retry
164
- */
165
- retryDelay?: RetryDelayFn;
166
- }
167
-
168
- /**
169
- * Wrap a function with retry logic. Errors will be retried according to the
170
- * provided options.
171
- *
172
- * @example
173
- * ```ts
174
- * // Compose with circuit breaker. Retry up to 3 times with no delay
175
- * const protectedA = createCircuitBreaker(
176
- * withRetry(unreliableApiCall, { maxAttempts: 3 })
177
- * )
178
- *
179
- * // Retry up to 5 times with exponential backoff
180
- * const protectedB = createCircuitBreaker(
181
- * withRetry(unreliableApiCall, {
182
- * maxAttempts: 5,
183
- * retryDelay: useExponentialBackoff(30),
184
- * })
185
- * )
186
- * ```
187
- */
188
- declare function withRetry$1<Ret, Args extends readonly unknown[]>(main: MainFn<Ret, Args>, options?: Readonly<RetryOptions>): MainFn<Ret, Args> & Disposable;
189
-
190
- /**
191
- * Wraps an async function with a timeout constraint. Rejects with an Error if
192
- * execution exceeds the specified timeout.
193
- *
194
- * @example
195
- * ```ts
196
- * const fetchWithTimeout = withTimeout(fetchData, 5000, "Fetch timed out")
197
- * try {
198
- * const data = await fetchWithTimeout(url)
199
- * } catch (error) {
200
- * console.error(error.message) // "Fetch timed out" after 5 seconds
201
- * }
202
- * ```
203
- */
204
- declare function withTimeout$1<Ret, Args extends readonly unknown[]>(main: MainFn<Ret, Args>, timeoutMs: number, timeoutMessage?: string): MainFn<Ret, Args> & Disposable;
205
145
 
206
146
  /**
207
147
  * Creates an exponential backoff strategy for retry delays.
@@ -234,6 +174,14 @@ declare function useExponentialBackoff(maxSeconds: number): RetryDelayFn;
234
174
  */
235
175
  declare function useFibonacciBackoff(maxSeconds: number): RetryDelayFn;
236
176
 
177
+ declare class CircuitError extends Error {
178
+ isTransient: boolean;
179
+ constructor(message: string, options?: {
180
+ cause?: unknown;
181
+ isTransient?: boolean;
182
+ });
183
+ }
184
+
237
185
  /**
238
186
  * Creates a circuit breaker that wraps an async function with failure tracking
239
187
  * and automatic fallback behavior.
@@ -277,12 +225,5 @@ declare function createCircuitBreaker<Ret, Args extends unknown[]>(main: MainFn<
277
225
  */
278
226
  declare const delayMs: (ms: number, signal?: AbortSignal) => Promise<void>;
279
227
 
280
- /** @deprecated Use `StateName` instead. */
281
- type CircuitState = StateName;
282
- /** @deprecated Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead. */
283
- declare const withRetry: typeof withRetry$1;
284
- /** @deprecated Use `options.timeout` on `createCircuitBreaker` instead. */
285
- declare const withTimeout: typeof withTimeout$1;
286
-
287
- export { createCircuitBreaker, delayMs, useExponentialBackoff, useFibonacciBackoff, withRetry, withTimeout };
288
- export type { CircuitBreakerOptions, CircuitBreakerProtectedFn, CircuitState, MainFn, RetryOptions, StateName };
228
+ export { CircuitError, createCircuitBreaker, delayMs, useExponentialBackoff, useFibonacciBackoff };
229
+ export type { CircuitBreakerOptions, CircuitBreakerProtectedFn, MainFn, StateName };
package/dist/index.mjs CHANGED
@@ -7,13 +7,6 @@ const abortable = (signal, pending) => new Promise((resolve, reject) => {
7
7
  function assert(value, message) {
8
8
  if (!value) throw new TypeError(message);
9
9
  }
10
- class CircuitError extends Error {
11
- isTransient;
12
- constructor(message, options) {
13
- super(`ERR_CIRCUIT_BREAKER_${message}`, options);
14
- this.isTransient = options?.isTransient ?? false;
15
- }
16
- }
17
10
  const delayMs = (ms, signal) => {
18
11
  if (!Number.isFinite(ms) || ms < 0) {
19
12
  throw new RangeError(
@@ -33,16 +26,6 @@ const delayMs = (ms, signal) => {
33
26
  signal.addEventListener("abort", onAbort, { once: true });
34
27
  }) : new Promise((next) => setTimeout(next, ms));
35
28
  };
36
- const deprecated = (fn, method, message) => {
37
- let warned = false;
38
- return ((...args) => {
39
- if (!warned) {
40
- console.warn(`[breaker-box] ${method} Deprecation: ${message}`);
41
- warned = true;
42
- }
43
- return fn(...args);
44
- });
45
- };
46
29
  const noop = () => {
47
30
  };
48
31
  function promiseTry(fn) {
@@ -52,65 +35,6 @@ function promiseTry(fn) {
52
35
  return Promise.reject(error);
53
36
  }
54
37
  }
55
- async function shouldContinue(options) {
56
- const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
57
- if (retries >= retryLimit)
58
- throw new CircuitError("MAX_RETRIES", { cause: lastError });
59
- if (!retryTest(lastError))
60
- throw new CircuitError("NON_RETRYABLE", { cause: lastError });
61
- try {
62
- if (!retryDelay) return true;
63
- else if (typeof retryDelay === "number") await delayMs(retryDelay, signal);
64
- else if (typeof retryDelay === "function") await retryDelay(retries, signal);
65
- } catch {
66
- }
67
- return true;
68
- }
69
-
70
- function withRetry$1(main, options = {}) {
71
- const {
72
- shouldRetry = () => true,
73
- maxAttempts = 3,
74
- retryDelay = () => Promise.resolve()
75
- } = options;
76
- assert(maxAttempts >= 1, "maxAttempts must be a number greater than 0");
77
- const controller = new AbortController();
78
- const { signal } = controller;
79
- async function withRetryFunction(...args) {
80
- let attempt = 1;
81
- while (true) {
82
- try {
83
- return await main(...args);
84
- } catch (cause) {
85
- if (attempt >= maxAttempts) {
86
- throw new Error(`ERR_CIRCUIT_BREAKER_MAX_ATTEMPTS (${maxAttempts})`, {
87
- cause
88
- });
89
- }
90
- if (!shouldRetry(cause, attempt)) throw cause;
91
- }
92
- attempt++;
93
- await abortable(signal, retryDelay(attempt, signal));
94
- }
95
- }
96
- return Object.assign(withRetryFunction, {
97
- [Symbol.dispose]: () => controller.abort()
98
- });
99
- }
100
-
101
- function withTimeout$1(main, timeoutMs, timeoutMessage = "ERR_CIRCUIT_BREAKER_TIMEOUT") {
102
- const controller = new AbortController();
103
- const { signal } = controller;
104
- function withTimeoutFunction(...args) {
105
- return new Promise((resolve, reject) => {
106
- const timer = setTimeout(reject, timeoutMs, new Error(timeoutMessage));
107
- abortable(signal, main(...args)).then(resolve, reject).finally(() => clearTimeout(timer));
108
- });
109
- }
110
- return Object.assign(withTimeoutFunction, {
111
- [Symbol.dispose]: () => controller.abort()
112
- });
113
- }
114
38
 
115
39
  function useExponentialBackoff(maxSeconds) {
116
40
  return function exponentialBackoff(attempt, signal) {
@@ -128,9 +52,18 @@ function useFibonacciBackoff(maxSeconds) {
128
52
  };
129
53
  }
130
54
 
55
+ class CircuitError extends Error {
56
+ isTransient;
57
+ constructor(message, options) {
58
+ super(`ERR_CIRCUIT_BREAKER_${message}`, options);
59
+ this.isTransient = options?.isTransient ?? false;
60
+ }
61
+ }
62
+
63
+ let warnedErrorIsFailure = false;
131
64
  function parseOptions(options) {
132
65
  const {
133
- errorIsFailure = () => false,
66
+ errorIsTransient = options.errorIsFailure ?? (() => false),
134
67
  errorThreshold = 0,
135
68
  errorWindow = 1e4,
136
69
  fallback,
@@ -144,9 +77,15 @@ function parseOptions(options) {
144
77
  retryTest = () => true,
145
78
  timeout = 0
146
79
  } = options;
80
+ if ("errorIsFailure" in options && !("errorIsTransient" in options) && !warnedErrorIsFailure) {
81
+ warnedErrorIsFailure = true;
82
+ console.warn(
83
+ 'breaker-box: "errorIsFailure" is deprecated. Use "errorIsTransient" instead.'
84
+ );
85
+ }
147
86
  assert(
148
- typeof errorIsFailure === "function",
149
- `"errorIsFailure" must be a function (received ${typeof errorIsFailure})`
87
+ typeof errorIsTransient === "function",
88
+ `"errorIsTransient" must be a function (received ${typeof errorIsTransient})`
150
89
  );
151
90
  assert(
152
91
  errorThreshold >= 0 && errorThreshold <= 1,
@@ -201,7 +140,7 @@ function parseOptions(options) {
201
140
  `"timeout" must be a finite, non-negative number (received ${timeout})`
202
141
  );
203
142
  return {
204
- errorIsFailure,
143
+ errorIsTransient,
205
144
  errorThreshold,
206
145
  errorWindow,
207
146
  fallback,
@@ -217,6 +156,20 @@ function parseOptions(options) {
217
156
  };
218
157
  }
219
158
 
159
+ async function shouldContinue(options) {
160
+ const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
161
+ if (retries >= retryLimit)
162
+ throw new CircuitError("MAX_RETRIES", { cause: lastError });
163
+ if (!retryTest(lastError))
164
+ throw new CircuitError("NON_RETRYABLE", { cause: lastError });
165
+ try {
166
+ if (!retryDelay) return true;
167
+ else if (typeof retryDelay === "number") await delayMs(retryDelay, signal);
168
+ else if (typeof retryDelay === "function") await retryDelay(retries, signal);
169
+ } catch {
170
+ }
171
+ return true;
172
+ }
220
173
  const validTransitions = {
221
174
  closed: ["open", "disposed"],
222
175
  open: ["halfOpen", "disposed"],
@@ -241,7 +194,7 @@ function createState(status, failureCause) {
241
194
  }
242
195
  function createCircuitBreaker(main, options = {}) {
243
196
  const {
244
- errorIsFailure,
197
+ errorIsTransient,
245
198
  errorThreshold,
246
199
  errorWindow,
247
200
  fallback,
@@ -267,7 +220,7 @@ function createCircuitBreaker(main, options = {}) {
267
220
  return result;
268
221
  } catch (cause) {
269
222
  historyItem.status = "rejected";
270
- const isTransient = errorIsFailure(cause);
223
+ const isTransient = errorIsTransient(cause);
271
224
  if (isTransient) historyItem = void 0;
272
225
  throw new CircuitError("CALL_FAILURE", { cause, isTransient });
273
226
  } finally {
@@ -379,16 +332,5 @@ function createCircuitBreaker(main, options = {}) {
379
332
  return wrapped;
380
333
  }
381
334
 
382
- const withRetry = deprecated(
383
- withRetry$1,
384
- "withRetry",
385
- "Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead."
386
- );
387
- const withTimeout = deprecated(
388
- withTimeout$1,
389
- "withTimeout",
390
- "Use `options.timeout` on`createCircuitBreaker` instead."
391
- );
392
-
393
- export { createCircuitBreaker, delayMs, useExponentialBackoff, useFibonacciBackoff, withRetry, withTimeout };
335
+ export { CircuitError, createCircuitBreaker, delayMs, useExponentialBackoff, useFibonacciBackoff };
394
336
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../lib/util.ts","../lib/retry.ts","../lib/timeout.ts","../lib/backoff.ts","../lib/options.ts","../lib/circuit-breaker.ts","../lib/index.ts"],"sourcesContent":["import type { AnyFn, RetryDelayFn } from \"./types.js\"\n\n/**\n * Returns a promise which rejects when the abort signal is triggered or\n * resolves when the promise is fulfilled.\n */\nexport const abortable = <T>(\n\tsignal: AbortSignal,\n\tpending: PromiseLike<T>,\n): Promise<T> =>\n\tnew Promise((resolve, reject) => {\n\t\tsignal.throwIfAborted()\n\n\t\tconst onAbort = () => reject(signal.reason)\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\n\t\tPromise.resolve(pending)\n\t\t\t.finally(() => signal.removeEventListener(\"abort\", onAbort))\n\t\t\t.then(resolve, reject)\n\t})\n\n/**\n * Asserts that the given value is truthy. If not, throws a `TypeError`.\n */\nexport function assert(value: unknown, message?: string): asserts value {\n\tif (!value) throw new TypeError(message)\n}\n\nexport class CircuitError extends Error {\n\tisTransient: boolean\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: unknown; isTransient?: boolean },\n\t) {\n\t\tsuper(`ERR_CIRCUIT_BREAKER_${message}`, options)\n\t\tthis.isTransient = options?.isTransient ?? false\n\t}\n}\n\n/**\n * Returns a promise that resolves after the specified number of milliseconds.\n */\nexport const delayMs = (ms: number, signal?: AbortSignal): Promise<void> => {\n\tif (!Number.isFinite(ms) || ms < 0) {\n\t\tthrow new RangeError(\n\t\t\t`\"ms\" must be a finite, non-negative number (received ${ms})`,\n\t\t)\n\t}\n\n\treturn signal\n\t\t? new Promise((resolve, reject) => {\n\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\tconst timer = setTimeout(() => {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort)\n\t\t\t\t\tresolve()\n\t\t\t\t}, ms)\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\treject(signal.reason)\n\t\t\t\t}\n\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\t\t\t})\n\t\t: new Promise((next) => setTimeout(next, ms))\n}\n\nexport const deprecated = <T extends AnyFn>(\n\tfn: T,\n\tmethod: string,\n\tmessage: string,\n): T => {\n\tlet warned = false\n\treturn ((...args) => {\n\t\tif (!warned) {\n\t\t\tconsole.warn(`[breaker-box] ${method} Deprecation: ${message}`)\n\t\t\twarned = true\n\t\t}\n\t\treturn fn(...args)\n\t}) as T\n}\n\nexport const identity = <T>(value: T): T => value\n\nexport const noop: (...args: unknown[]) => void = () => {}\n\n/**\n * Polyfill for `Promise.try()`\n */\nexport function promiseTry<T>(fn: () => T): Promise<T> {\n\ttry {\n\t\treturn Promise.resolve(fn())\n\t} catch (error) {\n\t\treturn Promise.reject(error)\n\t}\n}\n\nexport async function shouldContinue(options: {\n\tretries: number\n\tlastError: unknown\n\tretryDelay: number | RetryDelayFn\n\tretryLimit: number\n\tretryTest: (error: unknown) => boolean\n\tsignal: AbortSignal\n}): Promise<true> {\n\tconst { retries, lastError, retryDelay, retryLimit, retryTest, signal } =\n\t\toptions\n\n\tif (retries >= retryLimit)\n\t\tthrow new CircuitError(\"MAX_RETRIES\", { cause: lastError })\n\tif (!retryTest(lastError))\n\t\tthrow new CircuitError(\"NON_RETRYABLE\", { cause: lastError })\n\n\ttry {\n\t\tif (!retryDelay) return true\n\t\telse if (typeof retryDelay === \"number\") await delayMs(retryDelay, signal)\n\t\telse if (typeof retryDelay === \"function\") await retryDelay(retries, signal)\n\t} catch {\n\t\t/* empty */\n\t}\n\n\treturn true\n}\n","import { type MainFn, type RetryOptions } from \"./types.js\"\nimport { assert, abortable } from \"./util.js\"\n\n/**\n * Wrap a function with retry logic. Errors will be retried according to the\n * provided options.\n *\n * @example\n * ```ts\n * // Compose with circuit breaker. Retry up to 3 times with no delay\n * const protectedA = createCircuitBreaker(\n * withRetry(unreliableApiCall, { maxAttempts: 3 })\n * )\n *\n * // Retry up to 5 times with exponential backoff\n * const protectedB = createCircuitBreaker(\n * withRetry(unreliableApiCall, {\n * maxAttempts: 5,\n * retryDelay: useExponentialBackoff(30),\n * })\n * )\n * ```\n */\nexport function withRetry<Ret, Args extends readonly unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\toptions: Readonly<RetryOptions> = {},\n): MainFn<Ret, Args> & Disposable {\n\tconst {\n\t\tshouldRetry = () => true,\n\t\tmaxAttempts = 3,\n\t\tretryDelay = () => Promise.resolve(),\n\t} = options\n\n\tassert(maxAttempts >= 1, \"maxAttempts must be a number greater than 0\")\n\n\tconst controller = new AbortController()\n\tconst { signal } = controller\n\n\tasync function withRetryFunction(...args: Args): Promise<Ret> {\n\t\tlet attempt = 1\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\treturn await main(...args)\n\t\t\t} catch (cause) {\n\t\t\t\tif (attempt >= maxAttempts) {\n\t\t\t\t\tthrow new Error(`ERR_CIRCUIT_BREAKER_MAX_ATTEMPTS (${maxAttempts})`, {\n\t\t\t\t\t\tcause,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif (!shouldRetry(cause, attempt)) throw cause\n\t\t\t}\n\n\t\t\tattempt++\n\t\t\tawait abortable(signal, retryDelay(attempt, signal))\n\t\t}\n\t}\n\n\treturn Object.assign(withRetryFunction, {\n\t\t[Symbol.dispose]: () => controller.abort(),\n\t})\n}\n","import { type MainFn } from \"./types.js\"\nimport { abortable } from \"./util.js\"\n\n/**\n * Wraps an async function with a timeout constraint. Rejects with an Error if\n * execution exceeds the specified timeout.\n *\n * @example\n * ```ts\n * const fetchWithTimeout = withTimeout(fetchData, 5000, \"Fetch timed out\")\n * try {\n * const data = await fetchWithTimeout(url)\n * } catch (error) {\n * console.error(error.message) // \"Fetch timed out\" after 5 seconds\n * }\n * ```\n */\nexport function withTimeout<Ret, Args extends readonly unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\ttimeoutMs: number,\n\ttimeoutMessage = \"ERR_CIRCUIT_BREAKER_TIMEOUT\",\n): MainFn<Ret, Args> & Disposable {\n\tconst controller = new AbortController()\n\tconst { signal } = controller\n\n\tfunction withTimeoutFunction(...args: Args): Promise<Ret> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(reject, timeoutMs, new Error(timeoutMessage))\n\n\t\t\tabortable(signal, main(...args))\n\t\t\t\t.then(resolve, reject)\n\t\t\t\t.finally(() => clearTimeout(timer))\n\t\t})\n\t}\n\n\treturn Object.assign(withTimeoutFunction, {\n\t\t[Symbol.dispose]: () => controller.abort(),\n\t})\n}\n","import type { RetryDelayFn } from \"./types.js\"\nimport { delayMs } from \"./util.js\"\n\n/**\n * Creates an exponential backoff strategy for retry delays.\n * Delay grows as 2^(attempt-2) seconds, capped at maxSeconds.\n *\n * The sequence is: 1s, 2s, 4s, 8s, 16s, 32s, etc.\n *\n * @example\n * ```ts\n * const backoff = useExponentialBackoff(30)\n * await backoff(2) // waits 1 second\n * await backoff(3) // waits 2 seconds\n * await backoff(10) // waits 30 seconds (capped)\n * ```\n */\nexport function useExponentialBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function exponentialBackoff(attempt, signal) {\n\t\tconst num = Math.max(attempt - 2, 0)\n\t\tconst delay = Math.min(2 ** num, maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n\nconst sqrt5 = /* @__PURE__ */ Math.sqrt(5)\n/**\n * Binet's formula for calculating Fibonacci numbers in constant time.\n * @see https://en.wikipedia.org/wiki/Fibonacci_sequence#Closed-form_expression\n */\nconst binet = (n: number) =>\n\tMath.round(((1 + sqrt5) ** n - (1 - sqrt5) ** n) / (2 ** n * sqrt5))\n\n/**\n * Creates a Fibonacci backoff strategy for retry delays. It is more gradual\n * than exponential backoff, useful for more aggressive retry patterns.\n *\n * The sequence is: 1s, 2s, 3s, 5s, 8s, 13s, etc.\n *\n * @example\n * ```ts\n * const backoff = useFibonacciBackoff(60)\n * await backoff(2) // waits 1 second\n * await backoff(5) // waits 5 seconds\n * await backoff(10) // waits 55 seconds\n * ```\n */\nexport function useFibonacciBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function fibonacciBackoff(attempt, signal) {\n\t\tconst delay = Math.min(binet(attempt), maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n","import type { AnyFn, CircuitBreakerOptions } from \"./types.js\"\nimport { assert } from \"./util.js\"\n\nexport function parseOptions<Fallback extends AnyFn>(\n\toptions: CircuitBreakerOptions<Fallback>,\n) {\n\tconst {\n\t\terrorIsFailure = () => false,\n\t\terrorThreshold = 0,\n\t\terrorWindow = 10_000,\n\t\tfallback,\n\t\tminimumCandidates = 1,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter = 30_000,\n\t\tretryDelay = 0,\n\t\tretryLimit = Infinity,\n\t\tretryTest = () => true,\n\t\ttimeout = 0,\n\t} = options\n\n\t// errorIsFailure\n\tassert(\n\t\ttypeof errorIsFailure === \"function\",\n\t\t`\"errorIsFailure\" must be a function (received ${typeof errorIsFailure})`,\n\t)\n\n\t// errorThreshold\n\tassert(\n\t\terrorThreshold >= 0 && errorThreshold <= 1,\n\t\t`\"errorThreshold\" must be between 0 and 1 (received ${errorThreshold})`,\n\t)\n\n\t// errorWindow\n\tassert(\n\t\terrorWindow >= 1_000,\n\t\t`\"errorWindow\" must be milliseconds of at least 1 second (received ${errorWindow})`,\n\t)\n\n\t// (optional) fallback\n\tassert(\n\t\t!fallback || typeof fallback === \"function\",\n\t\t`\"fallback\" must be a function (received ${typeof fallback})`,\n\t)\n\n\t// minimumCandidates\n\tassert(\n\t\tminimumCandidates >= 1,\n\t\t`\"minimumCandidates\" must be greater than 0 (received ${minimumCandidates})`,\n\t)\n\n\t// (optional) onClose\n\tassert(\n\t\t!onClose || typeof onClose === \"function\",\n\t\t`\"onClose\" must be a function (received ${typeof onClose})`,\n\t)\n\n\t// (optional) onHalfOpen\n\tassert(\n\t\t!onHalfOpen || typeof onHalfOpen === \"function\",\n\t\t`\"onHalfOpen\" must be a function (received ${typeof onHalfOpen})`,\n\t)\n\n\t// (optional) onOpen\n\tassert(\n\t\t!onOpen || typeof onOpen === \"function\",\n\t\t`\"onOpen\" must be a function (received ${typeof onOpen})`,\n\t)\n\n\t// resetAfter\n\tassert(\n\t\tresetAfter >= 1_000,\n\t\t`\"resetAfter\" must be milliseconds of at least 1 second (received ${resetAfter})`,\n\t)\n\tassert(\n\t\tresetAfter >= errorWindow,\n\t\t`\"resetAfter\" must be greater than or equal to \"errorWindow\" (received ${resetAfter}, expected >= ${errorWindow})`,\n\t)\n\n\t// retryDelay\n\tassert(\n\t\ttypeof retryDelay === \"function\" ||\n\t\t\t(typeof retryDelay === \"number\" &&\n\t\t\t\tretryDelay >= 0 &&\n\t\t\t\tNumber.isFinite(retryDelay)),\n\t\t`\"retryDelay\" must be a function or a finite, non-negative number (received ${typeof retryDelay})`,\n\t)\n\n\t// retryLimit\n\tassert(\n\t\ttypeof retryLimit === \"number\" && retryLimit >= 1,\n\t\t`\"retryLimit\" must be greater than 0 (received ${retryLimit})`,\n\t)\n\n\t// retryTest\n\tassert(\n\t\ttypeof retryTest === \"function\",\n\t\t`\"retryTest\" must be a function (received ${typeof retryTest})`,\n\t)\n\n\t// timeout\n\tassert(\n\t\tNumber.isFinite(timeout) && timeout >= 0,\n\t\t`\"timeout\" must be a finite, non-negative number (received ${timeout})`,\n\t)\n\n\treturn {\n\t\terrorIsFailure,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t}\n}\n","import { parseOptions } from \"./options.js\"\nimport type {\n\tCircuitBreakerOptions,\n\tCircuitBreakerProtectedFn,\n\tHistoryEntry,\n\tHistoryMap,\n\tMainFn,\n\tStateName,\n} from \"./types.js\"\nimport {\n\tCircuitError,\n\tabortable,\n\tassert,\n\tdelayMs,\n\tnoop,\n\tpromiseTry,\n\tshouldContinue,\n} from \"./util.js\"\n\nconst validTransitions: Record<StateName, StateName[]> = {\n\tclosed: [\"open\", \"disposed\"],\n\topen: [\"halfOpen\", \"disposed\"],\n\thalfOpen: [\"closed\", \"open\", \"disposed\"],\n\tdisposed: [],\n}\n\nfunction assertTransition(from: StateName, to: StateName): void {\n\tassert(\n\t\tvalidTransitions[from].includes(to),\n\t\t`Invalid transition from ${from} to ${to}`,\n\t)\n}\n\ninterface CircuitInternalState<T extends StateName = StateName> {\n\tcontroller: AbortController\n\tfailureCause: unknown\n\tfailureRate: number\n\thistory: HistoryMap\n\tstatus: T\n}\n\nfunction createState(\n\tstatus: StateName,\n\tfailureCause?: unknown,\n): CircuitInternalState {\n\tconst controller = new AbortController()\n\treturn {\n\t\tcontroller,\n\t\tfailureCause,\n\t\tfailureRate: 0,\n\t\thistory: new Map(),\n\t\tstatus,\n\t}\n}\n\n/**\n * Creates a circuit breaker that wraps an async function with failure tracking\n * and automatic fallback behavior.\n *\n * The circuit breaker operates in four states:\n *\n * - `closed`: Normal operation, tracks failures in a sliding window\n * - `open`: Failed state, fallback is used until `resetAfter` milliseconds\n * - `halfOpen`: Testing recovery, allows trial calls\n * - `disposed`: Terminal state, all calls rejected\n *\n * When the failure rate exceeds `errorThreshold` within the `errorWindow`, the\n * circuit opens and rejects calls (using fallback if provided) for `resetAfter`\n * milliseconds. After this period, it transitions to half-open and allows up\n * to `minimumCandidates` concurrent trial calls. If their failure rate stays\n * at or below the threshold, the circuit closes; otherwise it reopens.\n *\n * @example\n * ```ts\n * const protectedFn = createCircuitBreaker(unreliableApiCall, {\n * errorThreshold: 0.5,\n * errorWindow: 10_000,\n * resetAfter: 30_000,\n * fallback: () => cachedResponse,\n * })\n *\n * try {\n * const result = await protectedFn(arg1, arg2)\n * } catch (error) {\n * console.error('Circuit breaker rejected call:', error)\n * }\n *\n * console.log(protectedFn.getState()) // 'closed' | 'open' | 'halfOpen' | 'disposed'\n * protectedFn[Symbol.dispose]() // Clean up timers and resources\n * ```\n */\nexport function createCircuitBreaker<Ret, Args extends unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\toptions: CircuitBreakerOptions<MainFn<Ret, Args>> = {},\n): CircuitBreakerProtectedFn<Ret, Args> {\n\tconst {\n\t\terrorIsFailure,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t} = parseOptions(options)\n\n\tlet state = createState(\"closed\")\n\n\tasync function tryCall(\n\t\tcurrent: CircuitInternalState,\n\t\targs: Args,\n\t): Promise<Ret> {\n\t\tconst { history } = current\n\t\tconst request = promiseTry(() => main(...args))\n\n\t\tlet historyItem: HistoryEntry | undefined = { status: \"pending\" }\n\t\thistory.set(request, historyItem)\n\n\t\ttry {\n\t\t\tconst result =\n\t\t\t\ttimeout > 0\n\t\t\t\t\t? await abortable(AbortSignal.timeout(timeout), request)\n\t\t\t\t\t: await request\n\t\t\thistoryItem.status = \"resolved\"\n\t\t\treturn result\n\t\t} catch (cause) {\n\t\t\thistoryItem.status = \"rejected\"\n\t\t\t// Drop this request if it's a transient error that shouldn't count\n\t\t\t// towards the failure rate\n\t\t\tconst isTransient = errorIsFailure(cause)\n\t\t\tif (isTransient) historyItem = undefined\n\n\t\t\t// Wrap the error in a CircuitError to provide additional context and\n\t\t\t// control flow handling.\n\t\t\tthrow new CircuitError(\"CALL_FAILURE\", { cause, isTransient })\n\t\t} finally {\n\t\t\t// Remove the request if it was a transient failure, or if it's stale.\n\t\t\tif (!historyItem || state !== current) history.delete(request)\n\t\t\t// Keep the request in history until the end of the error window, or until\n\t\t\t// the circuit transitions.\n\t\t\telse {\n\t\t\t\tconst { signal } = current.controller\n\t\t\t\tdelayMs(errorWindow, signal)\n\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t.finally(() => history.delete(request))\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction calculateFailureRate(): number {\n\t\tlet failures = 0\n\t\tlet total = 0\n\t\tfor (const { status } of state.history.values()) {\n\t\t\tif (status === \"rejected\") failures++\n\t\t\tif (status !== \"pending\") total++\n\t\t}\n\t\tif (!total || total < minimumCandidates) return 0\n\t\treturn failures / total\n\t}\n\n\tfunction transitionTo(\n\t\ttoStatus: StateName,\n\t\tfailureCause?: unknown,\n\t): CircuitInternalState {\n\t\tassertTransition(state.status, toStatus)\n\t\tstate.controller.abort()\n\t\treturn (state = createState(toStatus, failureCause))\n\t}\n\n\tasync function transitionToOpen(error: CircuitError): Promise<void> {\n\t\t// Race guard: a concurrent failure may have already changed state.\n\t\tif (state.status !== \"closed\" && state.status !== \"halfOpen\") return\n\n\t\tconst cause = error.cause ?? error\n\t\tconst nextState = transitionTo(\"open\", cause)\n\t\tif (onOpen) setImmediate(onOpen, cause)\n\n\t\tconst { signal } = nextState.controller\n\t\tawait delayMs(resetAfter, signal)\n\t\tif (state === nextState) transitionToHalfOpen()\n\t}\n\n\tfunction transitionToHalfOpen(): void {\n\t\ttransitionTo(\"halfOpen\", state.failureCause)\n\t\tif (onHalfOpen) setImmediate(onHalfOpen)\n\t}\n\n\tfunction transitionToClosed(): void {\n\t\ttransitionTo(\"closed\")\n\t\tif (onClose) setImmediate(onClose)\n\t}\n\n\tfunction guardIsCurrent(\n\t\tcurrent: CircuitInternalState,\n\t\terror: unknown,\n\t): error is CircuitError {\n\t\tif (!(error instanceof CircuitError)) throw error\n\t\t// Transient errors shouldn't affect the circuit breaker's state. Re-throw\n\t\t// the original cause of the error.\n\t\tif (error.isTransient) throw error.cause\n\n\t\t// If the circuit breaker was disposed mid-flight, surface the underlying\n\t\t// cause of the in-flight call rather than the dispose error.\n\t\tif (state.status === \"disposed\")\n\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\tthrow error.cause ?? new CircuitError(\"DISPOSED\")\n\n\t\t// If the circuit breaker transitioned states, try again.\n\t\treturn state === current\n\t}\n\n\tasync function protectedFn(...args: Args): Promise<Ret> {\n\t\tlet lastError: CircuitError | undefined\n\t\tlet retries = 0\n\t\tdo {\n\t\t\tconst current = state\n\t\t\tlastError = undefined\n\n\t\t\t// Closed: Normal Operation\n\t\t\tif (current.status === \"closed\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) {\n\t\t\t\t\t\tlastError = error\n\t\t\t\t\t\t// Determine if the failure rate should open the circuit.\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\tif (rate > errorThreshold) transitionToOpen(error).catch(noop)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Half-Open: Execute trial calls until we have enough candidates.\n\t\t\telse if (\n\t\t\t\tcurrent.status === \"halfOpen\" &&\n\t\t\t\tcurrent.history.size < minimumCandidates\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) lastError = error\n\t\t\t\t\tbreak\n\t\t\t\t} finally {\n\t\t\t\t\t// Do nothing until we have enough candidates to make a decision.\n\t\t\t\t\tif (state === current && current.history.size >= minimumCandidates) {\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\t// Determine if the failure rate should re-open the circuit or\n\t\t\t\t\t\t// if it is healthy enough to close it again.\n\t\t\t\t\t\tif (rate > errorThreshold && lastError)\n\t\t\t\t\t\t\ttransitionToOpen(lastError).catch(noop)\n\t\t\t\t\t\telse if (rate <= errorThreshold) transitionToClosed()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Open: Skip calls and immediately return fallback if available.\n\t\t\telse if (current.status === \"open\" || current.status === \"halfOpen\") {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Disposed: Reject all calls with dispose error.\n\t\t\telse throw current.failureCause\n\t\t} while (\n\t\t\tawait shouldContinue({\n\t\t\t\tretries: ++retries,\n\t\t\t\tlastError: lastError?.cause ?? lastError,\n\t\t\t\tretryDelay,\n\t\t\t\tretryLimit,\n\t\t\t\tretryTest,\n\t\t\t\tsignal: state.controller.signal,\n\t\t\t}).catch((error: CircuitError) => {\n\t\t\t\tlastError = error\n\t\t\t\treturn false\n\t\t\t})\n\t\t)\n\n\t\tif (!fallback) throw lastError ?? state.failureCause\n\t\treturn fallback(...args)\n\t}\n\n\tfunction dispose(disposeMessage = \"ERR_CIRCUIT_BREAKER_DISPOSED\"): void {\n\t\tif (state.status === \"disposed\") return\n\t\ttransitionTo(\"disposed\", new ReferenceError(disposeMessage))\n\t\tmain[Symbol.dispose]?.()\n\t}\n\n\tconst wrapped = protectedFn as CircuitBreakerProtectedFn<Ret, Args>\n\twrapped[Symbol.dispose] = () => dispose()\n\twrapped.dispose = dispose\n\twrapped.getFailureRate = () => state.failureRate\n\twrapped.getLatestError = () => state.failureCause\n\twrapped.getState = () => state.status\n\n\treturn wrapped\n}\n","import { withRetry as internalWithRetry } from \"./retry.js\"\nimport { withTimeout as internalWithTimeout } from \"./timeout.js\"\nimport type { StateName } from \"./types.js\"\n\nexport { useExponentialBackoff, useFibonacciBackoff } from \"./backoff.js\"\nexport { createCircuitBreaker } from \"./circuit-breaker.js\"\n\nexport type {\n\tCircuitBreakerOptions,\n\tCircuitBreakerProtectedFn,\n\tMainFn,\n\tRetryOptions,\n\tStateName,\n} from \"./types.js\"\nexport { delayMs } from \"./util.js\"\n\n// =============================================================================\n// Deprecated API properties\nimport { deprecated } from \"./util.js\"\n\n/** @deprecated Use `StateName` instead. */\nexport type CircuitState = StateName\n\n/** @deprecated Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead. */\nexport const withRetry = deprecated(\n\tinternalWithRetry,\n\t\"withRetry\",\n\t\"Use `retryLimit`, `retryDelay`, and `retryTest` options on `createCircuitBreaker` instead.\",\n)\n\n/** @deprecated Use `options.timeout` on `createCircuitBreaker` instead. */\nexport const withTimeout = deprecated(\n\tinternalWithTimeout,\n\t\"withTimeout\",\n\t\"Use `options.timeout` on`createCircuitBreaker` instead.\",\n)\n"],"names":["withRetry","withTimeout","internalWithRetry","internalWithTimeout"],"mappings":"AACO,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;AAC/E,EAAE,MAAM,CAAC,cAAc,EAAE;AACzB,EAAE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AAC7C,EAAE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC3D,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;AAC5G,CAAC,CAAC;AACK,SAAS,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE;AACvC,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,SAAS,CAAC,OAAO,CAAC;AAC1C;AACO,MAAM,YAAY,SAAS,KAAK,CAAC;AACxC,EAAE,WAAW;AACb,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE;AAChC,IAAI,KAAK,CAAC,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC;AACpD,IAAI,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,KAAK;AACpD,EAAE;AACF;AACY,MAAC,OAAO,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK;AACvC,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AACtC,IAAI,MAAM,IAAI,UAAU;AACxB,MAAM,CAAC,qDAAqD,EAAE,EAAE,CAAC,CAAC;AAClE,KAAK;AACL,EAAE;AACF,EAAE,OAAO,MAAM,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;AACnD,IAAI,MAAM,CAAC,cAAc,EAAE;AAC3B,IAAI,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM;AACnC,MAAM,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;AAClD,MAAM,OAAO,EAAE;AACf,IAAI,CAAC,EAAE,EAAE,CAAC;AACV,IAAI,MAAM,OAAO,GAAG,MAAM;AAC1B,MAAM,YAAY,CAAC,KAAK,CAAC;AACzB,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AAC3B,IAAI,CAAC;AACL,IAAI,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC7D,EAAE,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAClD;AACO,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK;AACnD,EAAE,IAAI,MAAM,GAAG,KAAK;AACpB,EAAE,QAAQ,CAAC,GAAG,IAAI,KAAK;AACvB,IAAI,IAAI,CAAC,MAAM,EAAE;AACjB,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;AACrE,MAAM,MAAM,GAAG,IAAI;AACnB,IAAI;AACJ,IAAI,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;AACtB,EAAE,CAAC;AACH,CAAC;AAEM,MAAM,IAAI,GAAG,MAAM;AAC1B,CAAC;AACM,SAAS,UAAU,CAAC,EAAE,EAAE;AAC/B,EAAE,IAAI;AACN,IAAI,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;AAChC,EAAE,CAAC,CAAC,OAAO,KAAK,EAAE;AAClB,IAAI,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AAChC,EAAE;AACF;AACO,eAAe,cAAc,CAAC,OAAO,EAAE;AAC9C,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO;AACnF,EAAE,IAAI,OAAO,IAAI,UAAU;AAC3B,IAAI,MAAM,IAAI,YAAY,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAC/D,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;AAC3B,IAAI,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACjE,EAAE,IAAI;AACN,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,IAAI;AAChC,SAAS,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC;AAC9E,SAAS,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;AAChF,EAAE,CAAC,CAAC,MAAM;AACV,EAAE;AACF,EAAE,OAAO,IAAI;AACb;;AClEO,SAASA,WAAS,CAAC,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE;AAC9C,EAAE,MAAM;AACR,IAAI,WAAW,GAAG,MAAM,IAAI;AAC5B,IAAI,WAAW,GAAG,CAAC;AACnB,IAAI,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO;AACtC,GAAG,GAAG,OAAO;AACb,EAAE,MAAM,CAAC,WAAW,IAAI,CAAC,EAAE,6CAA6C,CAAC;AACzE,EAAE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AAC1C,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU;AAC/B,EAAE,eAAe,iBAAiB,CAAC,GAAG,IAAI,EAAE;AAC5C,IAAI,IAAI,OAAO,GAAG,CAAC;AACnB,IAAI,OAAO,IAAI,EAAE;AACjB,MAAM,IAAI;AACV,QAAQ,OAAO,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;AAClC,MAAM,CAAC,CAAC,OAAO,KAAK,EAAE;AACtB,QAAQ,IAAI,OAAO,IAAI,WAAW,EAAE;AACpC,UAAU,MAAM,IAAI,KAAK,CAAC,CAAC,kCAAkC,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE;AAC/E,YAAY;AACZ,WAAW,CAAC;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK;AACrD,MAAM;AACN,MAAM,OAAO,EAAE;AACf,MAAM,MAAM,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1D,IAAI;AACJ,EAAE;AACF,EAAE,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE;AAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK;AAC5C,GAAG,CAAC;AACJ;;AC7BO,SAASC,aAAW,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,GAAG,6BAA6B,EAAE;AAC7F,EAAE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AAC1C,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU;AAC/B,EAAE,SAAS,mBAAmB,CAAC,GAAG,IAAI,EAAE;AACxC,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;AAC5C,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AAC5E,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;AAC/F,IAAI,CAAC,CAAC;AACN,EAAE;AACF,EAAE,OAAO,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE;AAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK;AAC5C,GAAG,CAAC;AACJ;;ACbO,SAAS,qBAAqB,CAAC,UAAU,EAAE;AAClD,EAAE,OAAO,SAAS,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE;AACtD,IAAI,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC;AACxC,IAAI,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,UAAU,CAAC;AAChD,IAAI,OAAO,OAAO,CAAC,KAAK,GAAG,GAAG,EAAE,MAAM,CAAC;AACvC,EAAE,CAAC;AACH;AACA,MAAM,KAAK,mBAAmB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;AAClF,SAAS,mBAAmB,CAAC,UAAU,EAAE;AAChD,EAAE,OAAO,SAAS,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE;AACpD,IAAI,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC;AACtD,IAAI,OAAO,OAAO,CAAC,KAAK,GAAG,GAAG,EAAE,MAAM,CAAC;AACvC,EAAE,CAAC;AACH;;ACdO,SAAS,YAAY,CAAC,OAAO,EAAE;AACtC,EAAE,MAAM;AACR,IAAI,cAAc,GAAG,MAAM,KAAK;AAChC,IAAI,cAAc,GAAG,CAAC;AACtB,IAAI,WAAW,GAAG,GAAG;AACrB,IAAI,QAAQ;AACZ,IAAI,iBAAiB,GAAG,CAAC;AACzB,IAAI,OAAO;AACX,IAAI,UAAU;AACd,IAAI,MAAM;AACV,IAAI,UAAU,GAAG,GAAG;AACpB,IAAI,UAAU,GAAG,CAAC;AAClB,IAAI,UAAU,GAAG,QAAQ;AACzB,IAAI,SAAS,GAAG,MAAM,IAAI;AAC1B,IAAI,OAAO,GAAG;AACd,GAAG,GAAG,OAAO;AACb,EAAE,MAAM;AACR,IAAI,OAAO,cAAc,KAAK,UAAU;AACxC,IAAI,CAAC,8CAA8C,EAAE,OAAO,cAAc,CAAC,CAAC;AAC5E,GAAG;AACH,EAAE,MAAM;AACR,IAAI,cAAc,IAAI,CAAC,IAAI,cAAc,IAAI,CAAC;AAC9C,IAAI,CAAC,mDAAmD,EAAE,cAAc,CAAC,CAAC;AAC1E,GAAG;AACH,EAAE,MAAM;AACR,IAAI,WAAW,IAAI,GAAG;AACtB,IAAI,CAAC,kEAAkE,EAAE,WAAW,CAAC,CAAC;AACtF,GAAG;AACH,EAAE,MAAM;AACR,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,UAAU;AAC/C,IAAI,CAAC,wCAAwC,EAAE,OAAO,QAAQ,CAAC,CAAC;AAChE,GAAG;AACH,EAAE,MAAM;AACR,IAAI,iBAAiB,IAAI,CAAC;AAC1B,IAAI,CAAC,qDAAqD,EAAE,iBAAiB,CAAC,CAAC;AAC/E,GAAG;AACH,EAAE,MAAM;AACR,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,UAAU;AAC7C,IAAI,CAAC,uCAAuC,EAAE,OAAO,OAAO,CAAC,CAAC;AAC9D,GAAG;AACH,EAAE,MAAM;AACR,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,UAAU;AACnD,IAAI,CAAC,0CAA0C,EAAE,OAAO,UAAU,CAAC,CAAC;AACpE,GAAG;AACH,EAAE,MAAM;AACR,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,UAAU;AAC3C,IAAI,CAAC,sCAAsC,EAAE,OAAO,MAAM,CAAC,CAAC;AAC5D,GAAG;AACH,EAAE,MAAM;AACR,IAAI,UAAU,IAAI,GAAG;AACrB,IAAI,CAAC,iEAAiE,EAAE,UAAU,CAAC,CAAC;AACpF,GAAG;AACH,EAAE,MAAM;AACR,IAAI,UAAU,IAAI,WAAW;AAC7B,IAAI,CAAC,sEAAsE,EAAE,UAAU,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;AACrH,GAAG;AACH,EAAE,MAAM;AACR,IAAI,OAAO,UAAU,KAAK,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;AACxH,IAAI,CAAC,2EAA2E,EAAE,OAAO,UAAU,CAAC,CAAC;AACrG,GAAG;AACH,EAAE,MAAM;AACR,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,IAAI,CAAC;AACrD,IAAI,CAAC,8CAA8C,EAAE,UAAU,CAAC,CAAC;AACjE,GAAG;AACH,EAAE,MAAM;AACR,IAAI,OAAO,SAAS,KAAK,UAAU;AACnC,IAAI,CAAC,yCAAyC,EAAE,OAAO,SAAS,CAAC,CAAC;AAClE,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC;AAC5C,IAAI,CAAC,0DAA0D,EAAE,OAAO,CAAC,CAAC;AAC1E,GAAG;AACH,EAAE,OAAO;AACT,IAAI,cAAc;AAClB,IAAI,cAAc;AAClB,IAAI,WAAW;AACf,IAAI,QAAQ;AACZ,IAAI,iBAAiB;AACrB,IAAI,OAAO;AACX,IAAI,UAAU;AACd,IAAI,MAAM;AACV,IAAI,UAAU;AACd,IAAI,UAAU;AACd,IAAI,UAAU;AACd,IAAI,SAAS;AACb,IAAI;AACJ,GAAG;AACH;;AC9EA,MAAM,gBAAgB,GAAG;AACzB,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;AAC9B,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;AAChC,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC;AAC1C,EAAE,QAAQ,EAAE;AACZ,CAAC;AACD,SAAS,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE;AACpC,EAAE,MAAM;AACR,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;AACvC,IAAI,CAAC,wBAAwB,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;AAC7C,GAAG;AACH;AACA,SAAS,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE;AAC3C,EAAE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AAC1C,EAAE,OAAO;AACT,IAAI,UAAU;AACd,IAAI,YAAY;AAChB,IAAI,WAAW,EAAE,CAAC;AAClB,IAAI,OAAO,kBAAkB,IAAI,GAAG,EAAE;AACtC,IAAI;AACJ,GAAG;AACH;AACO,SAAS,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE;AACzD,EAAE,MAAM;AACR,IAAI,cAAc;AAClB,IAAI,cAAc;AAClB,IAAI,WAAW;AACf,IAAI,QAAQ;AACZ,IAAI,iBAAiB;AACrB,IAAI,OAAO;AACX,IAAI,UAAU;AACd,IAAI,MAAM;AACV,IAAI,UAAU;AACd,IAAI,UAAU;AACd,IAAI,UAAU;AACd,IAAI,SAAS;AACb,IAAI;AACJ,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC;AAC3B,EAAE,IAAI,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC;AACnC,EAAE,eAAe,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE;AACxC,IAAI,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO;AAC/B,IAAI,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AACnD,IAAI,IAAI,WAAW,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE;AAC3C,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC;AACrC,IAAI,IAAI;AACR,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO;AACzG,MAAM,WAAW,CAAC,MAAM,GAAG,UAAU;AACrC,MAAM,OAAO,MAAM;AACnB,IAAI,CAAC,CAAC,OAAO,KAAK,EAAE;AACpB,MAAM,WAAW,CAAC,MAAM,GAAG,UAAU;AACrC,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC;AAC/C,MAAM,IAAI,WAAW,EAAE,WAAW,GAAG,MAAM;AAC3C,MAAM,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AACpE,IAAI,CAAC,SAAS;AACd,MAAM,IAAI,CAAC,WAAW,IAAI,KAAK,KAAK,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;AACpE,WAAW;AACX,QAAQ,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU;AAC7C,QAAQ,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM;AACjD,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACjD,MAAM;AACN,IAAI;AACJ,EAAE;AACF,EAAE,SAAS,oBAAoB,GAAG;AAClC,IAAI,IAAI,QAAQ,GAAG,CAAC;AACpB,IAAI,IAAI,KAAK,GAAG,CAAC;AACjB,IAAI,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE;AACrD,MAAM,IAAI,MAAM,KAAK,UAAU,EAAE,QAAQ,EAAE;AAC3C,MAAM,IAAI,MAAM,KAAK,SAAS,EAAE,KAAK,EAAE;AACvC,IAAI;AACJ,IAAI,IAAI,CAAC,KAAK,IAAI,KAAK,GAAG,iBAAiB,EAAE,OAAO,CAAC;AACrD,IAAI,OAAO,QAAQ,GAAG,KAAK;AAC3B,EAAE;AACF,EAAE,SAAS,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE;AAChD,IAAI,gBAAgB,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC;AAC5C,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE;AAC5B,IAAI,OAAO,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC;AACtD,EAAE;AACF,EAAE,eAAe,gBAAgB,CAAC,KAAK,EAAE;AACzC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE;AAClE,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK;AACtC,IAAI,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;AACjD,IAAI,IAAI,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;AAC3C,IAAI,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU;AAC3C,IAAI,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC;AACrC,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,oBAAoB,EAAE;AACnD,EAAE;AACF,EAAE,SAAS,oBAAoB,GAAG;AAClC,IAAI,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC;AAChD,IAAI,IAAI,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC;AAC5C,EAAE;AACF,EAAE,SAAS,kBAAkB,GAAG;AAChC,IAAI,YAAY,CAAC,QAAQ,CAAC;AAC1B,IAAI,IAAI,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC;AACtC,EAAE;AACF,EAAE,SAAS,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE;AAC1C,IAAI,IAAI,EAAE,KAAK,YAAY,YAAY,CAAC,EAAE,MAAM,KAAK;AACrD,IAAI,IAAI,KAAK,CAAC,WAAW,EAAE,MAAM,KAAK,CAAC,KAAK;AAC5C,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU;AACnC,MAAM,MAAM,KAAK,CAAC,KAAK,IAAI,IAAI,YAAY,CAAC,UAAU,CAAC;AACvD,IAAI,OAAO,KAAK,KAAK,OAAO;AAC5B,EAAE;AACF,EAAE,eAAe,WAAW,CAAC,GAAG,IAAI,EAAE;AACtC,IAAI,IAAI,SAAS;AACjB,IAAI,IAAI,OAAO,GAAG,CAAC;AACnB,IAAI,GAAG;AACP,MAAM,MAAM,OAAO,GAAG,KAAK;AAC3B,MAAM,SAAS,GAAG,MAAM;AACxB,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE;AACvC,QAAQ,IAAI;AACZ,UAAU,OAAO,MAAM,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;AAC7C,QAAQ,CAAC,CAAC,OAAO,KAAK,EAAE;AACxB,UAAU,IAAI,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;AAC9C,YAAY,SAAS,GAAG,KAAK;AAC7B,YAAY,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,GAAG,oBAAoB,EAAE;AACrE,YAAY,IAAI,IAAI,GAAG,cAAc,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AAC1E,UAAU;AACV,QAAQ;AACR,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,iBAAiB,EAAE;AAC5F,QAAQ,IAAI;AACZ,UAAU,OAAO,MAAM,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;AAC7C,QAAQ,CAAC,CAAC,OAAO,KAAK,EAAE;AACxB,UAAU,IAAI,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK;AAC/D,UAAU;AACV,QAAQ,CAAC,SAAS;AAClB,UAAU,IAAI,KAAK,KAAK,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,iBAAiB,EAAE;AAC9E,YAAY,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,GAAG,oBAAoB,EAAE;AACrE,YAAY,IAAI,IAAI,GAAG,cAAc,IAAI,SAAS;AAClD,cAAc,gBAAgB,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AACrD,iBAAiB,IAAI,IAAI,IAAI,cAAc,EAAE,kBAAkB,EAAE;AACjE,UAAU;AACV,QAAQ;AACR,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE;AAC7E,QAAQ;AACR,MAAM,CAAC,MAAM,MAAM,OAAO,CAAC,YAAY;AACvC,IAAI,CAAC,QAAQ,MAAM,cAAc,CAAC;AAClC,MAAM,OAAO,EAAE,EAAE,OAAO;AACxB,MAAM,SAAS,EAAE,SAAS,EAAE,KAAK,IAAI,SAAS;AAC9C,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,SAAS;AACf,MAAM,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC;AAC/B,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK;AACxB,MAAM,SAAS,GAAG,KAAK;AACvB,MAAM,OAAO,KAAK;AAClB,IAAI,CAAC,CAAC;AACN,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM,SAAS,IAAI,KAAK,CAAC,YAAY;AACxD,IAAI,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC;AAC5B,EAAE;AACF,EAAE,SAAS,OAAO,CAAC,cAAc,GAAG,8BAA8B,EAAE;AACpE,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE;AACrC,IAAI,YAAY,CAAC,UAAU,EAAE,IAAI,cAAc,CAAC,cAAc,CAAC,CAAC;AAChE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;AAC5B,EAAE;AACF,EAAE,MAAM,OAAO,GAAG,WAAW;AAC7B,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,OAAO,EAAE;AAC3C,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO;AAC3B,EAAE,OAAO,CAAC,cAAc,GAAG,MAAM,KAAK,CAAC,WAAW;AAClD,EAAE,OAAO,CAAC,cAAc,GAAG,MAAM,KAAK,CAAC,YAAY;AACnD,EAAE,OAAO,CAAC,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM;AACvC,EAAE,OAAO,OAAO;AAChB;;ACpKY,MAAC,SAAS,GAAG,UAAU;AACnC,EAAEC,WAAiB;AACnB,EAAE,WAAW;AACb,EAAE;AACF;AACY,MAAC,WAAW,GAAG,UAAU;AACrC,EAAEC,aAAmB;AACrB,EAAE,aAAa;AACf,EAAE;AACF;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":["../lib/util.ts","../lib/backoff.ts","../lib/circuit-error.ts","../lib/options.ts","../lib/circuit-breaker.ts"],"sourcesContent":["\n/**\n * Returns a promise which rejects when the abort signal is triggered or\n * resolves when the promise is fulfilled.\n */\nexport const abortable = <T>(\n\tsignal: AbortSignal,\n\tpending: PromiseLike<T>,\n): Promise<T> =>\n\tnew Promise((resolve, reject) => {\n\t\tsignal.throwIfAborted()\n\n\t\tconst onAbort = () => reject(signal.reason)\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\n\t\tPromise.resolve(pending)\n\t\t\t.finally(() => signal.removeEventListener(\"abort\", onAbort))\n\t\t\t.then(resolve, reject)\n\t})\n\n/**\n * Asserts that the given value is truthy. If not, throws a `TypeError`.\n */\nexport function assert(value: unknown, message?: string): asserts value {\n\tif (!value) throw new TypeError(message)\n}\n\n/**\n * Returns a promise that resolves after the specified number of milliseconds.\n */\nexport const delayMs = (ms: number, signal?: AbortSignal): Promise<void> => {\n\tif (!Number.isFinite(ms) || ms < 0) {\n\t\tthrow new RangeError(\n\t\t\t`\"ms\" must be a finite, non-negative number (received ${ms})`,\n\t\t)\n\t}\n\n\treturn signal\n\t\t? new Promise((resolve, reject) => {\n\t\t\t\tsignal.throwIfAborted()\n\n\t\t\t\tconst timer = setTimeout(() => {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort)\n\t\t\t\t\tresolve()\n\t\t\t\t}, ms)\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tclearTimeout(timer)\n\t\t\t\t\treject(signal.reason)\n\t\t\t\t}\n\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true })\n\t\t\t})\n\t\t: new Promise((next) => setTimeout(next, ms))\n}\n\nexport const noop: (...args: unknown[]) => void = () => {}\n\n/**\n * Polyfill for `Promise.try()`\n */\nexport function promiseTry<T>(fn: () => T): Promise<T> {\n\ttry {\n\t\treturn Promise.resolve(fn())\n\t} catch (error) {\n\t\treturn Promise.reject(error)\n\t}\n}\n\n\n","import type { RetryDelayFn } from \"./types.js\"\nimport { delayMs } from \"./util.js\"\n\n/**\n * Creates an exponential backoff strategy for retry delays.\n * Delay grows as 2^(attempt-2) seconds, capped at maxSeconds.\n *\n * The sequence is: 1s, 2s, 4s, 8s, 16s, 32s, etc.\n *\n * @example\n * ```ts\n * const backoff = useExponentialBackoff(30)\n * await backoff(2) // waits 1 second\n * await backoff(3) // waits 2 seconds\n * await backoff(10) // waits 30 seconds (capped)\n * ```\n */\nexport function useExponentialBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function exponentialBackoff(attempt, signal) {\n\t\tconst num = Math.max(attempt - 2, 0)\n\t\tconst delay = Math.min(2 ** num, maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n\nconst sqrt5 = /* @__PURE__ */ Math.sqrt(5)\n/**\n * Binet's formula for calculating Fibonacci numbers in constant time.\n * @see https://en.wikipedia.org/wiki/Fibonacci_sequence#Closed-form_expression\n */\nconst binet = (n: number) =>\n\tMath.round(((1 + sqrt5) ** n - (1 - sqrt5) ** n) / (2 ** n * sqrt5))\n\n/**\n * Creates a Fibonacci backoff strategy for retry delays. It is more gradual\n * than exponential backoff, useful for more aggressive retry patterns.\n *\n * The sequence is: 1s, 2s, 3s, 5s, 8s, 13s, etc.\n *\n * @example\n * ```ts\n * const backoff = useFibonacciBackoff(60)\n * await backoff(2) // waits 1 second\n * await backoff(5) // waits 5 seconds\n * await backoff(10) // waits 55 seconds\n * ```\n */\nexport function useFibonacciBackoff(maxSeconds: number): RetryDelayFn {\n\treturn function fibonacciBackoff(attempt, signal) {\n\t\tconst delay = Math.min(binet(attempt), maxSeconds)\n\t\treturn delayMs(delay * 1_000, signal)\n\t}\n}\n","export class CircuitError extends Error {\n\tisTransient: boolean\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: unknown; isTransient?: boolean },\n\t) {\n\t\tsuper(`ERR_CIRCUIT_BREAKER_${message}`, options)\n\t\tthis.isTransient = options?.isTransient ?? false\n\t}\n}\n","import type { AnyFn, CircuitBreakerOptions } from \"./types.js\"\nimport { assert } from \"./util.js\"\n\nlet warnedErrorIsFailure = false\n\nexport function parseOptions<Fallback extends AnyFn>(\n\toptions: CircuitBreakerOptions<Fallback>,\n) {\n\tconst {\n\t\terrorIsTransient = options.errorIsFailure ?? (() => false),\n\t\terrorThreshold = 0,\n\t\terrorWindow = 10_000,\n\t\tfallback,\n\t\tminimumCandidates = 1,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter = 30_000,\n\t\tretryDelay = 0,\n\t\tretryLimit = Infinity,\n\t\tretryTest = () => true,\n\t\ttimeout = 0,\n\t} = options\n\n\tif (\n\t\t\"errorIsFailure\" in options &&\n\t\t!(\"errorIsTransient\" in options) &&\n\t\t!warnedErrorIsFailure\n\t) {\n\t\twarnedErrorIsFailure = true\n\t\tconsole.warn(\n\t\t\t'breaker-box: \"errorIsFailure\" is deprecated. Use \"errorIsTransient\" instead.',\n\t\t)\n\t}\n\n\t// errorIsTransient\n\tassert(\n\t\ttypeof errorIsTransient === \"function\",\n\t\t`\"errorIsTransient\" must be a function (received ${typeof errorIsTransient})`,\n\t)\n\n\t// errorThreshold\n\tassert(\n\t\terrorThreshold >= 0 && errorThreshold <= 1,\n\t\t`\"errorThreshold\" must be between 0 and 1 (received ${errorThreshold})`,\n\t)\n\n\t// errorWindow\n\tassert(\n\t\terrorWindow >= 1_000,\n\t\t`\"errorWindow\" must be milliseconds of at least 1 second (received ${errorWindow})`,\n\t)\n\n\t// (optional) fallback\n\tassert(\n\t\t!fallback || typeof fallback === \"function\",\n\t\t`\"fallback\" must be a function (received ${typeof fallback})`,\n\t)\n\n\t// minimumCandidates\n\tassert(\n\t\tminimumCandidates >= 1,\n\t\t`\"minimumCandidates\" must be greater than 0 (received ${minimumCandidates})`,\n\t)\n\n\t// (optional) onClose\n\tassert(\n\t\t!onClose || typeof onClose === \"function\",\n\t\t`\"onClose\" must be a function (received ${typeof onClose})`,\n\t)\n\n\t// (optional) onHalfOpen\n\tassert(\n\t\t!onHalfOpen || typeof onHalfOpen === \"function\",\n\t\t`\"onHalfOpen\" must be a function (received ${typeof onHalfOpen})`,\n\t)\n\n\t// (optional) onOpen\n\tassert(\n\t\t!onOpen || typeof onOpen === \"function\",\n\t\t`\"onOpen\" must be a function (received ${typeof onOpen})`,\n\t)\n\n\t// resetAfter\n\tassert(\n\t\tresetAfter >= 1_000,\n\t\t`\"resetAfter\" must be milliseconds of at least 1 second (received ${resetAfter})`,\n\t)\n\tassert(\n\t\tresetAfter >= errorWindow,\n\t\t`\"resetAfter\" must be greater than or equal to \"errorWindow\" (received ${resetAfter}, expected >= ${errorWindow})`,\n\t)\n\n\t// retryDelay\n\tassert(\n\t\ttypeof retryDelay === \"function\" ||\n\t\t\t(typeof retryDelay === \"number\" &&\n\t\t\t\tretryDelay >= 0 &&\n\t\t\t\tNumber.isFinite(retryDelay)),\n\t\t`\"retryDelay\" must be a function or a finite, non-negative number (received ${typeof retryDelay})`,\n\t)\n\n\t// retryLimit\n\tassert(\n\t\ttypeof retryLimit === \"number\" && retryLimit >= 1,\n\t\t`\"retryLimit\" must be greater than 0 (received ${retryLimit})`,\n\t)\n\n\t// retryTest\n\tassert(\n\t\ttypeof retryTest === \"function\",\n\t\t`\"retryTest\" must be a function (received ${typeof retryTest})`,\n\t)\n\n\t// timeout\n\tassert(\n\t\tNumber.isFinite(timeout) && timeout >= 0,\n\t\t`\"timeout\" must be a finite, non-negative number (received ${timeout})`,\n\t)\n\n\treturn {\n\t\terrorIsTransient,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t}\n}\n","import { parseOptions } from \"./options.js\"\nimport type {\n\tCircuitBreakerOptions,\n\tCircuitBreakerProtectedFn,\n\tHistoryEntry,\n\tHistoryMap,\n\tMainFn,\n\tRetryDelayFn,\n\tStateName,\n} from \"./types.js\"\nimport { CircuitError } from \"./circuit-error.js\"\nimport {\n\tabortable,\n\tassert,\n\tdelayMs,\n\tnoop,\n\tpromiseTry,\n} from \"./util.js\"\n\nasync function shouldContinue(options: {\n\tretries: number\n\tlastError: unknown\n\tretryDelay: number | RetryDelayFn\n\tretryLimit: number\n\tretryTest: (error: unknown) => boolean\n\tsignal: AbortSignal\n}): Promise<true> {\n\tconst { retries, lastError, retryDelay, retryLimit, retryTest, signal } =\n\t\toptions\n\n\tif (retries >= retryLimit)\n\t\tthrow new CircuitError(\"MAX_RETRIES\", { cause: lastError })\n\tif (!retryTest(lastError))\n\t\tthrow new CircuitError(\"NON_RETRYABLE\", { cause: lastError })\n\n\ttry {\n\t\tif (!retryDelay) return true\n\t\telse if (typeof retryDelay === \"number\") await delayMs(retryDelay, signal)\n\t\telse if (typeof retryDelay === \"function\") await retryDelay(retries, signal)\n\t} catch {\n\t\t/* empty */\n\t}\n\n\treturn true\n}\n\nconst validTransitions: Record<StateName, StateName[]> = {\n\tclosed: [\"open\", \"disposed\"],\n\topen: [\"halfOpen\", \"disposed\"],\n\thalfOpen: [\"closed\", \"open\", \"disposed\"],\n\tdisposed: [],\n}\n\nfunction assertTransition(from: StateName, to: StateName): void {\n\tassert(\n\t\tvalidTransitions[from].includes(to),\n\t\t`Invalid transition from ${from} to ${to}`,\n\t)\n}\n\ninterface CircuitInternalState<T extends StateName = StateName> {\n\tcontroller: AbortController\n\tfailureCause: unknown\n\tfailureRate: number\n\thistory: HistoryMap\n\tstatus: T\n}\n\nfunction createState(\n\tstatus: StateName,\n\tfailureCause?: unknown,\n): CircuitInternalState {\n\tconst controller = new AbortController()\n\treturn {\n\t\tcontroller,\n\t\tfailureCause,\n\t\tfailureRate: 0,\n\t\thistory: new Map(),\n\t\tstatus,\n\t}\n}\n\n/**\n * Creates a circuit breaker that wraps an async function with failure tracking\n * and automatic fallback behavior.\n *\n * The circuit breaker operates in four states:\n *\n * - `closed`: Normal operation, tracks failures in a sliding window\n * - `open`: Failed state, fallback is used until `resetAfter` milliseconds\n * - `halfOpen`: Testing recovery, allows trial calls\n * - `disposed`: Terminal state, all calls rejected\n *\n * When the failure rate exceeds `errorThreshold` within the `errorWindow`, the\n * circuit opens and rejects calls (using fallback if provided) for `resetAfter`\n * milliseconds. After this period, it transitions to half-open and allows up\n * to `minimumCandidates` concurrent trial calls. If their failure rate stays\n * at or below the threshold, the circuit closes; otherwise it reopens.\n *\n * @example\n * ```ts\n * const protectedFn = createCircuitBreaker(unreliableApiCall, {\n * errorThreshold: 0.5,\n * errorWindow: 10_000,\n * resetAfter: 30_000,\n * fallback: () => cachedResponse,\n * })\n *\n * try {\n * const result = await protectedFn(arg1, arg2)\n * } catch (error) {\n * console.error('Circuit breaker rejected call:', error)\n * }\n *\n * console.log(protectedFn.getState()) // 'closed' | 'open' | 'halfOpen' | 'disposed'\n * protectedFn[Symbol.dispose]() // Clean up timers and resources\n * ```\n */\nexport function createCircuitBreaker<Ret, Args extends unknown[]>(\n\tmain: MainFn<Ret, Args>,\n\toptions: CircuitBreakerOptions<MainFn<Ret, Args>> = {},\n): CircuitBreakerProtectedFn<Ret, Args> {\n\tconst {\n\t\terrorIsTransient,\n\t\terrorThreshold,\n\t\terrorWindow,\n\t\tfallback,\n\t\tminimumCandidates,\n\t\tonClose,\n\t\tonHalfOpen,\n\t\tonOpen,\n\t\tresetAfter,\n\t\tretryDelay,\n\t\tretryLimit,\n\t\tretryTest,\n\t\ttimeout,\n\t} = parseOptions(options)\n\n\tlet state = createState(\"closed\")\n\n\tasync function tryCall(\n\t\tcurrent: CircuitInternalState,\n\t\targs: Args,\n\t): Promise<Ret> {\n\t\tconst { history } = current\n\t\tconst request = promiseTry(() => main(...args))\n\n\t\tlet historyItem: HistoryEntry | undefined = { status: \"pending\" }\n\t\thistory.set(request, historyItem)\n\n\t\ttry {\n\t\t\tconst result =\n\t\t\t\ttimeout > 0\n\t\t\t\t\t? await abortable(AbortSignal.timeout(timeout), request)\n\t\t\t\t\t: await request\n\t\t\thistoryItem.status = \"resolved\"\n\t\t\treturn result\n\t\t} catch (cause) {\n\t\t\thistoryItem.status = \"rejected\"\n\t\t\t// Drop this request if it's a transient error that shouldn't count\n\t\t\t// towards the failure rate\n\t\t\tconst isTransient = errorIsTransient(cause)\n\t\t\tif (isTransient) historyItem = undefined\n\n\t\t\t// Wrap the error in a CircuitError to provide additional context and\n\t\t\t// control flow handling.\n\t\t\tthrow new CircuitError(\"CALL_FAILURE\", { cause, isTransient })\n\t\t} finally {\n\t\t\t// Remove the request if it was a transient failure, or if it's stale.\n\t\t\tif (!historyItem || state !== current) history.delete(request)\n\t\t\t// Keep the request in history until the end of the error window, or until\n\t\t\t// the circuit transitions.\n\t\t\telse {\n\t\t\t\tconst { signal } = current.controller\n\t\t\t\tdelayMs(errorWindow, signal)\n\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t.finally(() => history.delete(request))\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction calculateFailureRate(): number {\n\t\tlet failures = 0\n\t\tlet total = 0\n\t\tfor (const { status } of state.history.values()) {\n\t\t\tif (status === \"rejected\") failures++\n\t\t\tif (status !== \"pending\") total++\n\t\t}\n\t\tif (!total || total < minimumCandidates) return 0\n\t\treturn failures / total\n\t}\n\n\tfunction transitionTo(\n\t\ttoStatus: StateName,\n\t\tfailureCause?: unknown,\n\t): CircuitInternalState {\n\t\tassertTransition(state.status, toStatus)\n\t\tstate.controller.abort()\n\t\treturn (state = createState(toStatus, failureCause))\n\t}\n\n\tasync function transitionToOpen(error: CircuitError): Promise<void> {\n\t\t// Race guard: a concurrent failure may have already changed state.\n\t\tif (state.status !== \"closed\" && state.status !== \"halfOpen\") return\n\n\t\tconst cause = error.cause ?? error\n\t\tconst nextState = transitionTo(\"open\", cause)\n\t\tif (onOpen) setImmediate(onOpen, cause)\n\n\t\tconst { signal } = nextState.controller\n\t\tawait delayMs(resetAfter, signal)\n\t\tif (state === nextState) transitionToHalfOpen()\n\t}\n\n\tfunction transitionToHalfOpen(): void {\n\t\ttransitionTo(\"halfOpen\", state.failureCause)\n\t\tif (onHalfOpen) setImmediate(onHalfOpen)\n\t}\n\n\tfunction transitionToClosed(): void {\n\t\ttransitionTo(\"closed\")\n\t\tif (onClose) setImmediate(onClose)\n\t}\n\n\tfunction guardIsCurrent(\n\t\tcurrent: CircuitInternalState,\n\t\terror: unknown,\n\t): error is CircuitError {\n\t\tif (!(error instanceof CircuitError)) throw error\n\t\t// Transient errors shouldn't affect the circuit breaker's state. Re-throw\n\t\t// the original cause of the error.\n\t\tif (error.isTransient) throw error.cause\n\n\t\t// If the circuit breaker was disposed mid-flight, surface the underlying\n\t\t// cause of the in-flight call rather than the dispose error.\n\t\tif (state.status === \"disposed\")\n\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\tthrow error.cause ?? new CircuitError(\"DISPOSED\")\n\n\t\t// If the circuit breaker transitioned states, try again.\n\t\treturn state === current\n\t}\n\n\tasync function protectedFn(...args: Args): Promise<Ret> {\n\t\tlet lastError: CircuitError | undefined\n\t\tlet retries = 0\n\t\tdo {\n\t\t\tconst current = state\n\t\t\tlastError = undefined\n\n\t\t\t// Closed: Normal Operation\n\t\t\tif (current.status === \"closed\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) {\n\t\t\t\t\t\tlastError = error\n\t\t\t\t\t\t// Determine if the failure rate should open the circuit.\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\tif (rate > errorThreshold) transitionToOpen(error).catch(noop)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Half-Open: Execute trial calls until we have enough candidates.\n\t\t\telse if (\n\t\t\t\tcurrent.status === \"halfOpen\" &&\n\t\t\t\tcurrent.history.size < minimumCandidates\n\t\t\t) {\n\t\t\t\ttry {\n\t\t\t\t\treturn await tryCall(current, args)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (guardIsCurrent(current, error)) lastError = error\n\t\t\t\t\tbreak\n\t\t\t\t} finally {\n\t\t\t\t\t// Do nothing until we have enough candidates to make a decision.\n\t\t\t\t\tif (state === current && current.history.size >= minimumCandidates) {\n\t\t\t\t\t\tconst rate = (current.failureRate = calculateFailureRate())\n\t\t\t\t\t\t// Determine if the failure rate should re-open the circuit or\n\t\t\t\t\t\t// if it is healthy enough to close it again.\n\t\t\t\t\t\tif (rate > errorThreshold && lastError)\n\t\t\t\t\t\t\ttransitionToOpen(lastError).catch(noop)\n\t\t\t\t\t\telse if (rate <= errorThreshold) transitionToClosed()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Open: Skip calls and immediately return fallback if available.\n\t\t\telse if (current.status === \"open\" || current.status === \"halfOpen\") {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Disposed: Reject all calls with dispose error.\n\t\t\telse throw current.failureCause\n\t\t} while (\n\t\t\tawait shouldContinue({\n\t\t\t\tretries: ++retries,\n\t\t\t\tlastError: lastError?.cause ?? lastError,\n\t\t\t\tretryDelay,\n\t\t\t\tretryLimit,\n\t\t\t\tretryTest,\n\t\t\t\tsignal: state.controller.signal,\n\t\t\t}).catch((error: CircuitError) => {\n\t\t\t\tlastError = error\n\t\t\t\treturn false\n\t\t\t})\n\t\t)\n\n\t\tif (!fallback) throw lastError ?? state.failureCause\n\t\treturn fallback(...args)\n\t}\n\n\tfunction dispose(disposeMessage = \"ERR_CIRCUIT_BREAKER_DISPOSED\"): void {\n\t\tif (state.status === \"disposed\") return\n\t\ttransitionTo(\"disposed\", new ReferenceError(disposeMessage))\n\t\tmain[Symbol.dispose]?.()\n\t}\n\n\tconst wrapped = protectedFn as CircuitBreakerProtectedFn<Ret, Args>\n\twrapped[Symbol.dispose] = () => dispose()\n\twrapped.dispose = dispose\n\twrapped.getFailureRate = () => state.failureRate\n\twrapped.getLatestError = () => state.failureCause\n\twrapped.getState = () => state.status\n\n\treturn wrapped\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "breaker-box",
3
- "version": "8.1.0",
3
+ "version": "9.0.0",
4
4
  "description": "A zero-dependency circuit breaker implementation for Node.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,12 +11,12 @@
11
11
  "types": "./dist/index.d.cts",
12
12
  "exports": {
13
13
  "require": {
14
- "default": "./dist/index.cjs",
15
- "types": "./dist/index.d.cts"
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
16
  },
17
17
  "import": {
18
- "default": "./dist/index.mjs",
19
- "types": "./dist/index.d.mts"
18
+ "types": "./dist/index.d.mts",
19
+ "default": "./dist/index.mjs"
20
20
  }
21
21
  },
22
22
  "files": [