{"version":3,"file":"Http.mjs","names":[],"sources":["../../../../../../http/src/Http.ts"],"sourcesContent":["import type {\r\n  AfterInterceptor,\r\n  AfterInterceptorContext,\r\n  BeforeInterceptor,\r\n  CacheDriver,\r\n  HttpCacheConfig,\r\n  HttpConfig,\r\n  HttpData,\r\n  HttpEventHandler,\r\n  HttpEventPayload,\r\n  HttpMethod,\r\n  HttpParams,\r\n  HttpResult,\r\n  HttpRetryConfig,\r\n  OutgoingRequest,\r\n  RequestOptions,\r\n  StreamFormat,\r\n  StreamRequestOptions,\r\n} from \"./Http.types\";\r\nimport { HttpError } from \"./HttpError\";\r\nimport { type CancellableAsyncIterable, type CancellablePromise, makeCancellable } from \"./cancellable\";\r\nimport { appendParams } from \"./utils/params\";\r\nimport { parseBody, prepareBody, readBodyWithProgress, wrapBodyWithProgress } from \"./utils/body\";\r\nimport { redactHeaders } from \"./utils/redact\";\r\n\r\n// ─── Module-level helpers ─────────────────────────────────────────────────────\r\n\r\n/**\r\n * Matches any URL scheme that is NOT http or https.\r\n * Used to block javascript:, data:, file:, ftp:, etc.\r\n */\r\nconst BLOCKED_SCHEMES = /^(?!https?:\\/\\/)[a-z][a-z0-9+\\-.]*:/i;\r\n\r\n/**\r\n * Join a base URL (may include protocol + host) with a path segment.\r\n * - Blocks non-http(s) schemes when base is empty (javascript:, data:, file:, …).\r\n * - Normalises the joined URL via `new URL()`, then verifies the resolved URL is\r\n *   still confined under `base` — `new URL()` *resolves* \"../..\" sequences rather\r\n *   than rejecting them, so without this check a `path` such as\r\n *   \"../../admin/secrets\" would successfully escape the configured baseURL prefix.\r\n */\r\nfunction joinUrl(base: string, path: string): string {\r\n  if (!base) {\r\n    if (BLOCKED_SCHEMES.test(path)) {\r\n      throw new Error(\r\n        `@mongez/http: Blocked request to unsafe URL scheme — \"${path.slice(0, 80)}\"`,\r\n      );\r\n    }\r\n    return path;\r\n  }\r\n  const joined = base.replace(/\\/$/, \"\") + \"/\" + path.replace(/^\\//, \"\");\r\n  let joinedUrl: URL;\r\n  try {\r\n    joinedUrl = new URL(joined);\r\n  } catch {\r\n    return joined; // Non-absolute URL (e.g. relative path used in tests) — return as-is.\r\n  }\r\n\r\n  let basePrefix: string;\r\n  try {\r\n    basePrefix = new URL(base).href.replace(/\\/$/, \"\");\r\n  } catch {\r\n    return joinedUrl.href; // base itself isn't a parseable absolute URL — nothing to confine against.\r\n  }\r\n\r\n  // Refuse rather than silently resolve: the joined URL must stay under the base path.\r\n  if (joinedUrl.href !== basePrefix && !joinedUrl.href.startsWith(basePrefix + \"/\")) {\r\n    throw new Error(\r\n      `@mongez/http: Blocked path traversal — \"${path.slice(0, 80)}\" resolves outside the configured baseURL (\"${base}\")`,\r\n    );\r\n  }\r\n\r\n  return joinedUrl.href;\r\n}\r\n\r\nfunction headersToObject(headers: Headers): Record<string, string> {\r\n  const result: Record<string, string> = {};\r\n  headers.forEach((value, key) => { result[key] = value; });\r\n  return result;\r\n}\r\n\r\n/**\r\n * Throw if any header name or value contains CR or LF characters.\r\n * Defence-in-depth against header injection; most runtimes already validate this,\r\n * but failing early with a clear message is better than a cryptic runtime error.\r\n */\r\nfunction assertSafeHeaders(headers: Record<string, string>): void {\r\n  for (const [name, value] of Object.entries(headers)) {\r\n    if (/[\\r\\n]/.test(name) || /[\\r\\n]/.test(value)) {\r\n      throw new Error(\r\n        `@mongez/http: Header \"${name}\" contains invalid CR or LF character.`,\r\n      );\r\n    }\r\n  }\r\n}\r\n\r\n/**\r\n * Return a copy of `req` with sensitive header values replaced by \"[redacted]\".\r\n * Used when emitting events so third-party listeners (analytics, loggers) never\r\n * receive raw credentials.\r\n */\r\nfunction sanitiseRequestForEvent(req: OutgoingRequest): OutgoingRequest {\r\n  return { ...req, headers: redactHeaders(req.headers) };\r\n}\r\n\r\n/**\r\n * Parse a full SSE event block (lines between two blank lines) into its\r\n * component fields: id, event, data (multi-line joined), and retry directive.\r\n * Returns `data: undefined` when the block should be skipped (comment-only or\r\n * no data lines).\r\n */\r\nfunction parseSseBlock<T>(\r\n  block: string,\r\n  customParser?: (line: string) => unknown,\r\n): { data?: T; id?: string; event?: string; retry?: number } {\r\n  const lines = block.split(\"\\n\");\r\n  const dataLines: string[] = [];\r\n  let id: string | undefined;\r\n  let event: string | undefined;\r\n  let retry: number | undefined;\r\n\r\n  for (const line of lines) {\r\n    if (line.startsWith(\"id:\")) {\r\n      id = line.slice(3).trimStart();\r\n    } else if (line.startsWith(\"event:\")) {\r\n      event = line.slice(6).trimStart();\r\n    } else if (line.startsWith(\"retry:\")) {\r\n      const n = parseInt(line.slice(6).trimStart(), 10);\r\n      if (!isNaN(n)) retry = n;\r\n    } else if (line.startsWith(\"data:\")) {\r\n      dataLines.push(line.slice(5).trimStart());\r\n    }\r\n    // Lines starting with \":\" are SSE comments — silently ignored.\r\n  }\r\n\r\n  if (dataLines.length === 0) return { id, event, retry };\r\n\r\n  const dataStr = dataLines.join(\"\\n\");\r\n  if (!dataStr || dataStr === \"[DONE]\") return { id, event, retry };\r\n\r\n  if (customParser) {\r\n    const parsed = customParser(dataStr);\r\n    return { data: parsed as T | undefined, id, event, retry };\r\n  }\r\n\r\n  try {\r\n    return { data: JSON.parse(dataStr) as T, id, event, retry };\r\n  } catch {\r\n    return { data: dataStr as unknown as T, id, event, retry };\r\n  }\r\n}\r\n\r\n/**\r\n * Parse a single NDJSON line. Returns undefined to signal \"skip this line\".\r\n */\r\nfunction parseNdjsonLine<T>(\r\n  line: string,\r\n  customParser?: (line: string) => unknown,\r\n): T | undefined {\r\n  if (customParser) return customParser(line) as T | undefined;\r\n\r\n  const trimmed = line.trim();\r\n  if (!trimmed) return undefined;\r\n  try {\r\n    return JSON.parse(trimmed) as T;\r\n  } catch {\r\n    return trimmed as unknown as T;\r\n  }\r\n}\r\n\r\nconst DEFAULT_RETRY_ON = [429, 500, 502, 503, 504];\r\nconst DEFAULT_TTL = 300; // 5 minutes\r\nconst DEFAULT_RECONNECT_DELAY = 3000; // ms\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n  return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * True when running in a browser-like environment (one user per instance).\r\n *\r\n * Both GET deduplication and the response cache derive their default key from URL +\r\n * params, which cannot distinguish one caller from another. That is harmless in a browser\r\n * and a cross-user data leak on a server, so both consult this check before applying it.\r\n */\r\nfunction isBrowser(): boolean {\r\n  return typeof window !== \"undefined\";\r\n}\r\n\r\nfunction buildCacheKey(url: string, params?: HttpParams): string {\r\n  const qs = params ? JSON.stringify(params) : \"\";\r\n  return `http:${url}${qs ? `:${qs}` : \"\"}`;\r\n}\r\n\r\n/**\r\n * Assign `value` onto `init[key]` only when the library actually has an opinion.\r\n *\r\n * The library-controlled fields are written *after* the caller's `fetchInit` so they\r\n * cannot be overridden — but writing `undefined` over a value the caller deliberately\r\n * put in `fetchInit` would erase it, defeating the escape hatch. Unset stays unset.\r\n */\r\nfunction assignIfDefined(init: Record<string, unknown>, key: string, value: unknown): void {\r\n  if (value !== undefined) init[key] = value;\r\n}\r\n\r\n// ─── Internal context for replay support ─────────────────────────────────────\r\n\r\ninterface ReplayCtx {\r\n  method: HttpMethod | string;\r\n  path: string;\r\n  data: HttpData | undefined;\r\n  options: RequestOptions;\r\n}\r\n\r\n// ─── Http ─────────────────────────────────────────────────────────────────────\r\n\r\nexport class Http {\r\n  private readonly config: HttpConfig;\r\n  private readonly beforeInterceptors: BeforeInterceptor[] = [];\r\n  private readonly afterInterceptors: AfterInterceptor[] = [];\r\n  private readonly eventHandlers: Map<string, HttpEventHandler[]> = new Map();\r\n  /**\r\n   * In-flight GET entries keyed by URL+params. Each entry tracks the shared underlying\r\n   * promise, the shared AbortController, and a ref-count of active callers.\r\n   * When the last caller cancels, the shared fetch is aborted.\r\n   */\r\n  private readonly inFlight = new Map<string, {\r\n    promise: Promise<HttpResult<unknown>>;\r\n    sharedController: AbortController;\r\n    refs: number;\r\n  }>();\r\n\r\n  constructor(config: HttpConfig = {}) {\r\n    this.config = config;\r\n  }\r\n\r\n  // ─── Configuration ──────────────────────────────────────────────────────────\r\n\r\n  /** Return a new Http instance that inherits this config merged with overrides. */\r\n  extend(overrides: HttpConfig): Http {\r\n    return new Http({ ...this.config, ...overrides });\r\n  }\r\n\r\n  getConfig(): Readonly<HttpConfig> {\r\n    return this.config;\r\n  }\r\n\r\n  // ─── Interceptors ───────────────────────────────────────────────────────────\r\n\r\n  before(interceptor: BeforeInterceptor): this {\r\n    this.beforeInterceptors.push(interceptor);\r\n    return this;\r\n  }\r\n\r\n  after<T = unknown>(interceptor: AfterInterceptor<T>): this {\r\n    this.afterInterceptors.push(interceptor as AfterInterceptor);\r\n    return this;\r\n  }\r\n\r\n  // ─── Events ─────────────────────────────────────────────────────────────────\r\n\r\n  on<T = unknown>(event: string, handler: HttpEventHandler<T>): this {\r\n    const list = this.eventHandlers.get(event) ?? [];\r\n    list.push(handler as HttpEventHandler);\r\n    this.eventHandlers.set(event, list);\r\n    return this;\r\n  }\r\n\r\n  off<T = unknown>(event: string, handler: HttpEventHandler<T>): this {\r\n    const list = this.eventHandlers.get(event);\r\n    if (list) {\r\n      const idx = list.indexOf(handler as HttpEventHandler);\r\n      if (idx !== -1) list.splice(idx, 1);\r\n    }\r\n    return this;\r\n  }\r\n\r\n  private emit<T>(event: string, payload: HttpEventPayload<T>): void {\r\n    const list = this.eventHandlers.get(event);\r\n    if (list) {\r\n      for (const handler of list) handler(payload as HttpEventPayload);\r\n    }\r\n  }\r\n\r\n  // ─── Public HTTP methods ─────────────────────────────────────────────────────\r\n\r\n  get<T = unknown>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>> {\r\n    return this.request<T>(\"GET\", path, undefined, options);\r\n  }\r\n\r\n  post<T = unknown>(path: string, data?: HttpData, options?: RequestOptions): CancellablePromise<HttpResult<T>> {\r\n    return this.request<T>(\"POST\", path, data, options);\r\n  }\r\n\r\n  put<T = unknown>(path: string, data?: HttpData, options?: RequestOptions): CancellablePromise<HttpResult<T>> {\r\n    return this.request<T>(\"PUT\", path, data, options);\r\n  }\r\n\r\n  patch<T = unknown>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>> {\r\n    return this.request<T>(\"PATCH\", path, options?.data as HttpData | undefined, options);\r\n  }\r\n\r\n  delete<T = unknown>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>> {\r\n    return this.request<T>(\"DELETE\", path, options?.data as HttpData | undefined, options);\r\n  }\r\n\r\n  head(path: string, options?: RequestOptions): CancellablePromise<HttpResult<null>> {\r\n    return this.request<null>(\"HEAD\", path, undefined, options);\r\n  }\r\n\r\n  options<T = unknown>(path: string, options?: RequestOptions): CancellablePromise<HttpResult<T>> {\r\n    return this.request<T>(\"OPTIONS\", path, undefined, options);\r\n  }\r\n\r\n  /**\r\n   * Send a request with any HTTP method — the escape hatch for non-standard verbs.\r\n   * All convenience methods delegate here.\r\n   *\r\n   * GET requests are deduplicated **in the browser**: concurrent calls with the same URL\r\n   * share a single underlying fetch, and each caller gets its own CancellablePromise.\r\n   * Outside a browser deduplication is off by default — see `HttpConfig.dedupe`.\r\n   */\r\n  request<T = unknown>(\r\n    method: HttpMethod | string,\r\n    path: string,\r\n    data?: HttpData,\r\n    options: RequestOptions = {},\r\n  ): CancellablePromise<HttpResult<T>> {\r\n    if (method === \"GET\" && this.shouldDedupe(options)) {\r\n      // Merge default params for dedup key so it matches what buildOutgoingRequest produces.\r\n      const mergedParams = this.config.params\r\n        ? { ...this.config.params, ...options.params }\r\n        : options.params;\r\n      const rawUrl = joinUrl(this.config.baseURL ?? \"\", path);\r\n      const dedupeKey = this.resolveDedupeKey(rawUrl, mergedParams, options);\r\n\r\n      if (!this.inFlight.has(dedupeKey)) {\r\n        const sharedController = new AbortController();\r\n        const promise = this.execute<T>(method, path, data, options, sharedController.signal) as Promise<HttpResult<unknown>>;\r\n        this.inFlight.set(dedupeKey, { promise, sharedController, refs: 0 });\r\n        // Use then(cb, cb) rather than finally(cb): the .finally() variant creates a\r\n        // derived promise that re-throws any rejection, causing an unhandled-rejection\r\n        // warning when no external consumer has attached a rejection handler to it yet.\r\n        const cleanup = (): void => { this.inFlight.delete(dedupeKey); };\r\n        promise.then(cleanup, cleanup);\r\n      }\r\n\r\n      const entry = this.inFlight.get(dedupeKey)!;\r\n      entry.refs++;\r\n\r\n      // Each caller gets its own AbortController so cancel() is per-caller.\r\n      // When the last active caller cancels, the shared fetch is aborted too.\r\n      const callerController = new AbortController();\r\n\r\n      callerController.signal.addEventListener(\"abort\", (): void => {\r\n        entry.refs--;\r\n        if (entry.refs <= 0) {\r\n          entry.sharedController.abort(callerController.signal.reason);\r\n        }\r\n      }, { once: true });\r\n\r\n      // Forward an external signal (React Query / useEffect) to the caller controller.\r\n      if (options.signal) {\r\n        if (options.signal.aborted) {\r\n          callerController.abort(options.signal.reason);\r\n        } else {\r\n          const extSignal = options.signal;\r\n          extSignal.addEventListener(\r\n            \"abort\",\r\n            (): void => callerController.abort(extSignal.reason),\r\n            { once: true },\r\n          );\r\n        }\r\n      }\r\n\r\n      // .then() produces a fresh promise object — safe to attach per-caller properties.\r\n      const callerPromise = entry.promise.then((r) => r as HttpResult<T>);\r\n      return Object.assign(callerPromise, {\r\n        cancel: (reason?: string): void => callerController.abort(reason ?? \"cancelled\"),\r\n        signal: callerController.signal,\r\n      }) as unknown as CancellablePromise<HttpResult<T>>;\r\n    }\r\n\r\n    return makeCancellable(\r\n      (signal) => this.execute<T>(method as HttpMethod, path, data, options, signal),\r\n      options.signal,\r\n    );\r\n  }\r\n\r\n  // ─── Cache management ────────────────────────────────────────────────────────\r\n\r\n  /**\r\n   * Remove a single cache entry by key.\r\n   * Pass the same key used in `options.cacheKey`, or the auto-generated key:\r\n   * `http:<url>:<serialised-params>`.\r\n   */\r\n  async invalidate(key: string): Promise<void> {\r\n    const config = this.resolveCacheConfig({});\r\n    if (config?.driver.remove) {\r\n      await config.driver.remove(key);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Remove all cache entries. Requires the driver to implement `clear()`.\r\n   */\r\n  async invalidateAll(): Promise<void> {\r\n    const config = this.resolveCacheConfig({});\r\n    if (config?.driver.clear) {\r\n      await config.driver.clear();\r\n    }\r\n  }\r\n\r\n  // ─── Concurrent request helpers ─────────────────────────────────────────────\r\n\r\n  /**\r\n   * Run multiple requests concurrently and collect every result in order.\r\n   * Cancelling the returned handle cancels all requests in the batch.\r\n   *\r\n   * Unlike `Promise.all`, individual requests still resolve to `{data, error}`\r\n   * even when one fails — they never throw. The batch itself resolves when\r\n   * all inner requests settle.\r\n   *\r\n   * @example\r\n   * const results = await http.all([\r\n   *   http.get<User[]>('/users'),\r\n   *   http.get<Post[]>('/posts'),\r\n   * ]);\r\n   * const [usersResult, postsResult] = results;\r\n   */\r\n  all<T>(requests: CancellablePromise<T>[]): CancellablePromise<T[]> {\r\n    const controller = new AbortController();\r\n    return Object.assign(Promise.all(requests), {\r\n      cancel: (reason?: string): void => {\r\n        controller.abort(reason ?? \"cancelled\");\r\n        for (const req of requests) req.cancel(reason ?? \"cancelled\");\r\n      },\r\n      get signal(): AbortSignal { return controller.signal; },\r\n    }) as unknown as CancellablePromise<T[]>;\r\n  }\r\n\r\n  /**\r\n   * Run multiple requests concurrently and return the result of whichever\r\n   * settles first. All other in-flight requests are cancelled immediately.\r\n   *\r\n   * Useful for mirror/fallback endpoints where you want the fastest response.\r\n   *\r\n   * @example\r\n   * const { data } = await http.race([\r\n   *   http.get('/cdn-us/data'),\r\n   *   http.get('/cdn-eu/data'),\r\n   * ]);\r\n   */\r\n  race<T>(requests: CancellablePromise<T>[]): CancellablePromise<T> {\r\n    const controller = new AbortController();\r\n\r\n    const cancelAll = (reason: string): void => {\r\n      for (const req of requests) req.cancel(reason);\r\n    };\r\n\r\n    // Cancel all losers once the first request settles.\r\n    const settled = Promise.race(requests).then(\r\n      (winner) => { cancelAll(\"race-finished\"); return winner; },\r\n      (err)    => { cancelAll(\"race-finished\"); return Promise.reject(err) as never; },\r\n    );\r\n\r\n    return Object.assign(settled, {\r\n      cancel: (reason?: string): void => {\r\n        controller.abort(reason ?? \"cancelled\");\r\n        cancelAll(reason ?? \"cancelled\");\r\n      },\r\n      get signal(): AbortSignal { return controller.signal; },\r\n    }) as unknown as CancellablePromise<T>;\r\n  }\r\n\r\n  // ─── Streaming ──────────────────────────────────────────────────────────────\r\n\r\n  /**\r\n   * Open a streaming connection and yield parsed chunks as an async iterable.\r\n   *\r\n   * Supports Server-Sent Events (SSE) and newline-delimited JSON (NDJSON).\r\n   * For SSE, automatically reconnects on disconnect and sends `Last-Event-ID`\r\n   * so the server can resume. Use `.cancel()` to abort from outside the loop.\r\n   *\r\n   * The stream **never throws** — errors are stored in `.error` instead.\r\n   * Check `stream.error` after the `for await` loop.\r\n   *\r\n   * @example\r\n   * const stream = http.stream<ChatChunk>('/chat', { method: 'POST', data: { messages } });\r\n   * for await (const chunk of stream) {\r\n   *   setContent(c => c + chunk.content);\r\n   * }\r\n   * if (stream.error) showError(stream.error.message);\r\n   */\r\n  stream<T = unknown>(\r\n    path: string,\r\n    options: StreamRequestOptions = {},\r\n  ): CancellableAsyncIterable<T> {\r\n    const controller = new AbortController();\r\n\r\n    if (options.signal) {\r\n      const ext = options.signal;\r\n      if (ext.aborted) {\r\n        controller.abort(ext.reason);\r\n      } else {\r\n        ext.addEventListener(\"abort\", () => controller.abort(ext.reason), { once: true });\r\n      }\r\n    }\r\n\r\n    const format = options.format ?? \"sse\";\r\n    const shouldReconnect = options.reconnect ?? false;\r\n    const maxAttempts = options.maxReconnectAttempts ?? Infinity;\r\n    const baseReconnectDelay = options.reconnectDelay ?? DEFAULT_RECONNECT_DELAY;\r\n    const self = this;\r\n\r\n    // Shared state written by the generator, read by the iterable's .error getter.\r\n    const state: { error: HttpError | null } = { error: null };\r\n\r\n    // SSE reconnection state — persists across reconnects.\r\n    let lastEventId: string | undefined;\r\n    let serverRetryDelay: number | undefined; // set by the server's `retry:` directive\r\n\r\n    async function* generator(): AsyncGenerator<T> {\r\n      let reconnectAttempt = 0;\r\n\r\n      while (true) {\r\n        if (controller.signal.aborted) return;\r\n\r\n        // ── Build request (fresh each attempt — re-applies auth + Last-Event-ID) ──\r\n        const extraHeaders: Record<string, string> = {};\r\n        if (!options.headers?.[\"Accept\"]) {\r\n          extraHeaders[\"Accept\"] = \"text/event-stream, application/x-ndjson, */*\";\r\n        }\r\n        if (lastEventId !== undefined) {\r\n          extraHeaders[\"Last-Event-ID\"] = lastEventId;\r\n        }\r\n\r\n        const req = await self.buildOutgoingRequest(\r\n          options.method ?? \"GET\",\r\n          path,\r\n          options.data as HttpData | undefined,\r\n          options,\r\n          extraHeaders,\r\n        );\r\n\r\n        self.emit(\"request\", { request: sanitiseRequestForEvent(req) });\r\n\r\n        // ── Fetch ──────────────────────────────────────────────────────────────\r\n        let response: Response;\r\n        try {\r\n          response = await fetch(\r\n            req.url,\r\n            self.buildFetchInit(req, req.body, controller.signal, options, {}, false),\r\n          );\r\n        } catch {\r\n          if (controller.signal.aborted) return; // cancelled — end silently\r\n\r\n          const err = new HttpError({\r\n            message: \"Stream network error\",\r\n            isNetwork: true,\r\n            request: req,\r\n          });\r\n          self.emit(\"error\", { request: sanitiseRequestForEvent(req) });\r\n\r\n          if (!shouldReconnect || reconnectAttempt >= maxAttempts) {\r\n            state.error = err;\r\n            return;\r\n          }\r\n\r\n          reconnectAttempt++;\r\n          await sleep(serverRetryDelay ?? baseReconnectDelay);\r\n          continue;\r\n        }\r\n\r\n        if (!response.ok) {\r\n          const errorBody = await parseBody(response).catch(() => null);\r\n          const err = new HttpError({\r\n            message: `HTTP ${response.status} ${response.statusText}`,\r\n            status: response.status,\r\n            body: errorBody,\r\n            response,\r\n            headers: headersToObject(response.headers),\r\n            request: req,\r\n          });\r\n          self.emit(\"error\", { request: sanitiseRequestForEvent(req) });\r\n          // Do NOT reconnect on HTTP errors — they indicate a server-side problem\r\n          // (wrong path, auth failure, etc.) that retrying won't fix.\r\n          state.error = err;\r\n          return;\r\n        }\r\n\r\n        // ── Read and parse the stream ──────────────────────────────────────────\r\n        const reader = response.body?.getReader();\r\n        if (!reader) return;\r\n\r\n        const decoder = new TextDecoder();\r\n        let buffer = \"\";\r\n        let readError = false;\r\n\r\n        try {\r\n          while (true) {\r\n            let readResult: ReadableStreamReadResult<Uint8Array>;\r\n            try {\r\n              readResult = await reader.read();\r\n            } catch {\r\n              if (controller.signal.aborted) return;\r\n              readError = true;\r\n              break;\r\n            }\r\n\r\n            const { done, value } = readResult;\r\n            if (done) break;\r\n\r\n            buffer += decoder.decode(value, { stream: true });\r\n\r\n            if (format === \"sse\") {\r\n              // SSE events are delimited by double-newlines.\r\n              let boundary: number;\r\n              while ((boundary = buffer.indexOf(\"\\n\\n\")) !== -1) {\r\n                const block = buffer.slice(0, boundary);\r\n                buffer = buffer.slice(boundary + 2);\r\n\r\n                const parsed = parseSseBlock<T>(\r\n                  block,\r\n                  options.parseLine as ((l: string) => unknown) | undefined,\r\n                );\r\n                if (parsed.retry !== undefined) serverRetryDelay = parsed.retry;\r\n                if (parsed.id !== undefined) lastEventId = parsed.id;\r\n                if (parsed.data !== undefined) {\r\n                  yield parsed.data;\r\n                }\r\n              }\r\n            } else {\r\n              // NDJSON: one JSON value per line.\r\n              const lines = buffer.split(\"\\n\");\r\n              buffer = lines.pop() ?? \"\";\r\n              for (const line of lines) {\r\n                const parsed = parseNdjsonLine<T>(\r\n                  line,\r\n                  options.parseLine as ((l: string) => unknown) | undefined,\r\n                );\r\n                if (parsed !== undefined) {\r\n                  yield parsed;\r\n                }\r\n              }\r\n            }\r\n          }\r\n\r\n          // Flush any remaining buffered content after the stream ends.\r\n          if (buffer.trim()) {\r\n            if (format === \"sse\") {\r\n              const parsed = parseSseBlock<T>(\r\n                buffer,\r\n                options.parseLine as ((l: string) => unknown) | undefined,\r\n              );\r\n              if (parsed.retry !== undefined) serverRetryDelay = parsed.retry;\r\n              if (parsed.id !== undefined) lastEventId = parsed.id;\r\n              if (parsed.data !== undefined) yield parsed.data;\r\n            } else {\r\n              const parsed = parseNdjsonLine<T>(\r\n                buffer,\r\n                options.parseLine as ((l: string) => unknown) | undefined,\r\n              );\r\n              if (parsed !== undefined) yield parsed;\r\n            }\r\n          }\r\n        } finally {\r\n          reader.releaseLock();\r\n        }\r\n\r\n        // ── Handle reconnect logic ─────────────────────────────────────────────\r\n        if (readError) {\r\n          if (!shouldReconnect || reconnectAttempt >= maxAttempts) {\r\n            state.error = new HttpError({\r\n              message: \"Stream read error\",\r\n              isNetwork: true,\r\n              request: req,\r\n            });\r\n            return;\r\n          }\r\n          reconnectAttempt++;\r\n          await sleep(serverRetryDelay ?? baseReconnectDelay);\r\n          continue; // outer while — reconnect\r\n        }\r\n\r\n        // Normal stream end.\r\n        if (!shouldReconnect) return;\r\n\r\n        // SSE auto-reconnect after normal end.\r\n        reconnectAttempt++;\r\n        if (reconnectAttempt > maxAttempts) return;\r\n        await sleep(serverRetryDelay ?? baseReconnectDelay);\r\n        // fall through to top of outer while → reconnect\r\n      }\r\n    }\r\n\r\n    const gen = generator();\r\n\r\n    return {\r\n      [Symbol.asyncIterator](): AsyncIterator<T> { return gen; },\r\n      cancel(reason?: string): void { controller.abort(reason ?? \"cancelled\"); },\r\n      get signal(): AbortSignal { return controller.signal; },\r\n      get error(): HttpError | null { return state.error; },\r\n    };\r\n  }\r\n\r\n  // ─── Core execution ──────────────────────────────────────────────────────────\r\n\r\n  /**\r\n   * Build the final OutgoingRequest: URL, headers, auth, before-interceptors.\r\n   * Shared by both regular requests and streaming.\r\n   */\r\n  private async buildOutgoingRequest(\r\n    method: HttpMethod | string,\r\n    path: string,\r\n    data: HttpData | undefined,\r\n    options: RequestOptions,\r\n    extraHeaders: Record<string, string> = {},\r\n  ): Promise<OutgoingRequest> {\r\n    const baseURL = this.config.baseURL ?? \"\";\r\n\r\n    // Merge default config params with per-request params (request wins on conflict).\r\n    const mergedParams = this.config.params\r\n      ? { ...this.config.params, ...options.params }\r\n      : options.params;\r\n    const fullPath = appendParams(joinUrl(baseURL, path), mergedParams);\r\n\r\n    // ── Body serialization ────────────────────────────────────────────────────\r\n    // Use the custom serializer for plain objects/arrays. FormData, Blob,\r\n    // HTMLFormElement, and string pass through prepareBody unchanged.\r\n    const isPassthrough =\r\n      !data ||\r\n      data instanceof FormData ||\r\n      typeof data === \"string\" ||\r\n      (typeof HTMLFormElement !== \"undefined\" && data instanceof HTMLFormElement);\r\n\r\n    const { body, contentType } = (this.config.serializer && !isPassthrough)\r\n      ? (() => {\r\n          const r = this.config.serializer!(data);\r\n          return { body: r.body, contentType: r.contentType as string | undefined };\r\n        })()\r\n      : prepareBody(data);\r\n\r\n    const headers: Record<string, string> = {\r\n      ...(this.config.headers ?? {}),\r\n      ...extraHeaders,\r\n      ...(options.headers ?? {}),\r\n    };\r\n\r\n    if (contentType && !headers[\"Content-Type\"]) {\r\n      headers[\"Content-Type\"] = contentType;\r\n    }\r\n\r\n    const outgoing: OutgoingRequest = { method, url: fullPath, headers, body };\r\n\r\n    const authValue = typeof this.config.auth === \"function\"\r\n      ? this.config.auth(outgoing)\r\n      : this.config.auth;\r\n\r\n    if (authValue) headers[\"Authorization\"] = authValue;\r\n\r\n    // Defence-in-depth: reject headers with embedded CR/LF before they reach fetch().\r\n    assertSafeHeaders(headers);\r\n\r\n    let req = outgoing;\r\n    for (const interceptor of this.beforeInterceptors) {\r\n      // Pass the full original options as the second argument so interceptors\r\n      // can inspect params, timeout, responseType, etc.\r\n      const modified = await interceptor(req, options as Readonly<RequestOptions>);\r\n      if (modified) req = modified;\r\n    }\r\n\r\n    return req;\r\n  }\r\n\r\n  private async execute<T>(\r\n    method: HttpMethod,\r\n    path: string,\r\n    data: HttpData | undefined,\r\n    options: RequestOptions,\r\n    signal: AbortSignal,\r\n    isReplay = false,\r\n  ): Promise<HttpResult<T>> {\r\n    // ── putToPost conversion ──────────────────────────────────────────────────\r\n    let actualMethod: HttpMethod | string = method;\r\n    let actualData = data;\r\n\r\n    if (method === \"PUT\" && this.config.putToPost) {\r\n      actualMethod = \"POST\";\r\n      const key = this.config.putMethodKey ?? \"_method\";\r\n      if (actualData instanceof FormData) {\r\n        actualData.append(key, \"PUT\");\r\n      } else if (typeof actualData === \"object\" && actualData !== null) {\r\n        actualData = { ...(actualData as object), [key]: \"PUT\" };\r\n      } else {\r\n        actualData = { [key]: \"PUT\" };\r\n      }\r\n    }\r\n\r\n    // ── Build outgoing request ────────────────────────────────────────────────\r\n    const req = await this.buildOutgoingRequest(actualMethod, path, actualData, options);\r\n\r\n    // Stash the original (pre-putToPost) parameters for replay().\r\n    const replayCtx: ReplayCtx = { method, path, data, options };\r\n\r\n    // ── Cache check (GET only) — runs before emitting \"request\" so the event\r\n    //    only fires for actual network calls, not cache hits. ─────────────────\r\n    const cacheConfig = this.resolveCacheConfig(options);\r\n    let cacheKey: string | undefined;\r\n\r\n    if (actualMethod === \"GET\" && cacheConfig) {\r\n      cacheKey = options.cacheKey ?? (\r\n        cacheConfig.generateKey\r\n          ? cacheConfig.generateKey(req.url, options.params)\r\n          : this.defaultCacheKey(req.url, options.params)\r\n      );\r\n\r\n      const cached = await cacheConfig.driver.get<T>(cacheKey);\r\n      if (cached !== null && cached !== undefined) {\r\n        return { data: cached, error: null, status: 200, response: new Response(), headers: {}, request: req };\r\n      }\r\n    }\r\n\r\n    // ── Emit \"request\" (only for real network calls, never for cache hits) ────\r\n    this.emit(\"request\", { request: sanitiseRequestForEvent(req) });\r\n\r\n    // ── Retry wrapper ─────────────────────────────────────────────────────────\r\n    const retryConfig = this.resolveRetryConfig(options);\r\n    return this.executeWithRetry<T>(req, signal, options, cacheConfig, retryConfig, cacheKey, replayCtx, isReplay);\r\n  }\r\n\r\n  private async executeWithRetry<T>(\r\n    req: OutgoingRequest,\r\n    signal: AbortSignal,\r\n    options: RequestOptions,\r\n    cacheConfig: ResolvedCache | null,\r\n    retryConfig: HttpRetryConfig | null,\r\n    cacheKey: string | undefined,\r\n    replayCtx: ReplayCtx,\r\n    isReplay: boolean,\r\n    attempt = 0,\r\n  ): Promise<HttpResult<T>> {\r\n    try {\r\n      return await this.executeSingle<T>(req, signal, options, cacheConfig, cacheKey, replayCtx, isReplay);\r\n    } catch (err) {\r\n      // Guard: only handle HttpErrors — rethrow anything else (e.g. interceptor bugs).\r\n      if (!(err instanceof HttpError)) throw err;\r\n\r\n      // Never retry aborts or timeouts.\r\n      if (err.isAborted || err.isTimeout) {\r\n        return this.errorResult<T>(err, options, req, replayCtx, isReplay);\r\n      }\r\n\r\n      if (\r\n        retryConfig &&\r\n        attempt < retryConfig.attempts &&\r\n        this.shouldRetry(err, retryConfig)\r\n      ) {\r\n        const base = retryConfig.backoff !== false\r\n          ? retryConfig.delay * Math.pow(2, attempt)\r\n          : retryConfig.delay;\r\n\r\n        // Optional jitter: multiply by a random factor in [0.5, 1.0] to avoid\r\n        // thundering-herd problems when many clients retry simultaneously.\r\n        let delay = retryConfig.jitter === true\r\n          ? base * (0.5 + Math.random() * 0.5)\r\n          : base;\r\n\r\n        // Respect the Retry-After header (common on 429 responses).\r\n        // Never wait less than the server explicitly requested.\r\n        if (err.response) {\r\n          const retryAfterRaw = err.response.headers.get(\"Retry-After\");\r\n          if (retryAfterRaw) {\r\n            const serverDelayMs = parseInt(retryAfterRaw, 10) * 1000;\r\n            if (!isNaN(serverDelayMs) && serverDelayMs > delay) {\r\n              delay = serverDelayMs;\r\n            }\r\n          }\r\n        }\r\n\r\n        // Fire the onRetry callback if configured.\r\n        if (retryConfig.onRetry) {\r\n          retryConfig.onRetry(attempt + 1, err, delay);\r\n        }\r\n\r\n        await sleep(delay);\r\n        return this.executeWithRetry<T>(req, signal, options, cacheConfig, retryConfig, cacheKey, replayCtx, isReplay, attempt + 1);\r\n      }\r\n\r\n      return this.errorResult<T>(err, options, req, replayCtx, isReplay);\r\n    }\r\n  }\r\n\r\n  private async executeSingle<T>(\r\n    req: OutgoingRequest,\r\n    signal: AbortSignal,\r\n    options: RequestOptions,\r\n    cacheConfig: ResolvedCache | null,\r\n    cacheKey: string | undefined,\r\n    replayCtx: ReplayCtx,\r\n    isReplay: boolean,\r\n  ): Promise<HttpResult<T>> {\r\n    // Fast path: if the signal was already aborted before the microtask queue\r\n    // delivered execute() — e.g. cancel() was called synchronously right after\r\n    // creating the request — throw immediately without touching fetch.\r\n    // AbortSignal does NOT fire \"abort\" listeners retroactively, so waiting for\r\n    // the event inside the fetch mock (or real fetch) would hang forever.\r\n    if (signal.aborted) {\r\n      throw new HttpError({ message: \"Request was cancelled\", isAborted: true, request: req });\r\n    }\r\n\r\n    // ── Timeout ───────────────────────────────────────────────────────────────\r\n    const timeout = options.timeout ?? this.config.timeout;\r\n    let timeoutId: ReturnType<typeof setTimeout> | undefined;\r\n    let timeoutController: AbortController | undefined;\r\n\r\n    if (timeout !== undefined) {\r\n      timeoutController = new AbortController();\r\n      timeoutId = setTimeout(() => timeoutController!.abort(\"timeout\"), timeout);\r\n    }\r\n\r\n    const effectiveSignal = timeoutController\r\n      ? mergeSignals(signal, timeoutController.signal)\r\n      : signal;\r\n\r\n    // ── Upload progress wrapping ───────────────────────────────────────────────\r\n    let fetchBody = req.body;\r\n    const extraInit: Record<string, unknown> = {};\r\n\r\n    if (options.onUploadProgress && req.body !== undefined) {\r\n      const wrapped = wrapBodyWithProgress(req.body, options.onUploadProgress);\r\n      fetchBody = wrapped.body;\r\n      if (wrapped.duplex) extraInit.duplex = wrapped.duplex;\r\n    }\r\n\r\n    let response: Response;\r\n    try {\r\n      response = await fetch(\r\n        req.url,\r\n        this.buildFetchInit(req, fetchBody, effectiveSignal, options, extraInit),\r\n      );\r\n    } catch (err) {\r\n      clearTimeout(timeoutId);\r\n\r\n      const timedOut = timeoutController?.signal.aborted ?? false;\r\n      const isTimeout = timedOut || (err instanceof Error && err.message === \"timeout\");\r\n      const isAborted = !isTimeout && signal.aborted;\r\n      const isNetwork = !isTimeout && !isAborted;\r\n\r\n      throw new HttpError({\r\n        message: isTimeout\r\n          ? `Request timed out after ${timeout}ms`\r\n          : isAborted\r\n            ? \"Request was cancelled\"\r\n            : `Network error: ${err instanceof Error ? err.message : String(err)}`,\r\n        isAborted,\r\n        isTimeout,\r\n        isNetwork,\r\n        request: req,\r\n      });\r\n    } finally {\r\n      clearTimeout(timeoutId);\r\n    }\r\n\r\n    // ── Stream fast-path ──────────────────────────────────────────────────────\r\n    // responseType:\"stream\" hands the caller the raw ReadableStream untouched.\r\n    // onDownloadProgress and cache are silently bypassed — reading the body here\r\n    // would consume it before the caller can pipe it anywhere.\r\n    if (options.responseType === \"stream\") {\r\n      if (!response.ok) {\r\n        // Read the body for error responses so HttpError.body is still populated.\r\n        const errorBody = await parseBody(response);\r\n        throw new HttpError({\r\n          message: `HTTP ${response.status} ${response.statusText}`,\r\n          status: response.status,\r\n          body: errorBody,\r\n          response,\r\n          headers: headersToObject(response.headers),\r\n          request: req,\r\n        });\r\n      }\r\n      const streamResult: HttpResult<T> = {\r\n        data: response.body as unknown as T,\r\n        error: null,\r\n        status: response.status,\r\n        response,\r\n        headers: headersToObject(response.headers),\r\n        request: req,\r\n      };\r\n      return this.runAfterInterceptors<T>(streamResult, replayCtx, isReplay, req);\r\n    }\r\n\r\n    // ── Parse body ────────────────────────────────────────────────────────────\r\n    const parsedBody = options.onDownloadProgress\r\n      ? await readBodyWithProgress(response, options.onDownloadProgress, options.responseType)\r\n      : await parseBody(response, options.responseType);\r\n\r\n    if (!response.ok) {\r\n      throw new HttpError({\r\n        message: `HTTP ${response.status} ${response.statusText}`,\r\n        status: response.status,\r\n        body: parsedBody,\r\n        response,\r\n        headers: headersToObject(response.headers),\r\n        request: req,\r\n      });\r\n    }\r\n\r\n    // ── Store in cache ────────────────────────────────────────────────────────\r\n    if (cacheConfig && cacheKey) {\r\n      await cacheConfig.driver.set(cacheKey, parsedBody as T, cacheConfig.ttl ?? DEFAULT_TTL);\r\n    }\r\n\r\n    const result: HttpResult<T> = {\r\n      data: parsedBody as T,\r\n      error: null,\r\n      status: response.status,\r\n      response,\r\n      headers: headersToObject(response.headers),\r\n      request: req,\r\n    };\r\n\r\n    return this.runAfterInterceptors<T>(result, replayCtx, isReplay, req);\r\n  }\r\n\r\n  private async errorResult<T>(\r\n    err: HttpError,\r\n    options: RequestOptions,\r\n    req: OutgoingRequest,\r\n    replayCtx: ReplayCtx,\r\n    isReplay: boolean,\r\n  ): Promise<HttpResult<T>> {\r\n    const errorRes: HttpResult<T> = {\r\n      data: null,\r\n      error: err,\r\n      status: err.status,\r\n      response: err.response,\r\n      headers: err.response ? headersToObject(err.response.headers) : null,\r\n      request: req,\r\n    };\r\n\r\n    const finalResult = await this.runAfterInterceptors<T>(errorRes, replayCtx, isReplay, req);\r\n\r\n    if (options.throw) throw finalResult.error ?? err;\r\n\r\n    return finalResult;\r\n  }\r\n\r\n  /**\r\n   * Run all after-interceptors on `result`, providing each with a `replay()` context.\r\n   *\r\n   * `replay()` re-fires the original request from scratch (fresh auth, before-interceptors).\r\n   * When `isReplay` is true, `replay()` is a no-op that returns the current result — this\r\n   * prevents infinite loops when a token-refresh interceptor would otherwise call replay()\r\n   * on the already-replayed request.\r\n   */\r\n  private async runAfterInterceptors<T>(\r\n    result: HttpResult<T>,\r\n    replayCtx: ReplayCtx,\r\n    isReplay: boolean,\r\n    req: OutgoingRequest,\r\n  ): Promise<HttpResult<T>> {\r\n    let finalResult = result as HttpResult<unknown>;\r\n\r\n    for (const interceptor of this.afterInterceptors) {\r\n      const context: AfterInterceptorContext<unknown> = {\r\n        replay: isReplay\r\n          ? async (): Promise<HttpResult<unknown>> => finalResult\r\n          : (): Promise<HttpResult<unknown>> => this.execute<unknown>(\r\n              replayCtx.method as HttpMethod,\r\n              replayCtx.path,\r\n              replayCtx.data,\r\n              replayCtx.options,\r\n              new AbortController().signal,\r\n              true, // isReplay = true — prevents recursive replays\r\n            ),\r\n      };\r\n\r\n      const modified = await interceptor(finalResult, context);\r\n      if (modified) finalResult = modified;\r\n    }\r\n\r\n    if (finalResult.error === null) {\r\n      this.emit(\"response\", { request: sanitiseRequestForEvent(req), response: finalResult });\r\n    } else {\r\n      this.emit(\"error\", { request: sanitiseRequestForEvent(req), response: finalResult });\r\n    }\r\n\r\n    return finalResult as HttpResult<T>;\r\n  }\r\n\r\n  // ─── Helpers ─────────────────────────────────────────────────────────────────\r\n\r\n  private shouldRetry(err: HttpError, config: HttpRetryConfig): boolean {\r\n    if (err.isNetwork) return true;\r\n    if (err.status === null) return false;\r\n    const retryOn = config.retryOn ?? DEFAULT_RETRY_ON;\r\n    return retryOn.includes(err.status);\r\n  }\r\n\r\n  /**\r\n   * Whether this GET should join the in-flight dedup pool.\r\n   *\r\n   * Per-request wins over instance config, which wins over the environment default:\r\n   * on in a browser (one user per instance), off everywhere else.\r\n   */\r\n  private shouldDedupe(options: RequestOptions): boolean {\r\n    return options.dedupe ?? this.config.dedupe ?? isBrowser();\r\n  }\r\n\r\n  /**\r\n   * Resolve the key that decides which concurrent GETs share one underlying fetch.\r\n   *\r\n   * Precedence: explicit per-request key → `config.dedupeKey(url, params)` → URL + params.\r\n   *\r\n   * The last two are derived from URL + params only — they never see headers, cookies or\r\n   * auth, so they cannot tell two *users* apart. That is fine in a browser and unsafe on a\r\n   * server, so outside a browser an explicit per-request key is mandatory. We refuse rather\r\n   * than guess which header carries identity: a guess would miss custom schemes (a tenant\r\n   * header, a signed cookie) while looking safe, which is worse than failing loudly.\r\n   */\r\n  private resolveDedupeKey(\r\n    rawUrl: string,\r\n    mergedParams: HttpParams | undefined,\r\n    options: RequestOptions,\r\n  ): string {\r\n    if (options.dedupeKey) return options.dedupeKey;\r\n\r\n    if (!isBrowser()) {\r\n      throw new Error(\r\n        \"@mongez/http: GET deduplication is enabled outside a browser, which would let \" +\r\n          \"concurrent requests with different credentials share one response. Pass an \" +\r\n          'identity-aware key — http.get(path, { dedupeKey: `me:${userId}` }) — or disable ' +\r\n          \"deduplication with { dedupe: false } on the request or the Http config.\",\r\n      );\r\n    }\r\n\r\n    return this.config.dedupeKey\r\n      ? this.config.dedupeKey(rawUrl, mergedParams)\r\n      : appendParams(rawUrl, mergedParams);\r\n  }\r\n\r\n  /**\r\n   * Build the `RequestInit` for a fetch call.\r\n   *\r\n   * Caller-supplied `fetchInit` is spread FIRST so that keys the library doesn't model —\r\n   * Next.js' `next: { revalidate, tags }`, runtime-specific flags — reach fetch, while the\r\n   * fields the library manages are written last and win. `method`/`headers`/`body`/`signal`\r\n   * always win (overriding them would bypass interceptors and auth, or break cancellation\r\n   * and timeouts); the optional ones win only when actually configured, so an unset option\r\n   * doesn't erase a deliberate `fetchInit` value.\r\n   *\r\n   * @param keepalive Whether `keepalive` participates at all. Streaming never applies it —\r\n   *                  it caps the body at 64 KB and exists for unload beacons, so a globally\r\n   *                  configured `keepalive: true` must not reach a long-lived stream.\r\n   */\r\n  private buildFetchInit(\r\n    req: OutgoingRequest,\r\n    body: BodyInit | undefined,\r\n    signal: AbortSignal,\r\n    options: RequestOptions,\r\n    extraInit: Record<string, unknown> = {},\r\n    keepalive = true,\r\n  ): RequestInit {\r\n    const init: Record<string, unknown> = {\r\n      ...this.config.fetchInit,\r\n      ...options.fetchInit,\r\n      ...extraInit,\r\n      method: req.method,\r\n      headers: req.headers,\r\n      body,\r\n      signal,\r\n    };\r\n\r\n    assignIfDefined(init, \"credentials\", options.credentials ?? this.config.credentials);\r\n    assignIfDefined(init, \"mode\", options.mode ?? this.config.mode);\r\n    assignIfDefined(init, \"redirect\", options.redirect ?? this.config.redirect);\r\n    assignIfDefined(init, \"cache\", options.fetchCache ?? this.config.fetchCache);\r\n\r\n    if (keepalive) {\r\n      assignIfDefined(init, \"keepalive\", options.keepalive ?? this.config.keepalive);\r\n    }\r\n\r\n    return init as RequestInit;\r\n  }\r\n\r\n  /**\r\n   * The fallback cache key, used only when neither `options.cacheKey` nor\r\n   * `cache.generateKey` was supplied.\r\n   *\r\n   * URL + params has the same blind spot as the default dedup key: it cannot tell two\r\n   * callers apart, so on a server an authenticated response could be handed to a different\r\n   * user. The cache is opt-in, so reaching here outside a browser means someone enabled it\r\n   * without saying how entries are scoped — refuse instead of caching per-user data under a\r\n   * shared key.\r\n   */\r\n  private defaultCacheKey(url: string, params?: HttpParams): string {\r\n    if (!isBrowser()) {\r\n      throw new Error(\r\n        \"@mongez/http: response caching is enabled outside a browser without an \" +\r\n          \"identity-aware key, so one user's cached response could be served to another. \" +\r\n          'Pass a per-request key — http.get(path, { cacheKey: `me:${userId}` }) — or a ' +\r\n          \"cache.generateKey that includes the caller's identity. On a server, prefer the \" +\r\n          \"framework's own cache (Next.js: fetchInit: { next: { revalidate, tags } }).\",\r\n      );\r\n    }\r\n\r\n    return buildCacheKey(url, params);\r\n  }\r\n\r\n  private resolveCacheConfig(options: RequestOptions): ResolvedCache | null {\r\n    const opt = options.cache;\r\n    const global = this.config.cache;\r\n\r\n    if (opt === false) return null;\r\n\r\n    if (opt && typeof opt === \"object\") {\r\n      const driver = opt.driver ?? (typeof global === \"object\" ? global.driver : null);\r\n      if (!driver) return null;\r\n      return { ...opt, driver } as ResolvedCache;\r\n    }\r\n\r\n    if (opt === true || opt === undefined) {\r\n      if (!global) return null;\r\n      if (typeof global === \"object\") return global as ResolvedCache;\r\n    }\r\n\r\n    return null;\r\n  }\r\n\r\n  private resolveRetryConfig(options: RequestOptions): HttpRetryConfig | null {\r\n    const opt = options.retry;\r\n    const global = this.config.retry;\r\n\r\n    if (opt === false) return null;\r\n    if (opt === true || opt === undefined) return global ?? null;\r\n    if (typeof opt === \"object\") {\r\n      return { attempts: 3, delay: 300, ...global, ...opt };\r\n    }\r\n    return null;\r\n  }\r\n}\r\n\r\n// ─── Internal types ──────────────────────────────────────────────────────────\r\n\r\ntype ResolvedCache = HttpCacheConfig & { driver: CacheDriver };\r\n\r\n// ─── Utility: merge two AbortSignals ─────────────────────────────────────────\r\n// Each handler removes the other listener when it fires, preventing leaks when\r\n// only one signal ever aborts (e.g. timeout fires but cancel never does).\r\n\r\nfunction mergeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\r\n  const controller = new AbortController();\r\n\r\n  if (a.aborted || b.aborted) {\r\n    controller.abort();\r\n    return controller.signal;\r\n  }\r\n\r\n  const abortFromA = (): void => { controller.abort(); b.removeEventListener(\"abort\", abortFromB); };\r\n  const abortFromB = (): void => { controller.abort(); a.removeEventListener(\"abort\", abortFromA); };\r\n\r\n  a.addEventListener(\"abort\", abortFromA, { once: true });\r\n  b.addEventListener(\"abort\", abortFromB, { once: true });\r\n\r\n  return controller.signal;\r\n}\r\n"],"mappings":"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"}