{"version":3,"file":"enhanced-interceptors.mjs","sources":["../../../src/lib/services/enhanced-interceptors.ts"],"sourcesContent":["/**\n * @file Enhanced Interceptors\n * @description Production-grade interceptor system with priority ordering,\n * distributed tracing, circuit breaker pattern, and error recovery.\n * Designed for microservices resilience.\n */\n\nimport { type HttpRequestConfig, type HttpResponse, HttpError } from './http';\nimport {\n  DEFAULT_TIMEOUT,\n  DEFAULT_RETRY_BASE_DELAY,\n  DEFAULT_RETRY_MAX_DELAY,\n  DEFAULT_SLOW_REQUEST_THRESHOLD,\n} from '@/lib/core/config/constants';\n\n// =============================================================================\n// TYPE DEFINITIONS\n// =============================================================================\n\n/**\n * Interceptor priority levels\n */\nexport enum InterceptorPriority {\n  /** Execute first - critical operations like tracing */\n  HIGHEST = 0,\n  /** Execute early - auth, correlation */\n  HIGH = 25,\n  /** Default priority */\n  NORMAL = 50,\n  /** Execute later - logging, metrics */\n  LOW = 75,\n  /** Execute last - cleanup, timing */\n  LOWEST = 100,\n}\n\n/**\n * Interceptor context for sharing state between interceptors\n */\nexport interface InterceptorContext {\n  /** Distributed trace ID */\n  traceId: string;\n  /** Current span ID */\n  spanId: string;\n  /** Parent span ID for nested calls */\n  parentSpanId?: string;\n  /** Request start time */\n  startTime: number;\n  /** Shared metadata between interceptors */\n  metadata: Map<string, unknown>;\n  /** Tags for categorization */\n  tags: string[];\n  /** Retry attempt number */\n  retryAttempt: number;\n  /** Original request config (before modifications) */\n  originalConfig: HttpRequestConfig;\n}\n\n/**\n * Request interceptor with context awareness\n */\nexport interface ContextualRequestInterceptor {\n  /** Unique name for the interceptor */\n  name: string;\n  /** Execution priority (lower = earlier) */\n  priority: number;\n  /** Whether interceptor is enabled */\n  enabled?: boolean;\n  /** Intercept function */\n  intercept: (\n    config: HttpRequestConfig,\n    context: InterceptorContext\n  ) => HttpRequestConfig | Promise<HttpRequestConfig>;\n  /** Error callback */\n  onError?: (error: Error, context: InterceptorContext) => void;\n}\n\n/**\n * Response interceptor with context awareness\n */\nexport interface ContextualResponseInterceptor<T = unknown> {\n  /** Unique name for the interceptor */\n  name: string;\n  /** Execution priority (lower = earlier) */\n  priority: number;\n  /** Whether interceptor is enabled */\n  enabled?: boolean;\n  /** Intercept function */\n  intercept: (\n    response: HttpResponse<T>,\n    context: InterceptorContext\n  ) => HttpResponse<T> | Promise<HttpResponse<T>>;\n  /** Error callback */\n  onError?: (error: Error, context: InterceptorContext) => void;\n}\n\n/**\n * Error interceptor with recovery support\n */\nexport interface ContextualErrorInterceptor {\n  /** Unique name for the interceptor */\n  name: string;\n  /** Execution priority (lower = earlier) */\n  priority: number;\n  /** Whether interceptor is enabled */\n  enabled?: boolean;\n  /** Intercept function - can return recovered response */\n  intercept: (\n    error: HttpError,\n    context: InterceptorContext\n  ) => HttpError | Promise<HttpError | HttpResponse>;\n  /** Check if this interceptor can handle the error */\n  canHandle?: (error: HttpError) => boolean;\n}\n\n// =============================================================================\n// INTERCEPTOR CHAIN\n// =============================================================================\n\n/**\n * Interceptor chain manager with priority ordering\n */\nexport class InterceptorChain {\n  private requestInterceptors: ContextualRequestInterceptor[] = [];\n  private responseInterceptors: ContextualResponseInterceptor[] = [];\n  private errorInterceptors: ContextualErrorInterceptor[] = [];\n\n  /**\n   * Add request interceptor with priority ordering\n   */\n  addRequestInterceptor(interceptor: ContextualRequestInterceptor): () => void {\n    this.requestInterceptors.push(interceptor);\n    this.requestInterceptors.sort((a, b) => a.priority - b.priority);\n\n    return () => {\n      const index = this.requestInterceptors.indexOf(interceptor);\n      if (index !== -1) {\n        this.requestInterceptors.splice(index, 1);\n      }\n    };\n  }\n\n  /**\n   * Add response interceptor with priority ordering\n   */\n  addResponseInterceptor(interceptor: ContextualResponseInterceptor): () => void {\n    this.responseInterceptors.push(interceptor);\n    this.responseInterceptors.sort((a, b) => a.priority - b.priority);\n\n    return () => {\n      const index = this.responseInterceptors.indexOf(interceptor);\n      if (index !== -1) {\n        this.responseInterceptors.splice(index, 1);\n      }\n    };\n  }\n\n  /**\n   * Add error interceptor with priority ordering\n   */\n  addErrorInterceptor(interceptor: ContextualErrorInterceptor): () => void {\n    this.errorInterceptors.push(interceptor);\n    this.errorInterceptors.sort((a, b) => a.priority - b.priority);\n\n    return () => {\n      const index = this.errorInterceptors.indexOf(interceptor);\n      if (index !== -1) {\n        this.errorInterceptors.splice(index, 1);\n      }\n    };\n  }\n\n  /**\n   * Create new interceptor context\n   */\n  createContext(\n    config: HttpRequestConfig,\n    parentContext?: Partial<InterceptorContext>\n  ): InterceptorContext {\n    const context: InterceptorContext = {\n      traceId: parentContext?.traceId ?? crypto.randomUUID(),\n      spanId: crypto.randomUUID(),\n      startTime: performance.now(),\n      metadata: new Map(parentContext?.metadata ?? []),\n      tags: [...(parentContext?.tags ?? [])],\n      retryAttempt: parentContext?.retryAttempt ?? 0,\n      originalConfig: { ...config },\n    };\n\n    if (parentContext?.spanId !== undefined) {\n      context.parentSpanId = parentContext.spanId;\n    }\n\n    return context;\n  }\n\n  /**\n   * Execute request interceptor chain\n   */\n  async executeRequestChain(\n    config: HttpRequestConfig,\n    context: InterceptorContext\n  ): Promise<HttpRequestConfig> {\n    let processedConfig = { ...config };\n\n    for (const interceptor of this.requestInterceptors) {\n      if (interceptor.enabled === false) continue;\n\n      try {\n        processedConfig = await interceptor.intercept(processedConfig, context);\n      } catch (error) {\n        interceptor.onError?.(error as Error, context);\n        throw error;\n      }\n    }\n\n    return processedConfig;\n  }\n\n  /**\n   * Execute response interceptor chain\n   */\n  async executeResponseChain<T>(\n    response: HttpResponse<T>,\n    context: InterceptorContext\n  ): Promise<HttpResponse<T>> {\n    let processedResponse = response;\n\n    for (const interceptor of this.responseInterceptors) {\n      if (interceptor.enabled === false) continue;\n\n      try {\n        processedResponse = (await interceptor.intercept(\n          processedResponse,\n          context\n        )) as HttpResponse<T>;\n      } catch (error) {\n        interceptor.onError?.(error as Error, context);\n        throw error;\n      }\n    }\n\n    return processedResponse;\n  }\n\n  /**\n   * Execute error interceptor chain with recovery support\n   */\n  async executeErrorChain(\n    error: HttpError,\n    context: InterceptorContext\n  ): Promise<HttpError | HttpResponse> {\n    let processedError: HttpError | HttpResponse = error;\n\n    for (const interceptor of this.errorInterceptors) {\n      if (interceptor.enabled === false) continue;\n\n      // Check if interceptor can handle this error\n      if (interceptor.canHandle && processedError instanceof HttpError && !interceptor.canHandle(processedError)) {\n        continue;\n      }\n      try {\n        processedError = await interceptor.intercept(processedError instanceof HttpError ? processedError : error, context);\n\n        // If we got a response back, the error was recovered\n      } catch {\n        // Interceptor threw, continue with original error\n      }\n    }\n\n    return processedError;\n  }\n\n  /**\n   * Get all registered interceptors\n   */\n  getInterceptors(): {\n    request: ContextualRequestInterceptor[];\n    response: ContextualResponseInterceptor[];\n    error: ContextualErrorInterceptor[];\n  } {\n    return {\n      request: [...this.requestInterceptors],\n      response: [...this.responseInterceptors],\n      error: [...this.errorInterceptors],\n    };\n  }\n\n  /**\n   * Remove interceptor by name\n   */\n  removeByName(name: string): void {\n    this.requestInterceptors = this.requestInterceptors.filter((i) => i.name !== name);\n    this.responseInterceptors = this.responseInterceptors.filter((i) => i.name !== name);\n    this.errorInterceptors = this.errorInterceptors.filter((i) => i.name !== name);\n  }\n\n  /**\n   * Clear all interceptors\n   */\n  clear(): void {\n    this.requestInterceptors = [];\n    this.responseInterceptors = [];\n    this.errorInterceptors = [];\n  }\n}\n\n// =============================================================================\n// CIRCUIT BREAKER\n// =============================================================================\n\n/**\n * Circuit breaker state\n */\nexport interface CircuitBreakerState {\n  /** Number of consecutive failures */\n  failures: number;\n  /** Last failure timestamp */\n  lastFailure: number;\n  /** Current circuit state */\n  state: 'closed' | 'open' | 'half-open';\n  /** Next attempt timestamp (when open) */\n  nextAttempt: number;\n  /** Successful requests in half-open state */\n  halfOpenSuccesses: number;\n}\n\n/**\n * Circuit breaker configuration\n */\nexport interface CircuitBreakerConfig {\n  /** Number of failures before opening circuit */\n  failureThreshold?: number;\n  /** Time to wait before attempting recovery (ms) */\n  resetTimeout?: number;\n  /** Number of successful requests needed to close circuit */\n  halfOpenSuccessThreshold?: number;\n  /** Which HTTP status codes are considered failures */\n  failureStatuses?: number[];\n  /** Key extractor for service identification */\n  getServiceKey?: (config: HttpRequestConfig) => string;\n  /** Callback when circuit opens */\n  onOpen?: (serviceKey: string, state: CircuitBreakerState) => void;\n  /** Callback when circuit closes */\n  onClose?: (serviceKey: string) => void;\n  /** Callback when circuit enters half-open */\n  onHalfOpen?: (serviceKey: string) => void;\n}\n\n/**\n * Circuit breaker error\n */\nexport class CircuitBreakerError extends Error {\n  readonly isCircuitBreakerError = true;\n  readonly serviceKey: string;\n  readonly retryAfterMs: number;\n  readonly state: CircuitBreakerState;\n\n  constructor(serviceKey: string, state: CircuitBreakerState) {\n    super(`Circuit breaker open for ${serviceKey}`);\n    this.name = 'CircuitBreakerError';\n    this.serviceKey = serviceKey;\n    this.retryAfterMs = Math.max(0, state.nextAttempt - Date.now());\n    this.state = state;\n  }\n}\n\n/**\n * Create circuit breaker interceptor\n */\nexport function createCircuitBreakerInterceptor(config: CircuitBreakerConfig = {}): {\n  request: ContextualRequestInterceptor;\n  error: ContextualErrorInterceptor;\n  response: ContextualResponseInterceptor;\n  getState: (serviceKey: string) => CircuitBreakerState | undefined;\n  reset: (serviceKey: string) => void;\n  resetAll: () => void;\n} {\n  const {\n    failureThreshold = 5,\n    resetTimeout = DEFAULT_TIMEOUT,\n    halfOpenSuccessThreshold = 3,\n    failureStatuses = [500, 502, 503, 504, 0],\n    getServiceKey = (c) => {\n      try {\n        return new URL(c.url, 'http://localhost').hostname;\n      } catch {\n        return 'default';\n      }\n    },\n    onOpen,\n    onClose,\n    onHalfOpen,\n  } = config;\n\n  const circuitStates = new Map<string, CircuitBreakerState>();\n\n  function getState(key: string): CircuitBreakerState {\n    if (!circuitStates.has(key)) {\n      circuitStates.set(key, {\n        failures: 0,\n        lastFailure: 0,\n        state: 'closed',\n        nextAttempt: 0,\n        halfOpenSuccesses: 0,\n      });\n    }\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    return circuitStates.get(key)!;\n  }\n\n  function recordSuccess(key: string): void {\n    const state = getState(key);\n\n    if (state.state === 'half-open') {\n      state.halfOpenSuccesses++;\n\n      if (state.halfOpenSuccesses >= halfOpenSuccessThreshold) {\n        state.state = 'closed';\n        state.failures = 0;\n        state.halfOpenSuccesses = 0;\n        onClose?.(key);\n      }\n    } else if (state.state === 'closed' && state.failures > 0) {\n      // Reset failure count on success in closed state\n      state.failures = 0;\n    }\n  }\n\n  function recordFailure(key: string): void {\n    const state = getState(key);\n    const now = Date.now();\n\n    state.failures++;\n    state.lastFailure = now;\n\n    if (state.state === 'half-open') {\n      // Failure in half-open state re-opens circuit\n      state.state = 'open';\n      state.nextAttempt = now + resetTimeout;\n      state.halfOpenSuccesses = 0;\n      onOpen?.(key, state);\n    } else if (state.failures >= failureThreshold) {\n      state.state = 'open';\n      state.nextAttempt = now + resetTimeout;\n      onOpen?.(key, state);\n    }\n  }\n\n  const requestInterceptor: ContextualRequestInterceptor = {\n    name: 'circuitBreaker',\n    priority: InterceptorPriority.HIGH,\n    intercept: (config, context) => {\n      const key = getServiceKey(config);\n      const state = getState(key);\n      const now = Date.now();\n\n      // Check circuit state\n      if (state.state === 'open') {\n        if (now >= state.nextAttempt) {\n          // Transition to half-open\n          state.state = 'half-open';\n          state.halfOpenSuccesses = 0;\n          onHalfOpen?.(key);\n        } else {\n          // Circuit is open, reject immediately\n          throw new CircuitBreakerError(key, state);\n        }\n      }\n\n      // Store service key in context for response/error handling\n      context.metadata.set('circuitBreaker:serviceKey', key);\n\n      return config;\n    },\n  };\n\n  const responseInterceptor: ContextualResponseInterceptor = {\n    name: 'circuitBreaker',\n    priority: InterceptorPriority.LOW,\n    intercept: (response, context) => {\n      const key = context.metadata.get('circuitBreaker:serviceKey') as string;\n      if (key) {\n        recordSuccess(key);\n      }\n      return response;\n    },\n  };\n\n  const errorInterceptor: ContextualErrorInterceptor = {\n    name: 'circuitBreaker',\n    priority: InterceptorPriority.HIGH,\n    canHandle: (error) => failureStatuses.includes(error.status),\n    intercept: (error, context) => {\n      const key = context.metadata.get('circuitBreaker:serviceKey') as string;\n      if (key) {\n        recordFailure(key);\n      }\n      return error;\n    },\n  };\n\n  return {\n    request: requestInterceptor,\n    response: responseInterceptor,\n    error: errorInterceptor,\n    getState: (key) => circuitStates.get(key),\n    reset: (key) => circuitStates.delete(key),\n    resetAll: () => circuitStates.clear(),\n  };\n}\n\n// =============================================================================\n// DISTRIBUTED TRACING\n// =============================================================================\n\n/**\n * Tracing configuration\n */\nexport interface TracingConfig {\n  /** Service name for tracing */\n  serviceName?: string;\n  /** Header names for trace propagation */\n  headers?: {\n    traceId?: string;\n    spanId?: string;\n    parentSpanId?: string;\n    sampled?: string;\n  };\n  /** Sampling rate (0-1) */\n  samplingRate?: number;\n  /** Callback for trace spans */\n  onSpan?: (span: TraceSpan) => void;\n}\n\n/**\n * Trace span data\n */\nexport interface TraceSpan {\n  traceId: string;\n  spanId: string;\n  parentSpanId?: string;\n  operationName: string;\n  serviceName: string;\n  startTime: number;\n  endTime?: number;\n  duration?: number;\n  status: 'ok' | 'error';\n  tags: Record<string, string | number | boolean>;\n  logs: Array<{ timestamp: number; message: string; data?: unknown }>;\n}\n\n/**\n * Create distributed tracing interceptors\n */\nexport function createTracingInterceptors(config: TracingConfig = {}): {\n  request: ContextualRequestInterceptor;\n  response: ContextualResponseInterceptor;\n  error: ContextualErrorInterceptor;\n} {\n  const {\n    serviceName = 'frontend',\n    headers = {\n      traceId: 'X-Trace-ID',\n      spanId: 'X-Span-ID',\n      parentSpanId: 'X-Parent-Span-ID',\n      sampled: 'X-B3-Sampled',\n    },\n    samplingRate = 1.0,\n    onSpan,\n  } = config;\n\n  const activeSpans = new Map<string, TraceSpan>();\n\n  function shouldSample(): boolean {\n    return Math.random() < samplingRate;\n  }\n\n  function createSpan(context: InterceptorContext, config: HttpRequestConfig): TraceSpan {\n    const span: TraceSpan = {\n      traceId: context.traceId,\n      spanId: context.spanId,\n      operationName: `${config.method ?? 'GET'} ${config.url}`,\n      serviceName,\n      startTime: context.startTime,\n      status: 'ok',\n      tags: {\n        'http.method': config.method ?? 'GET',\n        'http.url': config.url,\n        component: 'http-client',\n      },\n      logs: [],\n    };\n\n    if (context.parentSpanId !== undefined) {\n      span.parentSpanId = context.parentSpanId;\n    }\n\n    return span;\n  }\n\n  const requestInterceptor: ContextualRequestInterceptor = {\n    name: 'tracing',\n    priority: InterceptorPriority.HIGHEST,\n    intercept: (config, context) => {\n      // Check if we should sample this request\n      const sampled = shouldSample();\n      context.metadata.set('tracing:sampled', sampled);\n\n      if (!sampled) {\n        return config;\n      }\n\n      // Create and store span\n      const span = createSpan(context, config);\n      activeSpans.set(context.spanId, span);\n\n      // Add trace headers\n      return {\n        ...config,\n        headers: {\n          ...config.headers,\n          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n          [headers.traceId!]: context.traceId,\n          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n          [headers.spanId!]: context.spanId,\n          ...(context.parentSpanId !== null &&\n          context.parentSpanId !== undefined &&\n          context.parentSpanId !== ''\n            ? {\n                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n                [headers.parentSpanId!]: context.parentSpanId,\n              }\n            : {}),\n          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n          [headers.sampled!]: '1',\n        },\n      };\n    },\n  };\n\n  const responseInterceptor: ContextualResponseInterceptor = {\n    name: 'tracing',\n    priority: InterceptorPriority.LOWEST,\n    intercept: (response, context) => {\n      const sampled = context.metadata.get('tracing:sampled');\n      if (sampled !== true) return response;\n\n      const span = activeSpans.get(context.spanId);\n      if (span) {\n        span.endTime = performance.now();\n        span.duration = span.endTime - span.startTime;\n        span.status = 'ok';\n        span.tags['http.status_code'] = response.status;\n\n        onSpan?.(span);\n        activeSpans.delete(context.spanId);\n      }\n\n      return response;\n    },\n  };\n\n  const errorInterceptor: ContextualErrorInterceptor = {\n    name: 'tracing',\n    priority: InterceptorPriority.LOWEST,\n    intercept: (error, context) => {\n      const sampled = context.metadata.get('tracing:sampled');\n      if (sampled !== true) return error;\n\n      const span = activeSpans.get(context.spanId);\n      if (span) {\n        span.endTime = performance.now();\n        span.duration = span.endTime - span.startTime;\n        span.status = 'error';\n        span.tags['http.status_code'] = error.status;\n        span.tags['error'] = true;\n        span.logs.push({\n          timestamp: performance.now(),\n          message: error.message,\n          data: { status: error.status, statusText: error.statusText },\n        });\n\n        onSpan?.(span);\n        activeSpans.delete(context.spanId);\n      }\n\n      return error;\n    },\n  };\n\n  return {\n    request: requestInterceptor,\n    response: responseInterceptor,\n    error: errorInterceptor,\n  };\n}\n\n// =============================================================================\n// CORRELATION & REQUEST ID\n// =============================================================================\n\n/**\n * Create correlation ID interceptor\n */\nexport function createCorrelationInterceptor(\n  headerName = 'X-Correlation-ID'\n): ContextualRequestInterceptor {\n  return {\n    name: 'correlation',\n    priority: InterceptorPriority.HIGHEST + 1,\n    intercept: (config, context) => {\n      const correlationId = crypto.randomUUID();\n      context.metadata.set('correlationId', correlationId);\n\n      return {\n        ...config,\n        headers: {\n          ...config.headers,\n          [headerName]: correlationId,\n        },\n      };\n    },\n  };\n}\n\n// =============================================================================\n// TIMING & PERFORMANCE\n// =============================================================================\n\n/**\n * Timing configuration\n */\nexport interface TimingConfig {\n  /** Threshold for slow request warning (ms) */\n  slowThreshold?: number;\n  /** Callback for timing data */\n  onTiming?: (data: TimingData) => void;\n  /** Log slow requests */\n  logSlowRequests?: boolean;\n}\n\n/**\n * Timing data\n */\nexport interface TimingData {\n  url: string;\n  method: string;\n  duration: number;\n  status: number;\n  traceId: string;\n  isSlow: boolean;\n}\n\n/**\n * Create timing interceptor\n */\nexport function createTimingInterceptor(config: TimingConfig = {}): ContextualResponseInterceptor {\n  const {\n    slowThreshold = DEFAULT_SLOW_REQUEST_THRESHOLD * 3,\n    onTiming,\n    logSlowRequests = true,\n  } = config;\n\n  return {\n    name: 'timing',\n    priority: InterceptorPriority.LOWEST,\n    intercept: (response, context) => {\n      const duration = performance.now() - context.startTime;\n      const isSlow = duration > slowThreshold;\n\n      const timingData: TimingData = {\n        url: response.config.url,\n        method: response.config.method ?? 'GET',\n        duration,\n        status: response.status,\n        traceId: context.traceId,\n        isSlow,\n      };\n\n      if (isSlow && logSlowRequests) {\n        console.warn(\n          `[Slow Request] ${timingData.method} ${timingData.url} took ${duration.toFixed(2)}ms`,\n          { traceId: context.traceId }\n        );\n      }\n\n      onTiming?.(timingData);\n\n      return response;\n    },\n  };\n}\n\n// =============================================================================\n// RETRY WITH BACKOFF\n// =============================================================================\n\n/**\n * Retry configuration\n */\nexport interface RetryConfig {\n  /** Maximum retry attempts */\n  maxRetries?: number;\n  /** Base delay between retries (ms) */\n  baseDelay?: number;\n  /** Maximum delay between retries (ms) */\n  maxDelay?: number;\n  /** Exponential backoff factor */\n  backoffFactor?: number;\n  /** Add jitter to delay */\n  jitter?: boolean;\n  /** Which status codes should trigger retry */\n  retryStatuses?: number[];\n  /** Retry on network errors */\n  retryOnNetworkError?: boolean;\n  /** Callback on retry */\n  onRetry?: (error: HttpError, attempt: number, delay: number) => void;\n}\n\n/**\n * Create retry interceptor with exponential backoff\n */\nexport function createRetryInterceptor(\n  config: RetryConfig = {},\n  httpClientFn: (config: HttpRequestConfig) => Promise<HttpResponse>\n): ContextualErrorInterceptor {\n  const {\n    maxRetries = 3,\n    baseDelay = DEFAULT_RETRY_BASE_DELAY,\n    maxDelay = DEFAULT_RETRY_MAX_DELAY,\n    backoffFactor = 2,\n    jitter = true,\n    retryStatuses = [500, 502, 503, 504, 429],\n    retryOnNetworkError = true,\n    onRetry,\n  } = config;\n\n  function calculateDelay(attempt: number): number {\n    let delay = Math.min(baseDelay * Math.pow(backoffFactor, attempt), maxDelay);\n\n    if (jitter) {\n      // Add random jitter (+/- 25%)\n      const jitterRange = delay * 0.25;\n      delay = delay + (Math.random() * jitterRange * 2 - jitterRange);\n    }\n\n    return Math.floor(delay);\n  }\n\n  function shouldRetry(error: HttpError): boolean {\n    if (retryOnNetworkError && error.status === 0) {\n      return true;\n    }\n    return retryStatuses.includes(error.status);\n  }\n\n  return {\n    name: 'retry',\n    priority: InterceptorPriority.NORMAL,\n    canHandle: shouldRetry,\n    intercept: async (error, context) => {\n      const attempt = context.retryAttempt;\n\n      if (attempt >= maxRetries) {\n        return error;\n      }\n\n      // Check Retry-After header for 429 responses\n      let delay = calculateDelay(attempt);\n      if (error.status === 429) {\n        const retryAfter = error.config.headers?.['Retry-After'];\n        if (retryAfter !== null && retryAfter !== undefined && retryAfter !== '') {\n          const parsed = parseInt(retryAfter, 10);\n          if (!isNaN(parsed)) {\n            delay = parsed * 1000;\n          }\n        }\n      }\n\n      onRetry?.(error, attempt + 1, delay);\n\n      // Wait before retry\n      await new Promise((resolve) => setTimeout(resolve, delay));\n\n      // Increment retry attempt in context\n      context.retryAttempt = attempt + 1;\n\n      // Retry the request\n      try {\n        return await httpClientFn(context.originalConfig);\n      } catch (retryError) {\n        if (retryError instanceof HttpError) {\n          return retryError;\n        }\n        throw retryError;\n      }\n    },\n  };\n}\n\n// =============================================================================\n// FACTORY & DEFAULTS\n// =============================================================================\n\n/**\n * Create a fully configured interceptor chain\n */\nexport function createEnhancedInterceptorChain(config?: {\n  tracing?: TracingConfig | false;\n  circuitBreaker?: CircuitBreakerConfig | false;\n  timing?: TimingConfig | false;\n  enableCorrelation?: boolean;\n}): InterceptorChain {\n  const chain = new InterceptorChain();\n\n  // Add tracing\n  if (config?.tracing !== false) {\n    const tracing = createTracingInterceptors(\n      typeof config?.tracing === 'object' ? config.tracing : {}\n    );\n    chain.addRequestInterceptor(tracing.request);\n    chain.addResponseInterceptor(tracing.response);\n    chain.addErrorInterceptor(tracing.error);\n  }\n\n  // Add correlation\n  if (config?.enableCorrelation !== false) {\n    chain.addRequestInterceptor(createCorrelationInterceptor());\n  }\n\n  // Add circuit breaker\n  if (config?.circuitBreaker !== false) {\n    const breaker = createCircuitBreakerInterceptor(\n      typeof config?.circuitBreaker === 'object' ? config.circuitBreaker : {}\n    );\n    chain.addRequestInterceptor(breaker.request);\n    chain.addResponseInterceptor(breaker.response);\n    chain.addErrorInterceptor(breaker.error);\n  }\n\n  // Add timing\n  if (config?.timing !== false) {\n    chain.addResponseInterceptor(\n      createTimingInterceptor(typeof config?.timing === 'object' ? config.timing : {})\n    );\n  }\n\n  return chain;\n}\n\n/**\n * Default interceptor chain instance\n */\nexport const enhancedInterceptorChain = createEnhancedInterceptorChain();\n"],"names":["InterceptorPriority","InterceptorChain","interceptor","a","b","index","config","parentContext","context","processedConfig","error","response","processedResponse","processedError","HttpError","name","i","CircuitBreakerError","serviceKey","state","createCircuitBreakerInterceptor","failureThreshold","resetTimeout","DEFAULT_TIMEOUT","halfOpenSuccessThreshold","failureStatuses","getServiceKey","c","onOpen","onClose","onHalfOpen","circuitStates","getState","key","recordSuccess","recordFailure","now","createTracingInterceptors","serviceName","headers","samplingRate","onSpan","activeSpans","shouldSample","createSpan","span","sampled","createCorrelationInterceptor","headerName","correlationId","createTimingInterceptor","slowThreshold","DEFAULT_SLOW_REQUEST_THRESHOLD","onTiming","logSlowRequests","duration","isSlow","timingData","createEnhancedInterceptorChain","chain","tracing","breaker","enhancedInterceptorChain"],"mappings":";;AAsBO,IAAKA,sBAAAA,OAEVA,EAAAA,EAAA,UAAU,CAAA,IAAV,WAEAA,EAAAA,EAAA,OAAO,EAAA,IAAP,QAEAA,EAAAA,EAAA,SAAS,EAAA,IAAT,UAEAA,EAAAA,EAAA,MAAM,EAAA,IAAN,OAEAA,EAAAA,EAAA,SAAS,GAAA,IAAT,UAVUA,IAAAA,KAAA,CAAA,CAAA;AAmGL,MAAMC,EAAiB;AAAA,EACpB,sBAAsD,CAAA;AAAA,EACtD,uBAAwD,CAAA;AAAA,EACxD,oBAAkD,CAAA;AAAA;AAAA;AAAA;AAAA,EAK1D,sBAAsBC,GAAuD;AAC3E,gBAAK,oBAAoB,KAAKA,CAAW,GACzC,KAAK,oBAAoB,KAAK,CAACC,GAAGC,MAAMD,EAAE,WAAWC,EAAE,QAAQ,GAExD,MAAM;AACX,YAAMC,IAAQ,KAAK,oBAAoB,QAAQH,CAAW;AAC1D,MAAIG,MAAU,MACZ,KAAK,oBAAoB,OAAOA,GAAO,CAAC;AAAA,IAE5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuBH,GAAwD;AAC7E,gBAAK,qBAAqB,KAAKA,CAAW,GAC1C,KAAK,qBAAqB,KAAK,CAACC,GAAGC,MAAMD,EAAE,WAAWC,EAAE,QAAQ,GAEzD,MAAM;AACX,YAAMC,IAAQ,KAAK,qBAAqB,QAAQH,CAAW;AAC3D,MAAIG,MAAU,MACZ,KAAK,qBAAqB,OAAOA,GAAO,CAAC;AAAA,IAE7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoBH,GAAqD;AACvE,gBAAK,kBAAkB,KAAKA,CAAW,GACvC,KAAK,kBAAkB,KAAK,CAACC,GAAGC,MAAMD,EAAE,WAAWC,EAAE,QAAQ,GAEtD,MAAM;AACX,YAAMC,IAAQ,KAAK,kBAAkB,QAAQH,CAAW;AACxD,MAAIG,MAAU,MACZ,KAAK,kBAAkB,OAAOA,GAAO,CAAC;AAAA,IAE1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cACEC,GACAC,GACoB;AACpB,UAAMC,IAA8B;AAAA,MAClC,SAASD,GAAe,WAAW,OAAO,WAAA;AAAA,MAC1C,QAAQ,OAAO,WAAA;AAAA,MACf,WAAW,YAAY,IAAA;AAAA,MACvB,UAAU,IAAI,IAAIA,GAAe,YAAY,CAAA,CAAE;AAAA,MAC/C,MAAM,CAAC,GAAIA,GAAe,QAAQ,CAAA,CAAG;AAAA,MACrC,cAAcA,GAAe,gBAAgB;AAAA,MAC7C,gBAAgB,EAAE,GAAGD,EAAA;AAAA,IAAO;AAG9B,WAAIC,GAAe,WAAW,WAC5BC,EAAQ,eAAeD,EAAc,SAGhCC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJF,GACAE,GAC4B;AAC5B,QAAIC,IAAkB,EAAE,GAAGH,EAAA;AAE3B,eAAWJ,KAAe,KAAK;AAC7B,UAAIA,EAAY,YAAY;AAE5B,YAAI;AACF,UAAAO,IAAkB,MAAMP,EAAY,UAAUO,GAAiBD,CAAO;AAAA,QACxE,SAASE,GAAO;AACd,gBAAAR,EAAY,UAAUQ,GAAgBF,CAAO,GACvCE;AAAA,QACR;AAGF,WAAOD;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBACJE,GACAH,GAC0B;AAC1B,QAAII,IAAoBD;AAExB,eAAWT,KAAe,KAAK;AAC7B,UAAIA,EAAY,YAAY;AAE5B,YAAI;AACF,UAAAU,IAAqB,MAAMV,EAAY;AAAA,YACrCU;AAAA,YACAJ;AAAA,UAAA;AAAA,QAEJ,SAASE,GAAO;AACd,gBAAAR,EAAY,UAAUQ,GAAgBF,CAAO,GACvCE;AAAA,QACR;AAGF,WAAOE;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJF,GACAF,GACmC;AACnC,QAAIK,IAA2CH;AAE/C,eAAWR,KAAe,KAAK;AAC7B,UAAIA,EAAY,YAAY,MAGxB,EAAAA,EAAY,aAAaW,aAA0BC,KAAa,CAACZ,EAAY,UAAUW,CAAc;AAGzG,YAAI;AACF,UAAAA,IAAiB,MAAMX,EAAY,UAAUW,aAA0BC,IAAYD,IAAiBH,GAAOF,CAAO;AAAA,QAGpH,QAAQ;AAAA,QAER;AAGF,WAAOK;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,kBAIE;AACA,WAAO;AAAA,MACL,SAAS,CAAC,GAAG,KAAK,mBAAmB;AAAA,MACrC,UAAU,CAAC,GAAG,KAAK,oBAAoB;AAAA,MACvC,OAAO,CAAC,GAAG,KAAK,iBAAiB;AAAA,IAAA;AAAA,EAErC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAaE,GAAoB;AAC/B,SAAK,sBAAsB,KAAK,oBAAoB,OAAO,CAACC,MAAMA,EAAE,SAASD,CAAI,GACjF,KAAK,uBAAuB,KAAK,qBAAqB,OAAO,CAACC,MAAMA,EAAE,SAASD,CAAI,GACnF,KAAK,oBAAoB,KAAK,kBAAkB,OAAO,CAACC,MAAMA,EAAE,SAASD,CAAI;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,sBAAsB,CAAA,GAC3B,KAAK,uBAAuB,CAAA,GAC5B,KAAK,oBAAoB,CAAA;AAAA,EAC3B;AACF;AA+CO,MAAME,UAA4B,MAAM;AAAA,EACpC,wBAAwB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAYC,GAAoBC,GAA4B;AAC1D,UAAM,4BAA4BD,CAAU,EAAE,GAC9C,KAAK,OAAO,uBACZ,KAAK,aAAaA,GAClB,KAAK,eAAe,KAAK,IAAI,GAAGC,EAAM,cAAc,KAAK,KAAK,GAC9D,KAAK,QAAQA;AAAA,EACf;AACF;AAKO,SAASC,EAAgCd,IAA+B,IAO7E;AACA,QAAM;AAAA,IACJ,kBAAAe,IAAmB;AAAA,IACnB,cAAAC,IAAeC;AAAA,IACf,0BAAAC,IAA2B;AAAA,IAC3B,iBAAAC,IAAkB,CAAC,KAAK,KAAK,KAAK,KAAK,CAAC;AAAA,IACxC,eAAAC,IAAgB,CAACC,MAAM;AACrB,UAAI;AACF,eAAO,IAAI,IAAIA,EAAE,KAAK,kBAAkB,EAAE;AAAA,MAC5C,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC;AAAA,IACA,YAAAC;AAAA,EAAA,IACExB,GAEEyB,wBAAoB,IAAA;AAE1B,WAASC,EAASC,GAAkC;AAClD,WAAKF,EAAc,IAAIE,CAAG,KACxBF,EAAc,IAAIE,GAAK;AAAA,MACrB,UAAU;AAAA,MACV,aAAa;AAAA,MACb,OAAO;AAAA,MACP,aAAa;AAAA,MACb,mBAAmB;AAAA,IAAA,CACpB,GAGIF,EAAc,IAAIE,CAAG;AAAA,EAC9B;AAEA,WAASC,EAAcD,GAAmB;AACxC,UAAMd,IAAQa,EAASC,CAAG;AAE1B,IAAId,EAAM,UAAU,eAClBA,EAAM,qBAEFA,EAAM,qBAAqBK,MAC7BL,EAAM,QAAQ,UACdA,EAAM,WAAW,GACjBA,EAAM,oBAAoB,GAC1BU,IAAUI,CAAG,MAENd,EAAM,UAAU,YAAYA,EAAM,WAAW,MAEtDA,EAAM,WAAW;AAAA,EAErB;AAEA,WAASgB,EAAcF,GAAmB;AACxC,UAAMd,IAAQa,EAASC,CAAG,GACpBG,IAAM,KAAK,IAAA;AAEjB,IAAAjB,EAAM,YACNA,EAAM,cAAciB,GAEhBjB,EAAM,UAAU,eAElBA,EAAM,QAAQ,QACdA,EAAM,cAAciB,IAAMd,GAC1BH,EAAM,oBAAoB,GAC1BS,IAASK,GAAKd,CAAK,KACVA,EAAM,YAAYE,MAC3BF,EAAM,QAAQ,QACdA,EAAM,cAAciB,IAAMd,GAC1BM,IAASK,GAAKd,CAAK;AAAA,EAEvB;AAuDA,SAAO;AAAA,IACL,SAtDuD;AAAA,MACvD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW,CAACb,GAAQE,MAAY;AAC9B,cAAMyB,IAAMP,EAAcpB,CAAM,GAC1Ba,IAAQa,EAASC,CAAG,GACpBG,IAAM,KAAK,IAAA;AAGjB,YAAIjB,EAAM,UAAU;AAClB,cAAIiB,KAAOjB,EAAM;AAEf,YAAAA,EAAM,QAAQ,aACdA,EAAM,oBAAoB,GAC1BW,IAAaG,CAAG;AAAA;AAGhB,kBAAM,IAAIhB,EAAoBgB,GAAKd,CAAK;AAK5C,eAAAX,EAAQ,SAAS,IAAI,6BAA6ByB,CAAG,GAE9C3B;AAAAA,MACT;AAAA,IAAA;AAAA,IA8BA,UA3ByD;AAAA,MACzD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW,CAACK,GAAUH,MAAY;AAChC,cAAMyB,IAAMzB,EAAQ,SAAS,IAAI,2BAA2B;AAC5D,eAAIyB,KACFC,EAAcD,CAAG,GAEZtB;AAAA,MACT;AAAA,IAAA;AAAA,IAmBA,OAhBmD;AAAA,MACnD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW,CAACD,MAAUe,EAAgB,SAASf,EAAM,MAAM;AAAA,MAC3D,WAAW,CAACA,GAAOF,MAAY;AAC7B,cAAMyB,IAAMzB,EAAQ,SAAS,IAAI,2BAA2B;AAC5D,eAAIyB,KACFE,EAAcF,CAAG,GAEZvB;AAAA,MACT;AAAA,IAAA;AAAA,IAOA,UAAU,CAACuB,MAAQF,EAAc,IAAIE,CAAG;AAAA,IACxC,OAAO,CAACA,MAAQF,EAAc,OAAOE,CAAG;AAAA,IACxC,UAAU,MAAMF,EAAc,MAAA;AAAA,EAAM;AAExC;AA6CO,SAASM,EAA0B/B,IAAwB,IAIhE;AACA,QAAM;AAAA,IACJ,aAAAgC,IAAc;AAAA,IACd,SAAAC,IAAU;AAAA,MACR,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,SAAS;AAAA,IAAA;AAAA,IAEX,cAAAC,IAAe;AAAA,IACf,QAAAC;AAAA,EAAA,IACEnC,GAEEoC,wBAAkB,IAAA;AAExB,WAASC,IAAwB;AAC/B,WAAO,KAAK,WAAWH;AAAA,EACzB;AAEA,WAASI,EAAWpC,GAA6BF,GAAsC;AACrF,UAAMuC,IAAkB;AAAA,MACtB,SAASrC,EAAQ;AAAA,MACjB,QAAQA,EAAQ;AAAA,MAChB,eAAe,GAAGF,EAAO,UAAU,KAAK,IAAIA,EAAO,GAAG;AAAA,MACtD,aAAAgC;AAAA,MACA,WAAW9B,EAAQ;AAAA,MACnB,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,eAAeF,EAAO,UAAU;AAAA,QAChC,YAAYA,EAAO;AAAA,QACnB,WAAW;AAAA,MAAA;AAAA,MAEb,MAAM,CAAA;AAAA,IAAC;AAGT,WAAIE,EAAQ,iBAAiB,WAC3BqC,EAAK,eAAerC,EAAQ,eAGvBqC;AAAA,EACT;AA4FA,SAAO;AAAA,IACL,SA3FuD;AAAA,MACvD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW,CAACvC,GAAQE,MAAY;AAE9B,cAAMsC,IAAUH,EAAA;AAGhB,YAFAnC,EAAQ,SAAS,IAAI,mBAAmBsC,CAAO,GAE3C,CAACA;AACH,iBAAOxC;AAIT,cAAMuC,IAAOD,EAAWpC,GAASF,CAAM;AACvC,eAAAoC,EAAY,IAAIlC,EAAQ,QAAQqC,CAAI,GAG7B;AAAA,UACL,GAAGvC;AAAAA,UACH,SAAS;AAAA,YACP,GAAGA,EAAO;AAAA;AAAA,YAEV,CAACiC,EAAQ,OAAQ,GAAG/B,EAAQ;AAAA;AAAA,YAE5B,CAAC+B,EAAQ,MAAO,GAAG/B,EAAQ;AAAA,YAC3B,GAAIA,EAAQ,iBAAiB,QAC7BA,EAAQ,iBAAiB,UACzBA,EAAQ,iBAAiB,KACrB;AAAA;AAAA,cAEE,CAAC+B,EAAQ,YAAa,GAAG/B,EAAQ;AAAA,YAAA,IAEnC,CAAA;AAAA;AAAA,YAEJ,CAAC+B,EAAQ,OAAQ,GAAG;AAAA,UAAA;AAAA,QACtB;AAAA,MAEJ;AAAA,IAAA;AAAA,IAuDA,UApDyD;AAAA,MACzD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW,CAAC5B,GAAUH,MAAY;AAEhC,YADgBA,EAAQ,SAAS,IAAI,iBAAiB,MACtC,GAAM,QAAOG;AAE7B,cAAMkC,IAAOH,EAAY,IAAIlC,EAAQ,MAAM;AAC3C,eAAIqC,MACFA,EAAK,UAAU,YAAY,IAAA,GAC3BA,EAAK,WAAWA,EAAK,UAAUA,EAAK,WACpCA,EAAK,SAAS,MACdA,EAAK,KAAK,kBAAkB,IAAIlC,EAAS,QAEzC8B,IAASI,CAAI,GACbH,EAAY,OAAOlC,EAAQ,MAAM,IAG5BG;AAAA,MACT;AAAA,IAAA;AAAA,IAkCA,OA/BmD;AAAA,MACnD,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW,CAACD,GAAOF,MAAY;AAE7B,YADgBA,EAAQ,SAAS,IAAI,iBAAiB,MACtC,GAAM,QAAOE;AAE7B,cAAMmC,IAAOH,EAAY,IAAIlC,EAAQ,MAAM;AAC3C,eAAIqC,MACFA,EAAK,UAAU,YAAY,IAAA,GAC3BA,EAAK,WAAWA,EAAK,UAAUA,EAAK,WACpCA,EAAK,SAAS,SACdA,EAAK,KAAK,kBAAkB,IAAInC,EAAM,QACtCmC,EAAK,KAAK,QAAW,IACrBA,EAAK,KAAK,KAAK;AAAA,UACb,WAAW,YAAY,IAAA;AAAA,UACvB,SAASnC,EAAM;AAAA,UACf,MAAM,EAAE,QAAQA,EAAM,QAAQ,YAAYA,EAAM,WAAA;AAAA,QAAW,CAC5D,GAED+B,IAASI,CAAI,GACbH,EAAY,OAAOlC,EAAQ,MAAM,IAG5BE;AAAA,MACT;AAAA,IAAA;AAAA,EAMO;AAEX;AASO,SAASqC,EACdC,IAAa,oBACiB;AAC9B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAAC1C,GAAQE,MAAY;AAC9B,YAAMyC,IAAgB,OAAO,WAAA;AAC7B,aAAAzC,EAAQ,SAAS,IAAI,iBAAiByC,CAAa,GAE5C;AAAA,QACL,GAAG3C;AAAA,QACH,SAAS;AAAA,UACP,GAAGA,EAAO;AAAA,UACV,CAAC0C,CAAU,GAAGC;AAAA,QAAA;AAAA,MAChB;AAAA,IAEJ;AAAA,EAAA;AAEJ;AAiCO,SAASC,EAAwB5C,IAAuB,IAAmC;AAChG,QAAM;AAAA,IACJ,eAAA6C,IAAgBC,IAAiC;AAAA,IACjD,UAAAC;AAAA,IACA,iBAAAC,IAAkB;AAAA,EAAA,IAChBhD;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW,CAACK,GAAUH,MAAY;AAChC,YAAM+C,IAAW,YAAY,IAAA,IAAQ/C,EAAQ,WACvCgD,IAASD,IAAWJ,GAEpBM,IAAyB;AAAA,QAC7B,KAAK9C,EAAS,OAAO;AAAA,QACrB,QAAQA,EAAS,OAAO,UAAU;AAAA,QAClC,UAAA4C;AAAA,QACA,QAAQ5C,EAAS;AAAA,QACjB,SAASH,EAAQ;AAAA,QACjB,QAAAgD;AAAA,MAAA;AAGF,aAAIA,KAAUF,KACZ,QAAQ;AAAA,QACN,kBAAkBG,EAAW,MAAM,IAAIA,EAAW,GAAG,SAASF,EAAS,QAAQ,CAAC,CAAC;AAAA,QACjF,EAAE,SAAS/C,EAAQ,QAAA;AAAA,MAAQ,GAI/B6C,IAAWI,CAAU,GAEd9C;AAAA,IACT;AAAA,EAAA;AAEJ;AAoHO,SAAS+C,EAA+BpD,GAK1B;AACnB,QAAMqD,IAAQ,IAAI1D,EAAA;AAGlB,MAAIK,GAAQ,YAAY,IAAO;AAC7B,UAAMsD,IAAUvB;AAAA,MACd,OAAO/B,GAAQ,WAAY,WAAWA,EAAO,UAAU,CAAA;AAAA,IAAC;AAE1D,IAAAqD,EAAM,sBAAsBC,EAAQ,OAAO,GAC3CD,EAAM,uBAAuBC,EAAQ,QAAQ,GAC7CD,EAAM,oBAAoBC,EAAQ,KAAK;AAAA,EACzC;AAQA,MALItD,GAAQ,sBAAsB,MAChCqD,EAAM,sBAAsBZ,GAA8B,GAIxDzC,GAAQ,mBAAmB,IAAO;AACpC,UAAMuD,IAAUzC;AAAA,MACd,OAAOd,GAAQ,kBAAmB,WAAWA,EAAO,iBAAiB,CAAA;AAAA,IAAC;AAExE,IAAAqD,EAAM,sBAAsBE,EAAQ,OAAO,GAC3CF,EAAM,uBAAuBE,EAAQ,QAAQ,GAC7CF,EAAM,oBAAoBE,EAAQ,KAAK;AAAA,EACzC;AAGA,SAAIvD,GAAQ,WAAW,MACrBqD,EAAM;AAAA,IACJT,EAAwB,OAAO5C,GAAQ,UAAW,WAAWA,EAAO,SAAS,CAAA,CAAE;AAAA,EAAA,GAI5EqD;AACT;AAKO,MAAMG,IAA2BJ,EAAA;"}