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 +24 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +24 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
57
|
+
async function shouldContinue(options) {
|
|
51
58
|
const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
|
|
52
|
-
if (retries >= retryLimit)
|
|
53
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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;
|
package/dist/index.cjs.map
CHANGED
|
@@ -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
|
|
55
|
+
async function shouldContinue(options) {
|
|
49
56
|
const { retries, lastError, retryDelay, retryLimit, retryTest, signal } = options;
|
|
50
|
-
if (retries >= retryLimit)
|
|
51
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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;
|
package/dist/index.mjs.map
CHANGED
|
@@ -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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"}
|