breaker-box 8.0.0 → 8.1.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/dist/index.cjs CHANGED
@@ -9,6 +9,13 @@ 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
+ }
12
19
  const delayMs = (ms, signal) => {
13
20
  if (!Number.isFinite(ms) || ms < 0) {
14
21
  throw new RangeError(
@@ -47,10 +54,12 @@ function promiseTry(fn) {
47
54
  return Promise.reject(error);
48
55
  }
49
56
  }
50
- async function shouldRetry(options) {
57
+ async function shouldContinue(options) {
51
58
  const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
52
- if (retries >= retryLimit) throw lastError;
53
- if (!retryTest(lastError)) throw lastError;
59
+ if (retries >= retryLimit)
60
+ throw new CircuitError("MAX_RETRIES", { cause: lastError });
61
+ if (!retryTest(lastError))
62
+ throw new CircuitError("NON_RETRYABLE", { cause: lastError });
54
63
  try {
55
64
  if (!retryDelay) return true;
56
65
  else if (typeof retryDelay === "number") await delayMs(retryDelay, signal);
@@ -92,12 +101,11 @@ function withRetry$1(main, options = {}) {
92
101
  }
93
102
 
94
103
  function withTimeout$1(main, timeoutMs, timeoutMessage = "ERR_CIRCUIT_BREAKER_TIMEOUT") {
95
- const error = new Error(timeoutMessage);
96
104
  const controller = new AbortController();
97
105
  const { signal } = controller;
98
106
  function withTimeoutFunction(...args) {
99
107
  return new Promise((resolve, reject) => {
100
- const timer = setTimeout(reject, timeoutMs, error);
108
+ const timer = setTimeout(reject, timeoutMs, new Error(timeoutMessage));
101
109
  abortable(signal, main(...args)).then(resolve, reject).finally(() => clearTimeout(timer));
102
110
  });
103
111
  }
@@ -223,13 +231,6 @@ function assertTransition(from, to) {
223
231
  `Invalid transition from ${from} to ${to}`
224
232
  );
225
233
  }
226
- class CircuitError extends Error {
227
- isTransient;
228
- constructor(message, options) {
229
- super(`ERR_CIRCUIT_BREAKER_${message}`, options);
230
- this.isTransient = options?.isTransient ?? false;
231
- }
232
- }
233
234
  function createState(status, failureCause) {
234
235
  const controller = new AbortController();
235
236
  return {
@@ -305,7 +306,7 @@ function createCircuitBreaker(main, options = {}) {
305
306
  if (state === nextState) transitionToHalfOpen();
306
307
  }
307
308
  function transitionToHalfOpen() {
308
- transitionTo("halfOpen");
309
+ transitionTo("halfOpen", state.failureCause);
309
310
  if (onHalfOpen) setImmediate(onHalfOpen);
310
311
  }
311
312
  function transitionToClosed() {
@@ -324,6 +325,7 @@ function createCircuitBreaker(main, options = {}) {
324
325
  let retries = 0;
325
326
  do {
326
327
  const current = state;
328
+ lastError = void 0;
327
329
  if (current.status === "closed") {
328
330
  try {
329
331
  return await tryCall(current, args);
@@ -339,6 +341,7 @@ function createCircuitBreaker(main, options = {}) {
339
341
  return await tryCall(current, args);
340
342
  } catch (error) {
341
343
  if (guardIsCurrent(current, error)) lastError = error;
344
+ break;
342
345
  } finally {
343
346
  if (state === current && current.history.size >= minimumCandidates) {
344
347
  const rate = current.failureRate = calculateFailureRate();
@@ -348,23 +351,21 @@ function createCircuitBreaker(main, options = {}) {
348
351
  }
349
352
  }
350
353
  } else if (current.status === "open" || current.status === "halfOpen") {
351
- if (!fallback) {
352
- throw (
353
- // eslint-disable-next-line @typescript-eslint/only-throw-error
354
- current.failureCause ?? new CircuitError("OPEN", { cause: current.failureCause })
355
- );
356
- }
357
- return await fallback(...args);
354
+ break;
358
355
  } else throw current.failureCause;
359
- } while (await shouldRetry({
356
+ } while (await shouldContinue({
360
357
  retries: ++retries,
361
- lastError,
358
+ lastError: lastError?.cause ?? lastError,
362
359
  retryDelay,
363
360
  retryLimit,
364
361
  retryTest,
365
362
  signal: state.controller.signal
363
+ }).catch((error) => {
364
+ lastError = error;
365
+ return false;
366
366
  }));
367
- throw new Error("unknown error in circuit breaker retry logic");
367
+ if (!fallback) throw lastError ?? state.failureCause;
368
+ return fallback(...args);
368
369
  }
369
370
  function dispose(disposeMessage = "ERR_CIRCUIT_BREAKER_DISPOSED") {
370
371
  if (state.status === "disposed") return;
@@ -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\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 shouldRetry(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) throw lastError\n\tif (!retryTest(lastError)) throw 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 error = new Error(timeoutMessage)\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, error)\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\tabortable,\n\tassert,\n\tdelayMs,\n\tnoop,\n\tpromiseTry,\n\tshouldRetry,\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\nclass 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\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\")\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\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} 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\tif (!fallback) {\n\t\t\t\t\tthrow (\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\t\t\t\tcurrent.failureCause ??\n\t\t\t\t\t\tnew CircuitError(\"OPEN\", { cause: current.failureCause })\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\treturn await fallback(...args)\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 shouldRetry({\n\t\t\t\tretries: ++retries,\n\t\t\t\tlastError,\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})\n\t\t)\n\t\tthrow new Error(\"unknown error in circuit breaker retry logic\")\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/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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"}
package/dist/index.mjs CHANGED
@@ -7,6 +7,13 @@ 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
+ }
10
17
  const delayMs = (ms, signal) => {
11
18
  if (!Number.isFinite(ms) || ms < 0) {
12
19
  throw new RangeError(
@@ -45,10 +52,12 @@ function promiseTry(fn) {
45
52
  return Promise.reject(error);
46
53
  }
47
54
  }
48
- async function shouldRetry(options) {
55
+ async function shouldContinue(options) {
49
56
  const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
50
- if (retries >= retryLimit) throw lastError;
51
- if (!retryTest(lastError)) throw lastError;
57
+ if (retries >= retryLimit)
58
+ throw new CircuitError("MAX_RETRIES", { cause: lastError });
59
+ if (!retryTest(lastError))
60
+ throw new CircuitError("NON_RETRYABLE", { cause: lastError });
52
61
  try {
53
62
  if (!retryDelay) return true;
54
63
  else if (typeof retryDelay === "number") await delayMs(retryDelay, signal);
@@ -90,12 +99,11 @@ function withRetry$1(main, options = {}) {
90
99
  }
91
100
 
92
101
  function withTimeout$1(main, timeoutMs, timeoutMessage = "ERR_CIRCUIT_BREAKER_TIMEOUT") {
93
- const error = new Error(timeoutMessage);
94
102
  const controller = new AbortController();
95
103
  const { signal } = controller;
96
104
  function withTimeoutFunction(...args) {
97
105
  return new Promise((resolve, reject) => {
98
- const timer = setTimeout(reject, timeoutMs, error);
106
+ const timer = setTimeout(reject, timeoutMs, new Error(timeoutMessage));
99
107
  abortable(signal, main(...args)).then(resolve, reject).finally(() => clearTimeout(timer));
100
108
  });
101
109
  }
@@ -221,13 +229,6 @@ function assertTransition(from, to) {
221
229
  `Invalid transition from ${from} to ${to}`
222
230
  );
223
231
  }
224
- class CircuitError extends Error {
225
- isTransient;
226
- constructor(message, options) {
227
- super(`ERR_CIRCUIT_BREAKER_${message}`, options);
228
- this.isTransient = options?.isTransient ?? false;
229
- }
230
- }
231
232
  function createState(status, failureCause) {
232
233
  const controller = new AbortController();
233
234
  return {
@@ -303,7 +304,7 @@ function createCircuitBreaker(main, options = {}) {
303
304
  if (state === nextState) transitionToHalfOpen();
304
305
  }
305
306
  function transitionToHalfOpen() {
306
- transitionTo("halfOpen");
307
+ transitionTo("halfOpen", state.failureCause);
307
308
  if (onHalfOpen) setImmediate(onHalfOpen);
308
309
  }
309
310
  function transitionToClosed() {
@@ -322,6 +323,7 @@ function createCircuitBreaker(main, options = {}) {
322
323
  let retries = 0;
323
324
  do {
324
325
  const current = state;
326
+ lastError = void 0;
325
327
  if (current.status === "closed") {
326
328
  try {
327
329
  return await tryCall(current, args);
@@ -337,6 +339,7 @@ function createCircuitBreaker(main, options = {}) {
337
339
  return await tryCall(current, args);
338
340
  } catch (error) {
339
341
  if (guardIsCurrent(current, error)) lastError = error;
342
+ break;
340
343
  } finally {
341
344
  if (state === current && current.history.size >= minimumCandidates) {
342
345
  const rate = current.failureRate = calculateFailureRate();
@@ -346,23 +349,21 @@ function createCircuitBreaker(main, options = {}) {
346
349
  }
347
350
  }
348
351
  } else if (current.status === "open" || current.status === "halfOpen") {
349
- if (!fallback) {
350
- throw (
351
- // eslint-disable-next-line @typescript-eslint/only-throw-error
352
- current.failureCause ?? new CircuitError("OPEN", { cause: current.failureCause })
353
- );
354
- }
355
- return await fallback(...args);
352
+ break;
356
353
  } else throw current.failureCause;
357
- } while (await shouldRetry({
354
+ } while (await shouldContinue({
358
355
  retries: ++retries,
359
- lastError,
356
+ lastError: lastError?.cause ?? lastError,
360
357
  retryDelay,
361
358
  retryLimit,
362
359
  retryTest,
363
360
  signal: state.controller.signal
361
+ }).catch((error) => {
362
+ lastError = error;
363
+ return false;
364
364
  }));
365
- throw new Error("unknown error in circuit breaker retry logic");
365
+ if (!fallback) throw lastError ?? state.failureCause;
366
+ return fallback(...args);
366
367
  }
367
368
  function dispose(disposeMessage = "ERR_CIRCUIT_BREAKER_DISPOSED") {
368
369
  if (state.status === "disposed") return;
@@ -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\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 shouldRetry(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) throw lastError\n\tif (!retryTest(lastError)) throw 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 error = new Error(timeoutMessage)\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, error)\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\tabortable,\n\tassert,\n\tdelayMs,\n\tnoop,\n\tpromiseTry,\n\tshouldRetry,\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\nclass 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\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\")\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\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} 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\tif (!fallback) {\n\t\t\t\t\tthrow (\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/only-throw-error\n\t\t\t\t\t\tcurrent.failureCause ??\n\t\t\t\t\t\tnew CircuitError(\"OPEN\", { cause: current.failureCause })\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\treturn await fallback(...args)\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 shouldRetry({\n\t\t\t\tretries: ++retries,\n\t\t\t\tlastError,\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})\n\t\t)\n\t\tthrow new Error(\"unknown error in circuit breaker retry logic\")\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.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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "breaker-box",
3
- "version": "8.0.0",
3
+ "version": "8.1.0",
4
4
  "description": "A zero-dependency circuit breaker implementation for Node.js",
5
5
  "repository": {
6
6
  "type": "git",