{"version":3,"sources":["../../src/retry/CircuitBreaker.ts","../../src/retry/SmartRetry.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { CircuitBreakerOptions, CircuitState } from './types.js';\n\n/**\n * Circuit Breaker — protects your app from cascading failures.\n *\n * States:\n * - **CLOSED** (normal): requests flow through; failures are counted.\n * - **OPEN** (tripped): all requests fail fast — no upstream calls made.\n * - **HALF_OPEN** (testing): a limited number of requests probe if recovery happened.\n *\n * @example\n * const breaker = new CircuitBreaker({ threshold: 5, resetAfter: 30_000 });\n * await breaker.execute(() => fetch('/api/payments'));\n */\nexport class CircuitBreaker {\n  private state: CircuitState = 'CLOSED';\n  private failureCount = 0;\n  private successCount = 0;\n  private openedAt = 0;\n\n  private readonly threshold: number;\n  private readonly resetAfter: number;\n  private readonly halfOpenSuccesses: number;\n\n  constructor(options: CircuitBreakerOptions = {}) {\n    this.threshold = options.threshold ?? 5;\n    this.resetAfter = options.resetAfter ?? 30_000;\n    this.halfOpenSuccesses = options.halfOpenSuccesses ?? 2;\n  }\n\n  /** Current state of the circuit */\n  get currentState(): CircuitState {\n    return this.state;\n  }\n\n  /**\n   * Execute `fn` through the circuit breaker.\n   * Throws `CircuitOpenError` when the circuit is OPEN.\n   */\n  async execute<T>(fn: () => Promise<T>): Promise<T> {\n    this.transitionIfNeeded();\n\n    if (this.state === 'OPEN') {\n      throw new CircuitOpenError(\n        `Circuit is OPEN — upstream failures: ${this.failureCount}. ` +\n        `Will retry after ${Math.round((this.resetAfter - (Date.now() - this.openedAt)) / 1000)}s.`,\n      );\n    }\n\n    try {\n      const result = await fn();\n      this.onSuccess();\n      return result;\n    } catch (error) {\n      this.onFailure();\n      throw error;\n    }\n  }\n\n  /** Reset the circuit to CLOSED (useful in tests or manual recovery) */\n  reset(): void {\n    this.state = 'CLOSED';\n    this.failureCount = 0;\n    this.successCount = 0;\n  }\n\n  // ─── Private ─────────────────────────────────────────────────────────────────\n\n  private onSuccess(): void {\n    this.failureCount = 0;\n    if (this.state === 'HALF_OPEN') {\n      this.successCount++;\n      if (this.successCount >= this.halfOpenSuccesses) {\n        this.state = 'CLOSED';\n        this.successCount = 0;\n      }\n    }\n  }\n\n  private onFailure(): void {\n    this.failureCount++;\n    if (this.state === 'HALF_OPEN') {\n      // Probe failed — reopen immediately\n      this.trip();\n    } else if (this.failureCount >= this.threshold) {\n      this.trip();\n    }\n  }\n\n  private trip(): void {\n    this.state = 'OPEN';\n    this.openedAt = Date.now();\n    this.successCount = 0;\n  }\n\n  private transitionIfNeeded(): void {\n    if (this.state === 'OPEN' && Date.now() - this.openedAt >= this.resetAfter) {\n      this.state = 'HALF_OPEN';\n      this.failureCount = 0;\n    }\n  }\n}\n\n/**\n * Thrown when a call is rejected because the circuit is open.\n */\nexport class CircuitOpenError extends Error {\n  override readonly name = 'CircuitOpenError';\n  constructor(message: string) {\n    super(message);\n  }\n}\n","import { CircuitBreaker } from './CircuitBreaker.js';\nimport type { SmartRetryOptions } from './types.js';\n\n/**\n * Error thrown when all retry attempts are exhausted.\n */\nexport class RetryExhaustedError extends Error {\n  override readonly name = 'RetryExhaustedError';\n  readonly attempts: number;\n  readonly lastError: unknown;\n\n  constructor(attempts: number, lastError: unknown) {\n    const msg = lastError instanceof Error ? lastError.message : String(lastError);\n    super(`All ${attempts} attempt(s) failed. Last error: ${msg}`);\n    this.attempts = attempts;\n    this.lastError = lastError;\n  }\n}\n\n/**\n * Error thrown when a single attempt exceeds the configured timeout.\n */\nexport class TimeoutError extends Error {\n  override readonly name = 'TimeoutError';\n  constructor(timeoutMs: number) {\n    super(`Operation timed out after ${timeoutMs}ms`);\n  }\n}\n\n/**\n * SmartRetry — production-grade retry logic with exponential backoff, jitter,\n * per-attempt timeouts, and an optional circuit breaker.\n *\n * @example\n * // Simple: 3 attempts, exponential backoff\n * const data = await retry(() => fetch('/api/data').then(r => r.json()));\n *\n * // Advanced: with circuit breaker\n * const retry = new SmartRetry({\n *   attempts: 5,\n *   timeout: 5_000,\n *   circuitBreaker: { threshold: 5, resetAfter: 30_000 },\n * });\n * const result = await retry.execute(() => callExternalApi());\n */\nexport class SmartRetry {\n  private readonly attempts: number;\n  private readonly baseDelay: number;\n  private readonly maxDelay: number;\n  private readonly jitter: number;\n  private readonly timeout: number;\n  private readonly shouldRetry: (error: unknown, attempt: number) => boolean;\n  private readonly onRetry: ((error: unknown, attempt: number, delayMs: number) => void) | undefined;\n  private readonly breaker: CircuitBreaker | undefined;\n\n  constructor(options: SmartRetryOptions = {}) {\n    this.attempts = options.attempts ?? 3;\n    this.baseDelay = options.baseDelay ?? 500;\n    this.maxDelay = options.maxDelay ?? 30_000;\n    this.jitter = options.jitter ?? 0.2;\n    this.timeout = options.timeout ?? 0;\n    this.shouldRetry = options.shouldRetry ?? (() => true);\n    this.onRetry = options.onRetry;\n    this.breaker = options.circuitBreaker\n      ? new CircuitBreaker(options.circuitBreaker)\n      : undefined;\n  }\n\n  /**\n   * Execute `fn` with retry logic applied.\n   */\n  async execute<T>(fn: () => Promise<T>): Promise<T> {\n    let lastError: unknown;\n\n    for (let attempt = 1; attempt <= this.attempts; attempt++) {\n      try {\n        const result = await this.runWithTimeout(\n          this.breaker ? () => this.breaker!.execute(fn) : fn,\n        );\n        return result;\n      } catch (error) {\n        lastError = error;\n\n        const isLastAttempt = attempt === this.attempts;\n        if (isLastAttempt || !this.shouldRetry(error, attempt)) {\n          break;\n        }\n\n        const delay = this.calculateDelay(attempt);\n        this.onRetry?.(error, attempt, delay);\n        await this.sleep(delay);\n      }\n    }\n\n    throw new RetryExhaustedError(this.attempts, lastError);\n  }\n\n  /** Current circuit breaker state (undefined if no breaker configured) */\n  get circuitState(): string | undefined {\n    return this.breaker?.currentState;\n  }\n\n  /** Manually reset the circuit breaker */\n  resetCircuit(): void {\n    this.breaker?.reset();\n  }\n\n  // ─── Private ─────────────────────────────────────────────────────────────────\n\n  private async runWithTimeout<T>(fn: () => Promise<T>): Promise<T> {\n    if (!this.timeout) return fn();\n\n    return new Promise<T>((resolve, reject) => {\n      const timer = setTimeout(\n        () => reject(new TimeoutError(this.timeout)),\n        this.timeout,\n      );\n\n      fn().then(\n        (value) => { clearTimeout(timer); resolve(value); },\n        (error: unknown) => { clearTimeout(timer); reject(error); },\n      );\n    });\n  }\n\n  /**\n   * Exponential backoff with jitter:\n   * delay = clamp(baseDelay * 2^(attempt-1) ± jitter%, 0, maxDelay)\n   */\n  private calculateDelay(attempt: number): number {\n    const exponential = this.baseDelay * Math.pow(2, attempt - 1);\n    const capped = Math.min(exponential, this.maxDelay);\n    const delta = capped * this.jitter;\n    const jittered = capped + (Math.random() * 2 - 1) * delta;\n    return Math.max(0, Math.round(jittered));\n  }\n\n  private sleep(ms: number): Promise<void> {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n  }\n}\n\n/**\n * Convenience function for one-off retries.\n *\n * @example\n * const data = await retry(() => api.getData(), { attempts: 3, timeout: 5000 });\n */\nexport async function retry<T>(\n  fn: () => Promise<T>,\n  options: SmartRetryOptions = {},\n): Promise<T> {\n  return new SmartRetry(options).execute(fn);\n}\n"]}