httix-http 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/core/defaults.ts","../../src/core/errors.ts","../../src/core/request.ts","../../src/core/response.ts","../../src/features/interceptors.ts","../../src/utils/helpers.ts","../../src/features/retry.ts","../../src/features/dedup.ts","../../src/features/rateLimit.ts","../../src/features/middleware.ts","../../src/features/auth.ts","../../src/features/pagination.ts","../../src/features/streaming.ts","../../src/utils/headers.ts","../../src/utils/merge.ts","../../src/core/client.ts","../../src/features/abort.ts","../../src/features/timeout.ts","../../src/methods/get.ts","../../src/methods/post.ts","../../src/methods/put.ts","../../src/methods/patch.ts","../../src/methods/delete.ts","../../src/methods/head.ts","../../src/methods/options.ts","../../src/methods/request.ts"],"sourcesContent":["/**\n * httix-http — Main entry point\n *\n * Re-exports every public API surface from the library and creates a\n * pre-configured default client instance for convenience.\n *\n * @example\n * ```ts\n * // 1. Use the default instance directly\n * import httix from 'httix-http';\n * const { data } = await httix.get('/users');\n *\n * // 2. Create a custom instance\n * import { createHttix } from 'httix-http';\n * const api = createHttix({ baseURL: 'https://api.example.com' });\n * const { data } = await api.get('/users');\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\nexport { HttixClientImpl, createHttix } from './core/client';\nexport type { HttixClient as HttixClientInterface } from './core/types';\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport {\n HttixError,\n HttixRequestError,\n HttixResponseError,\n HttixTimeoutError,\n HttixAbortError,\n HttixRetryError,\n} from './core/errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type {\n HttpMethod,\n RequestBody,\n QueryParamValue,\n QueryParams,\n PathParams,\n HttixHeaders,\n BackoffStrategy,\n RetryConfig,\n RateLimitConfig,\n DedupConfig,\n AuthConfig,\n BearerAuthConfig,\n BasicAuthConfig,\n ApiKeyAuthConfig,\n PaginationStyle,\n PaginationConfig,\n DownloadProgress,\n SSEEvent,\n StreamConfig,\n MiddlewareContext,\n MiddlewareFn,\n RequestInterceptor,\n RequestErrorInterceptor,\n ResponseInterceptor,\n ResponseErrorInterceptor,\n InterceptorHandler,\n InterceptorManager as InterceptorManagerInterface,\n HttixConfig,\n HttixRequestConfig,\n HttixResponse,\n HttixPlugin,\n} from './core/types';\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nexport {\n DEFAULT_CONFIG,\n DEFAULT_RETRY,\n DEFAULT_TIMEOUT,\n DEFAULT_HEADERS,\n DEFAULT_REQUEST_CONFIG,\n} from './core/defaults';\n\n// ---------------------------------------------------------------------------\n// Features\n// ---------------------------------------------------------------------------\n\nexport { InterceptorManager } from './features/interceptors';\nexport { createCancelToken, isCancel, createCancelError } from './features/abort';\nexport { RequestDeduplicator } from './features/dedup';\nexport { RateLimiter } from './features/rateLimit';\nexport { composeMiddleware } from './features/middleware';\nexport { parseSSE, parseNDJSON, createProgressReader } from './features/streaming';\nexport { retryRequest, parseRetryAfter } from './features/retry';\nexport { createTimeoutController, clearTimeoutController } from './features/timeout';\nexport { applyAuth, createAuthInterceptor, createAuthRefreshHandler } from './features/auth';\nexport { createPaginator, parseLinkHeader } from './features/pagination';\n\n// ---------------------------------------------------------------------------\n// Method factories\n// ---------------------------------------------------------------------------\n\nexport { createGetMethod } from './methods/get';\nexport { createPostMethod } from './methods/post';\nexport { createPutMethod } from './methods/put';\nexport { createPatchMethod } from './methods/patch';\nexport { createDeleteMethod } from './methods/delete';\nexport { createHeadMethod } from './methods/head';\nexport { createOptionsMethod } from './methods/options';\nexport { createRequestMethod } from './methods/request';\n\n// ---------------------------------------------------------------------------\n// Default instance\n// ---------------------------------------------------------------------------\n\nimport { HttixClientImpl } from './core/client';\nimport { isCancel } from './features/abort';\n\n/**\n * Pre-configured default client instance.\n *\n * All HTTP methods are pre-bound so they can be destructured or passed\n * around without losing the `this` context.\n *\n * @example\n * ```ts\n * import httix from 'httix-http';\n *\n * // Direct usage\n * const { data } = await httix.get('/users');\n *\n * // Destructure for ergonomic usage\n * const { get, post, put, patch, delete: remove } = httix;\n *\n * // Create a derived client with different defaults\n * const adminApi = httix.create({\n * baseURL: 'https://admin.api.example.com',\n * auth: { type: 'bearer', token: adminToken },\n * });\n * ```\n */\nconst defaultClient = new HttixClientImpl();\n\nconst httix = {\n /** Core request method */\n request: defaultClient.request.bind(defaultClient),\n\n /** HTTP method shortcuts */\n get: defaultClient.get.bind(defaultClient),\n post: defaultClient.post.bind(defaultClient),\n put: defaultClient.put.bind(defaultClient),\n patch: defaultClient.patch.bind(defaultClient),\n delete: defaultClient.delete.bind(defaultClient),\n head: defaultClient.head.bind(defaultClient),\n options: defaultClient.options.bind(defaultClient),\n\n /** Interceptor managers */\n interceptors: defaultClient.interceptors,\n\n /** Stream utilities */\n stream: defaultClient.stream,\n\n /** Pagination helper */\n paginate: defaultClient.paginate,\n\n /** Client defaults */\n defaults: defaultClient.defaults,\n\n /** Register middleware */\n use: defaultClient.use.bind(defaultClient),\n\n /** Create a new client with merged configuration */\n create: (config?: Partial<import('./core/types').HttixConfig>) =>\n new HttixClientImpl(config),\n\n /** Cancel all in-flight requests */\n cancelAll: defaultClient.cancelAll.bind(defaultClient),\n\n /** Check whether an error is a cancellation error */\n isCancel,\n\n /**\n * Alias for {@link createHttix} — create a new client instance.\n */\n createHttix: (config?: Partial<import('./core/types').HttixConfig>) =>\n new HttixClientImpl(config),\n};\n\nexport default httix;\n","/**\n * httix — Default configuration values\n */\n\nimport type { HttixConfig, HttixRequestConfig, RetryConfig } from './types';\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY: Required<RetryConfig> = {\n attempts: 3,\n backoff: 'exponential',\n baseDelay: 1000,\n maxDelay: 30000,\n jitter: true,\n retryOn: [408, 429, 500, 502, 503, 504],\n retryOnNetworkError: true,\n retryOnSafeMethodsOnly: false,\n retryCondition: () => true,\n onRetry: () => {},\n};\n\n/** Default timeout in milliseconds */\nexport const DEFAULT_TIMEOUT = 30000;\n\n/** Default headers */\nexport const DEFAULT_HEADERS: Record<string, string> = {\n Accept: 'application/json, text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n 'Accept-Language': '*',\n};\n\n/** Default request configuration */\nexport const DEFAULT_REQUEST_CONFIG: Partial<HttixRequestConfig> = {\n method: 'GET',\n timeout: DEFAULT_TIMEOUT,\n throwOnError: true,\n credentials: 'same-origin',\n mode: 'cors',\n redirect: 'follow',\n cache: 'default',\n};\n\n/** Default client configuration */\nexport const DEFAULT_CONFIG: HttixConfig = {\n url: '',\n baseURL: '',\n headers: DEFAULT_HEADERS,\n timeout: DEFAULT_TIMEOUT,\n throwOnError: true,\n credentials: 'same-origin',\n mode: 'cors',\n redirect: 'follow',\n cache: 'default',\n retry: DEFAULT_RETRY,\n dedup: false,\n};\n","/**\n * httix — Error class hierarchy\n */\n\nimport type { HttixErrorOptions, HttixRequestConfig } from './types';\n\n/**\n * Base error class for all httix errors.\n */\nexport class HttixError extends Error {\n public readonly name: string = 'HttixError';\n public readonly config?: HttixRequestConfig;\n public override readonly cause?: Error;\n\n constructor(message: string, options?: HttixErrorOptions) {\n super(message);\n this.name = 'HttixError';\n this.config = options?.config;\n this.cause = options?.cause;\n\n // Restore proper prototype chain (required for extending built-ins in TS)\n Object.setPrototypeOf(this, new.target.prototype);\n\n // Maintain proper stack trace in V8 environments\n const ErrorConstructor = Error as unknown as {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (ErrorConstructor.captureStackTrace) {\n ErrorConstructor.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when a network-level request failure occurs\n * (e.g., DNS failure, connection refused, CORS error).\n */\nexport class HttixRequestError extends HttixError {\n public readonly name: string = 'HttixRequestError';\n\n constructor(message: string, options?: HttixErrorOptions) {\n super(message, options);\n this.name = 'HttixRequestError';\n }\n}\n\n/**\n * Error thrown when the server responds with a 4xx or 5xx status code.\n */\nexport class HttixResponseError extends HttixError {\n public readonly name: string = 'HttixResponseError';\n public readonly status: number;\n public readonly statusText: string;\n public readonly data: unknown;\n public readonly headers?: Headers;\n public override readonly config?: HttixRequestConfig;\n\n constructor(\n status: number,\n statusText: string,\n data: unknown,\n headers?: Headers,\n config?: HttixRequestConfig,\n ) {\n const message = `Request failed with status ${status}: ${statusText}`;\n super(message, { message, config });\n this.name = 'HttixResponseError';\n this.status = status;\n this.statusText = statusText;\n this.data = data;\n this.headers = headers;\n this.config = config;\n }\n}\n\n/**\n * Error thrown when a request exceeds its configured timeout.\n */\nexport class HttixTimeoutError extends HttixError {\n public readonly name: string = 'HttixTimeoutError';\n public readonly timeout: number;\n\n constructor(timeout: number, config?: HttixRequestConfig) {\n const message = `Request timed out after ${timeout}ms`;\n super(message, { message, config });\n this.name = 'HttixTimeoutError';\n this.timeout = timeout;\n }\n}\n\n/**\n * Error thrown when a request is cancelled via AbortController.\n */\nexport class HttixAbortError extends HttixError {\n public readonly name: string = 'HttixAbortError';\n public readonly reason: string;\n\n constructor(reason?: string, config?: HttixRequestConfig) {\n const message = reason ?? 'Request was aborted';\n super(message, { message, config });\n this.name = 'HttixAbortError';\n this.reason = message;\n }\n}\n\n/**\n * Error thrown when all retry attempts have been exhausted.\n */\nexport class HttixRetryError extends HttixError {\n public readonly name: string = 'HttixRetryError';\n public readonly attempts: number;\n public readonly lastError: HttixError;\n\n constructor(attempts: number, lastError: HttixError, config?: HttixRequestConfig) {\n const message = `Request failed after ${attempts} attempt${attempts === 1 ? '' : 's'}`;\n super(message, { message, config, cause: lastError });\n this.name = 'HttixRetryError';\n this.attempts = attempts;\n this.lastError = lastError;\n }\n}\n","/**\n * httix — Request builder\n *\n * Transforms an HttixRequestConfig into a native `Request` instance ready\n * for `fetch()`, handling URL interpolation, header merging, body\n * serialisation, timeout scheduling, and abort-signal composition.\n */\n\nimport type {\n HttixHeaders,\n HttixRequestConfig,\n PathParams,\n QueryParams,\n RequestBody,\n} from './types';\nimport { DEFAULT_HEADERS } from './defaults';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface BuildRequestResult {\n request: globalThis.Request;\n timeoutController?: AbortController;\n timeoutId?: ReturnType<typeof setTimeout>;\n}\n\n/**\n * Builds a native `Request` from an `HttixRequestConfig`.\n *\n * The returned `timeoutController` / `timeoutId` must be cleared by the\n * caller via `clearTimeoutSignal` once the request settles, otherwise the\n * timer will leak and keep the event-loop alive.\n */\nexport function buildRequest(config: HttixRequestConfig): BuildRequestResult {\n // 1. Build the full URL (baseURL + url interpolation + query string)\n const url = buildUrl(config.baseURL, config.url, config.params, config.query);\n\n // 2. Merge default headers with per-request headers (request wins)\n const headers = mergeHeaders(DEFAULT_HEADERS, config.headers);\n\n // 3. Serialise the request body (may mutate `headers` to set Content-Type)\n const body = serializeBody(config.body, headers);\n\n // 4. Create the native Request object\n const method = config.method ?? 'GET';\n const requestInit: globalThis.RequestInit = {\n method,\n headers,\n body,\n credentials: config.credentials,\n mode: config.mode,\n cache: config.cache,\n redirect: config.redirect,\n referrerPolicy: config.referrerPolicy,\n };\n\n // 5. Compose abort signals (config.signal + optional timeout)\n const timeout = config.timeout ?? 0;\n let timeoutController: AbortController | undefined;\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeout > 0) {\n timeoutController = new AbortController();\n timeoutId = setTimeout(() => {\n timeoutController!.abort(new DOMException(`Request timed out after ${timeout}ms`, 'TimeoutError'));\n }, timeout);\n\n if (config.signal) {\n // Both signals exist — combine so that *either* aborting cancels the request\n requestInit.signal = combineSignals(config.signal, timeoutController.signal);\n } else {\n requestInit.signal = timeoutController.signal;\n }\n } else if (config.signal) {\n requestInit.signal = config.signal;\n }\n\n const request = new globalThis.Request(url, requestInit);\n\n return { request, timeoutController, timeoutId };\n}\n\n/**\n * Cleans up the timeout timer and abort controller created by `buildRequest`.\n * Should be called in a `finally` block after the fetch settles.\n */\nexport function clearTimeoutSignal(\n controller: AbortController | undefined,\n timeoutId: ReturnType<typeof setTimeout> | undefined,\n): void {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n if (controller) {\n controller.abort(); // no-op if already aborted, but releases listeners\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Combines multiple `AbortSignal`s into a single signal that aborts when\n * *any* of the source signals abort.\n */\nfunction combineSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n break;\n }\n signal.addEventListener(\n 'abort',\n () => controller.abort(signal.reason),\n { once: true },\n );\n }\n\n return controller.signal;\n}\n\n/**\n * Builds the full request URL by:\n * 1. Joining `baseURL` + `url` (handling slashes)\n * 2. Replacing `:paramName` path parameters\n * 3. Appending query-string parameters\n */\nfunction buildUrl(\n baseURL: string | undefined,\n url: string,\n params: PathParams | undefined,\n query: QueryParams | undefined,\n): string {\n let full = url;\n\n // Combine baseURL + url\n if (baseURL) {\n const base = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL;\n const path = full.startsWith('/') ? full : `/${full}`;\n full = `${base}${path}`;\n }\n\n // Interpolate path parameters (:paramName → value)\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n full = full.replace(`:${key}`, encodeURIComponent(String(value)));\n }\n }\n\n // Append query parameters\n if (query && Object.keys(query).length > 0) {\n const separator = full.includes('?') ? '&' : '?';\n full += `${separator}${encodeQueryParams(query)}`;\n }\n\n return full;\n}\n\n/**\n * Encodes a `QueryParams` object into a URL query string.\n * Handles arrays as repeated keys: `?key=a&key=b`\n */\nfunction encodeQueryParams(query: QueryParams): string {\n const parts: string[] = [];\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n // Skip nullish values entirely\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item !== undefined && item !== null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`);\n }\n }\n } else {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n\n return parts.join('&');\n}\n\n/**\n * Merges default headers with per-request headers.\n * Request headers always take precedence over defaults.\n */\nfunction mergeHeaders(\n defaults: HttixHeaders,\n custom?: HttixHeaders,\n): Headers {\n const merged = new Headers();\n\n // Apply defaults first\n applyHeaders(merged, defaults);\n\n // Custom headers override defaults\n if (custom) {\n applyHeaders(merged, custom);\n }\n\n return merged;\n}\n\n/**\n * Applies a `HttixHeaders` value to a `Headers` instance.\n */\nfunction applyHeaders(target: Headers, source: HttixHeaders): void {\n if (source instanceof Headers) {\n source.forEach((value, key) => {\n target.set(key, value);\n });\n } else {\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined) {\n target.set(key, value);\n }\n }\n }\n}\n\n/**\n * Serialises an `RequestBody` into a value suitable for the Fetch API\n * `body` parameter. Mutates `headers` to set `Content-Type` when JSON\n * serialisation is performed and no explicit Content-Type is present.\n *\n * Returns `undefined` when there is no body to send (which is correct for\n * GET/HEAD requests in the Fetch API).\n */\nfunction serializeBody(\n body: RequestBody | undefined,\n headers: Headers,\n): globalThis.BodyInit | undefined {\n if (body === undefined || body === null) {\n return undefined;\n }\n\n // Pass through natively-supported body types directly\n if (\n typeof body === 'string' ||\n body instanceof FormData ||\n body instanceof URLSearchParams ||\n body instanceof Blob ||\n body instanceof ArrayBuffer ||\n body instanceof ReadableStream\n ) {\n return body;\n }\n\n // Objects and arrays → JSON\n if (typeof body === 'object') {\n // Set Content-Type to application/json if not already set\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n return JSON.stringify(body);\n }\n\n // Primitives (number, boolean)\n // number / boolean — serialise as JSON string for consistency\n if (typeof body === 'number' || typeof body === 'boolean') {\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n return JSON.stringify(body);\n }\n\n return undefined;\n}\n","/**\n * httix — Response wrapper and body parsing utilities\n */\n\nimport type { HttixRequestConfig, HttixResponse } from './types';\n\n/**\n * Creates a fully-populated HttixResponse from a raw Fetch Response.\n */\nexport function createResponse<T>(\n raw: Response,\n config: HttixRequestConfig,\n data: T,\n timing: number,\n): HttixResponse<T> {\n return {\n data,\n status: raw.status,\n statusText: raw.statusText,\n headers: raw.headers,\n ok: raw.ok,\n raw,\n timing,\n config,\n };\n}\n\n/**\n * Parses the body of a Fetch Response according to the request configuration.\n *\n * Resolution order:\n * 1. Custom `parseResponse` function on config\n * 2. Explicit `responseType` ('json' | 'text' | 'blob' | 'arrayBuffer')\n * 3. Auto-detection based on Content-Type header and status code\n */\nexport async function parseResponseBody<T>(\n response: Response,\n config: HttixRequestConfig,\n): Promise<T> {\n // 1. Custom parser takes absolute precedence\n if (typeof config.parseResponse === 'function') {\n return (await config.parseResponse(response)) as T;\n }\n\n // 204 No Content — nothing to parse\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get('Content-Type') ?? '';\n\n // 2. Explicit responseType override\n if (config.responseType) {\n return parseWithType<T>(response, config.responseType);\n }\n\n // 3. Auto-detection\n return autoParse<T>(response, contentType);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nasync function parseWithType<T>(\n response: Response,\n responseType: NonNullable<HttixRequestConfig['responseType']>,\n): Promise<T> {\n switch (responseType) {\n case 'json': {\n try {\n return (await response.json()) as T;\n } catch {\n return undefined as T;\n }\n }\n case 'text': {\n try {\n return (await response.text()) as T;\n } catch {\n return undefined as T;\n }\n }\n case 'blob': {\n try {\n return (await response.blob()) as T;\n } catch {\n return undefined as T;\n }\n }\n case 'arrayBuffer': {\n try {\n return (await response.arrayBuffer()) as T;\n } catch {\n return undefined as T;\n }\n }\n }\n}\n\nasync function autoParse<T>(response: Response, contentType: string): Promise<T> {\n const lowerCt = contentType.toLowerCase();\n\n // application/json\n if (lowerCt.includes('application/json')) {\n try {\n return (await response.json()) as T;\n } catch {\n return undefined as T;\n }\n }\n\n // text/*\n if (lowerCt.includes('text/')) {\n try {\n return (await response.text()) as T;\n } catch {\n return undefined as T;\n }\n }\n\n // Null body (e.g. 204 already handled, but defensive check for zero-length)\n if (!response.body) {\n return undefined as T;\n }\n\n // Best-effort: read as text first, then try JSON.parse.\n // We cannot call response.json() then response.text() because the body\n // stream is consumed after the first read. Reading as text first lets us\n // attempt JSON parsing on the resulting string without double-consuming.\n try {\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n // Not valid JSON — return the raw text as a best-effort fallback\n return text as T;\n }\n /* v8 ignore next 4 */\n } catch {\n // Body stream error — defensive fallback\n return undefined as T;\n }\n}\n","/**\n * httix — Interceptor management and execution\n */\n\nimport type {\n HttixRequestConfig,\n HttixResponse,\n InterceptorHandler,\n InterceptorManager as InterceptorManagerInterface,\n RequestInterceptor,\n RequestErrorInterceptor,\n ResponseErrorInterceptor,\n ResponseInterceptor,\n} from '../core/types';\nimport type { HttixError } from '../core/errors';\n\n/**\n * Manages a list of interceptor handlers for requests or responses.\n * Handlers can be added, ejected by id, or cleared entirely.\n */\nexport class InterceptorManager<F, E> implements InterceptorManagerInterface<F, E> {\n handlers: InterceptorHandler<F, E>[] = [];\n\n use(fulfilled: F, rejected?: E): number {\n this.handlers.push({ fulfilled, rejected });\n return this.handlers.length - 1;\n }\n\n eject(id: number): void {\n if (id >= 0 && id < this.handlers.length) {\n this.handlers[id] = null as unknown as InterceptorHandler<F, E>;\n }\n }\n\n clear(): void {\n this.handlers = [];\n }\n}\n\n/**\n * Run request interceptors sequentially, chaining each fulfilled handler's\n * output as the next handler's input. If a handler's fulfilled function\n * throws and it has a rejected handler, the rejected handler is called.\n * If the rejected handler returns a config the chain continues; if it\n * re-throws, the error propagates.\n */\nexport async function runRequestInterceptors(\n config: HttixRequestConfig,\n interceptors: InterceptorManagerInterface<RequestInterceptor, RequestErrorInterceptor>,\n): Promise<HttixRequestConfig> {\n let currentConfig = config;\n\n for (const handler of interceptors.handlers) {\n if (handler === null) continue;\n\n try {\n currentConfig = await handler.fulfilled(currentConfig);\n } catch (err) {\n if (handler.rejected) {\n try {\n const result = await handler.rejected(err as HttixError);\n // If rejected returns a config, continue the chain with it\n if (result !== undefined) {\n currentConfig = result;\n }\n // If rejected returns void, continue with the current config\n } catch {\n // Rejected handler threw — propagate the error\n throw err;\n }\n } else {\n // No rejected handler — propagate the error\n throw err;\n }\n }\n }\n\n return currentConfig;\n}\n\n/**\n * Run response interceptors sequentially, chaining each fulfilled handler's\n * output as the next handler's input. Error handling mirrors\n * runRequestInterceptors.\n */\nexport async function runResponseInterceptors<T>(\n response: HttixResponse<T>,\n interceptors: InterceptorManagerInterface<ResponseInterceptor<T>, ResponseErrorInterceptor>,\n): Promise<HttixResponse<T>> {\n let currentResponse = response;\n\n for (const handler of interceptors.handlers) {\n if (handler === null) continue;\n\n try {\n currentResponse = await handler.fulfilled(currentResponse);\n } catch (err) {\n if (handler.rejected) {\n try {\n const result = await handler.rejected(err as HttixError);\n if (result !== undefined) {\n currentResponse = result as HttixResponse<T>;\n }\n } catch {\n throw err;\n }\n } else {\n throw err;\n }\n }\n }\n\n return currentResponse;\n}\n\n/**\n * Attempt to handle a response error through response interceptors' rejected\n * handlers. If any rejected handler returns a response, the error is considered\n * \"handled\" and that response is returned. If no handler resolves the error,\n * the original error is re-thrown.\n */\nexport async function runResponseErrorInterceptors(\n error: HttixError,\n interceptors: InterceptorManagerInterface<ResponseInterceptor<unknown>, ResponseErrorInterceptor>,\n): Promise<HttixResponse<unknown>> {\n for (const handler of interceptors.handlers) {\n if (handler === null) continue;\n\n if (handler.rejected) {\n try {\n const result = await handler.rejected(error);\n // If the rejected handler returns a response, the error is handled\n if (result !== undefined && result !== null) {\n return result;\n }\n // If rejected returns void, continue to next handler\n } catch {\n // Rejected handler threw — continue to next handler\n continue;\n }\n }\n }\n\n // No handler resolved the error — re-throw the original\n throw error;\n}\n","/**\n * httix — General-purpose helper utilities\n */\n\nimport type { BackoffStrategy } from '../core/types';\nimport { HttixRequestError, HttixResponseError, type HttixError } from '../core/errors';\nimport { isAbsoluteURL } from './url';\n\n// Re-export isAbsoluteURL from url.ts so consumers can import from helpers\nexport { isAbsoluteURL };\n\n/**\n * Return a promise that resolves after the given number of milliseconds.\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise<void>((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Generate a unique request ID useful for tracing.\n * Format: `req_<timestamp>_<random7chars>`\n */\nexport function generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * Determine whether an error is eligible for automatic retry.\n *\n * - HttixRequestError (network-level failures) → retryable\n * - HttixResponseError with retryable status codes → retryable\n * - Everything else → not retryable\n */\nexport function isRetryableError(error: HttixError): boolean {\n if (error instanceof HttixRequestError) {\n return true;\n }\n\n if (error instanceof HttixResponseError) {\n return isRetryableStatus(error.status);\n }\n\n return false;\n}\n\n/**\n * Check whether an HTTP status code is considered retryable.\n */\nexport function isRetryableStatus(status: number): boolean {\n return [408, 429, 500, 502, 503, 504].includes(status);\n}\n\n/**\n * Calculate the delay in milliseconds before the next retry attempt.\n *\n * @param attempt - The current attempt number (1-based)\n * @param backoff - The backoff strategy to use\n * @param baseDelay - The base delay in milliseconds\n * @param maxDelay - The maximum allowed delay in milliseconds\n * @param jitter - Whether to apply random jitter (50%–100% of calculated delay)\n */\nexport function calculateDelay(\n attempt: number,\n backoff: BackoffStrategy,\n baseDelay: number,\n maxDelay: number,\n jitter: boolean,\n): number {\n let calculated: number;\n\n switch (backoff) {\n case 'fixed':\n calculated = baseDelay;\n break;\n case 'linear':\n calculated = baseDelay * attempt;\n break;\n case 'exponential':\n calculated = baseDelay * Math.pow(2, attempt - 1);\n break;\n default:\n // Fallback for unknown strategies — should never happen with valid BackoffStrategy\n calculated = baseDelay;\n break;\n }\n\n // Clamp to maxDelay\n calculated = Math.min(calculated, maxDelay);\n\n // Apply jitter: random value between 50% and 100% of the calculated delay\n if (jitter) {\n calculated = calculated * (0.5 + Math.random() * 0.5);\n }\n\n // Ensure the delay is never negative\n return Math.max(0, calculated);\n}\n","/**\n * httix — Retry logic\n */\n\nimport type { HttixRequestConfig, HttixResponse, RetryConfig } from '../core/types';\nimport { DEFAULT_RETRY } from '../core/defaults';\nimport { HttixRequestError, HttixResponseError } from '../core/errors';\nimport { calculateDelay, delay } from '../utils/helpers';\n\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\n\n/**\n * Parse a Retry-After header value.\n *\n * - If the value is a plain number, it represents seconds to wait.\n * - If the value is an ISO date string, calculate the number of seconds\n * from now until that date.\n * - Returns null if the value cannot be parsed.\n */\nexport function parseRetryAfter(value: string | null): number | null {\n if (value === null) return null;\n\n // Try parsing as a number of seconds\n const seconds = Number(value);\n if (!Number.isNaN(seconds) && seconds > 0 && String(seconds) === value.trim()) {\n return seconds * 1000;\n }\n\n // Try parsing as an ISO date string\n const date = Date.parse(value);\n if (!Number.isNaN(date)) {\n const diff = date - Date.now();\n return diff > 0 ? diff : 0;\n }\n\n return null;\n}\n\n/**\n * Execute a request function with retry support.\n *\n * Merges the provided retry configuration with defaults, evaluates retry\n * conditions on each failure, applies backoff delay, and throws\n * HttixRetryError if all attempts are exhausted.\n */\nexport async function retryRequest<T>(\n fn: () => Promise<HttixResponse<T>>,\n config: RetryConfig | false | undefined,\n requestConfig: HttixRequestConfig,\n): Promise<HttixResponse<T>> {\n // If retry is explicitly disabled, just execute once\n if (config === false || config === undefined) {\n return fn();\n }\n\n // Merge user config over defaults\n const retryCfg: Required<RetryConfig> = {\n attempts: config.attempts ?? DEFAULT_RETRY.attempts,\n backoff: config.backoff ?? DEFAULT_RETRY.backoff,\n baseDelay: config.baseDelay ?? DEFAULT_RETRY.baseDelay,\n maxDelay: config.maxDelay ?? DEFAULT_RETRY.maxDelay,\n jitter: config.jitter ?? DEFAULT_RETRY.jitter,\n retryOn: config.retryOn ?? DEFAULT_RETRY.retryOn,\n retryOnNetworkError: config.retryOnNetworkError ?? DEFAULT_RETRY.retryOnNetworkError,\n retryOnSafeMethodsOnly: config.retryOnSafeMethodsOnly ?? DEFAULT_RETRY.retryOnSafeMethodsOnly,\n retryCondition: config.retryCondition ?? DEFAULT_RETRY.retryCondition,\n onRetry: config.onRetry ?? DEFAULT_RETRY.onRetry,\n };\n\n const maxAttempts = retryCfg.attempts;\n const method = (requestConfig.method ?? 'GET').toUpperCase();\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const response = await fn();\n\n // Successful 2xx — return immediately\n if (response.status >= 200 && response.status < 300) {\n return response;\n }\n\n // Non-2xx response: check if retryable\n if (!retryCfg.retryOn.includes(response.status)) {\n return response;\n }\n\n // Create an HttixResponseError for consistency\n const responseError = new HttixResponseError(\n response.status,\n response.statusText,\n response.data,\n response.headers,\n requestConfig,\n );\n lastError = responseError;\n\n if (!shouldRetry(responseError, attempt, maxAttempts, retryCfg, method)) {\n throw responseError;\n }\n\n // Calculate and apply delay\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));\n const backoffMs = calculateDelay(\n attempt + 1,\n retryCfg.backoff,\n retryCfg.baseDelay,\n retryCfg.maxDelay,\n retryCfg.jitter,\n );\n const finalDelay = retryAfterMs !== null ? retryAfterMs : backoffMs;\n\n retryCfg.onRetry(attempt + 1, responseError, finalDelay);\n await delay(finalDelay);\n } catch (err) {\n lastError = err;\n\n if (!shouldRetry(err as Error, attempt, maxAttempts, retryCfg, method)) {\n throw err;\n }\n\n const httixErr = err as HttixRequestError | HttixResponseError;\n\n // Calculate and apply delay\n const retryAfterMs =\n httixErr instanceof HttixResponseError\n ? parseRetryAfter(httixErr.headers?.get('retry-after') ?? null)\n : null;\n const backoffMs = calculateDelay(\n attempt + 1,\n retryCfg.backoff,\n retryCfg.baseDelay,\n retryCfg.maxDelay,\n retryCfg.jitter,\n );\n const finalDelay = retryAfterMs !== null ? retryAfterMs : backoffMs;\n\n retryCfg.onRetry(attempt + 1, httixErr, finalDelay);\n await delay(finalDelay);\n }\n }\n\n // All attempts exhausted — defensive fallback\n /* v8 ignore start */\n if (!lastError) throw new Error('All retry attempts exhausted');\n throw lastError;\n}\n/* v8 ignore stop */\n\n/**\n * Determine whether the request should be retried based on the error\n * type, retry configuration, and current attempt.\n */\nfunction shouldRetry(\n error: Error,\n attempt: number,\n maxAttempts: number,\n config: Required<RetryConfig>,\n method: string,\n): boolean {\n // Check if attempts remaining\n if (attempt + 1 >= maxAttempts) {\n return false;\n }\n\n // Check safe methods restriction\n if (config.retryOnSafeMethodsOnly && !SAFE_METHODS.has(method)) {\n return false;\n }\n\n // Check custom retry condition\n if (!config.retryCondition(error as HttixResponseError & HttixRequestError)) {\n return false;\n }\n\n // Network error\n if (error instanceof HttixRequestError) {\n return config.retryOnNetworkError;\n }\n\n // Response error — check status against retryOn list\n if (error instanceof HttixResponseError) {\n return config.retryOn.includes(error.status);\n }\n\n return false;\n}\n","/**\n * httix — Request deduplication\n */\n\nimport type { HttixRequestConfig } from '../core/types';\n\n/**\n * Deduplicates in-flight requests and optionally caches responses\n * for a configurable TTL.\n *\n * - When `ttl` is 0 (default), only coalesces concurrent requests with\n * the same key — once the request resolves, subsequent calls execute\n * a new request.\n * - When `ttl` > 0, resolved responses are cached for the specified\n * duration and returned for matching keys without re-executing.\n */\nexport class RequestDeduplicator {\n private inflight = new Map<string, Promise<unknown>>();\n private cache = new Map<string, { data: unknown; timestamp: number }>();\n private ttl: number;\n\n constructor(ttl = 0) {\n this.ttl = ttl;\n }\n\n /**\n * Deduplicate a request by key.\n *\n * If a cached response is available (and not expired), return it.\n * If a request is already in-flight, return the same promise.\n * Otherwise, execute `requestFn`, cache the result (if TTL > 0),\n * and return it.\n */\n async dedup<T>(key: string, requestFn: () => Promise<T>): Promise<T> {\n // Check cache first (if TTL > 0)\n if (this.ttl > 0) {\n const cached = this.cache.get(key);\n if (cached && Date.now() - cached.timestamp < this.ttl) {\n return cached.data as T;\n }\n }\n\n // Check in-flight requests\n const inflight = this.inflight.get(key);\n if (inflight) {\n return inflight as Promise<T>;\n }\n\n // Execute the request\n const promise = requestFn().then((result) => {\n // Cache result if TTL > 0\n if (this.ttl > 0) {\n this.cache.set(key, { data: result, timestamp: Date.now() });\n }\n this.inflight.delete(key);\n return result;\n }).catch((error) => {\n this.inflight.delete(key);\n throw error;\n });\n\n this.inflight.set(key, promise);\n return promise;\n }\n\n /**\n * Generate a deduplication key from a request config.\n *\n * The key is composed of the HTTP method, origin, pathname, and\n * sorted query parameters.\n */\n generateKey(config: HttixRequestConfig): string {\n const url = new URL(config.url, config.baseURL);\n const sortedQuery = config.query\n ? Object.keys(config.query)\n .sort()\n .map((k) => `${k}=${String((config.query as Record<string, unknown>)[k])}`)\n .join('&')\n : '';\n return `${config.method || 'GET'}:${url.origin}${url.pathname}${sortedQuery ? '?' + sortedQuery : ''}`;\n }\n\n /**\n * Clear all in-flight requests and cached responses.\n */\n clear(): void {\n this.inflight.clear();\n this.cache.clear();\n }\n}\n","/**\n * httix — Rate limiting\n */\n\n/**\n * Token-bucket-style rate limiter that limits the number of concurrent\n * requests within a sliding time window per key.\n *\n * When the maximum number of requests for a key is reached, additional\n * requests are queued and drained when the next interval starts.\n */\nexport class RateLimiter {\n private queues = new Map<string, Array<{ execute: () => Promise<void>; resolve: (v: unknown) => void }>>();\n private activeCounts = new Map<string, number>();\n private timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n constructor(\n private maxRequests: number,\n private interval: number,\n ) {}\n\n /**\n * Throttle a request function by key.\n *\n * If the number of active requests for the given key is below\n * `maxRequests`, the request executes immediately. Otherwise, it is\n * queued and will execute when the next interval starts.\n */\n async throttle(key: string, requestFn: () => Promise<unknown>): Promise<unknown> {\n // If there's no active window, reset count (timer already fired)\n if (!this.timers.has(key)) {\n this.activeCounts.set(key, 0);\n }\n\n const count = this.activeCounts.get(key) || 0;\n\n if (count < this.maxRequests) {\n // Execute immediately\n this.activeCounts.set(key, count + 1);\n if (count === 0) {\n // Start the interval timer on first request of a new window\n this.timers.set(key, setTimeout(() => {\n this.activeCounts.set(key, 0);\n this.timers.delete(key);\n // Drain queue\n this.drainQueue(key);\n }, this.interval));\n }\n return requestFn();\n }\n\n // Queue the request — it will be resolved when drainQueue executes it\n return new Promise((resolve) => {\n if (!this.queues.has(key)) {\n this.queues.set(key, []);\n }\n this.queues.get(key)!.push({\n execute: async () => {\n const result = await requestFn();\n resolve(result);\n },\n /* v8 ignore next */\n resolve: () => {},\n });\n });\n }\n\n /**\n * Drain queued requests for a given key, processing up to maxRequests\n * and starting a new interval timer.\n */\n private drainQueue(key: string): void {\n const queue = this.queues.get(key);\n if (!queue || queue.length === 0) return;\n\n const toProcess = queue.splice(0, this.maxRequests);\n this.activeCounts.set(key, toProcess.length);\n\n // Restart timer for the next window\n this.timers.set(key, setTimeout(() => {\n this.activeCounts.set(key, 0);\n this.timers.delete(key);\n this.drainQueue(key);\n }, this.interval));\n\n for (const item of toProcess) {\n item.execute();\n }\n }\n\n /**\n * Clear all queues, timers, and active counts.\n */\n clear(): void {\n for (const timer of this.timers.values()) {\n clearTimeout(timer);\n }\n this.queues.clear();\n this.activeCounts.clear();\n this.timers.clear();\n }\n\n /**\n * Get the number of queued (waiting) requests for a given key.\n */\n getQueueSize(key: string): number {\n return this.queues.get(key)?.length || 0;\n }\n}\n","/**\n * httix — Koa-style middleware composition\n */\n\nimport type { HttixRequestConfig, HttixResponse, MiddlewareContext, MiddlewareFn } from '../core/types';\n\n/**\n * Compose an array of middleware functions into a single function.\n *\n * The composition follows the Koa \"onion\" model: each middleware is called\n * with a context and a `next` function that invokes the next middleware in\n * the chain. Code before `await next()` runs on the way in; code after\n * `await next()` runs on the way out (in reverse order).\n *\n * If no middlewares are provided, the composed function simply calls `next`.\n *\n * @throws {Error} If `next()` is called more than once in a single middleware.\n */\nexport function composeMiddleware<T>(\n middlewares: MiddlewareFn<T>[],\n): (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void> {\n return function composed(ctx, next) {\n let index = -1;\n\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n const fn = middlewares[i];\n if (!fn) {\n return next();\n }\n\n await fn(ctx as MiddlewareContext<HttixRequestConfig, HttixResponse<T>>, () => dispatch(i + 1));\n }\n\n return dispatch(0);\n };\n}\n","/**\n * httix — Authentication utilities\n */\n\nimport type {\n AuthConfig,\n BearerAuthConfig,\n HttixRequestConfig,\n RequestInterceptor,\n ResponseErrorInterceptor,\n} from '../core/types';\nimport type { HttixError } from '../core/errors';\nimport { HttixResponseError as HttixResponseErrorCls } from '../core/errors';\n\n/**\n * Resolve an auth value that may be a static value or an async resolver function.\n */\nasync function resolveValue(value: string | (() => string | Promise<string>)): Promise<string> {\n return typeof value === 'function' ? value() : value;\n}\n\n/**\n * Deep-clone a request config so mutations don't affect the original.\n */\nfunction cloneConfig(config: HttixRequestConfig): HttixRequestConfig {\n return { ...config };\n}\n\n/**\n * Apply authentication headers or query parameters to a request config\n * based on the provided auth configuration.\n *\n * Returns a new config object — the original is not mutated.\n */\nexport async function applyAuth(\n config: HttixRequestConfig,\n authConfig: AuthConfig,\n): Promise<HttixRequestConfig> {\n const result = cloneConfig(config);\n\n // Ensure headers is a plain object we can mutate\n const headers: Record<string, string> = {};\n if (result.headers) {\n if (result.headers instanceof Headers) {\n result.headers.forEach((value, key) => {\n headers[key] = value;\n });\n } else {\n Object.assign(headers, result.headers);\n }\n }\n result.headers = headers;\n\n // Ensure query is a mutable object\n const query: Record<string, string | number | boolean | null | undefined> = {\n ...(result.query as Record<string, string | number | boolean | null | undefined> | undefined),\n };\n\n switch (authConfig.type) {\n case 'bearer': {\n const token = await resolveValue(authConfig.token);\n headers['Authorization'] = `Bearer ${token}`;\n break;\n }\n\n case 'basic': {\n const credentials = `${authConfig.username}:${authConfig.password}`;\n const encoded = btoa(credentials);\n headers['Authorization'] = `Basic ${encoded}`;\n break;\n }\n\n case 'apiKey': {\n const value = await resolveValue(authConfig.value);\n if (authConfig.in === 'header') {\n headers[authConfig.key] = value;\n } else {\n // 'query'\n query[authConfig.key] = value;\n }\n break;\n }\n }\n\n // Only set query if we actually added something\n if (Object.keys(query).length > Object.keys(result.query ?? {}).length || authConfig.type === 'apiKey' && authConfig.in === 'query') {\n result.query = query;\n }\n\n return result;\n}\n\n/**\n * Create a request interceptor that applies authentication to every\n * outgoing request.\n */\nexport function createAuthInterceptor(authConfig: AuthConfig): RequestInterceptor {\n return async (config: HttixRequestConfig): Promise<HttixRequestConfig> => {\n return applyAuth(config, authConfig);\n };\n}\n\n/**\n * Create a response error interceptor that handles 401 Unauthorized\n * errors by refreshing the bearer token and retrying the original request.\n *\n * If no `refreshToken` is configured, returns a no-op interceptor.\n * Concurrent 401 errors are deduplicated — only one token refresh\n * happens at a time, and other callers wait for the same refresh.\n */\nexport function createAuthRefreshHandler(\n authConfig: BearerAuthConfig,\n): ResponseErrorInterceptor {\n // No-op if no refresh mechanism is configured\n if (!authConfig.refreshToken) {\n return (_error: HttixError): void => {\n // Signal the error is not handled\n };\n }\n\n let refreshPromise: Promise<string> | null = null;\n\n return (async (error: HttixError) => {\n // Only handle 401 errors\n if (!(error instanceof HttixResponseErrorCls) || error.status !== 401) {\n return;\n }\n\n const originalConfig = error.config;\n if (!originalConfig) {\n return;\n }\n\n // Dedup concurrent refreshes\n if (!refreshPromise) {\n refreshPromise = authConfig.refreshToken!().then((newToken) => {\n // Persist the new token if a callback is provided\n if (authConfig.onTokenRefresh) {\n authConfig.onTokenRefresh(newToken);\n }\n // Update the static token so future requests use it\n if (typeof authConfig.token === 'string') {\n (authConfig as { token: string }).token = newToken;\n }\n refreshPromise = null;\n return newToken;\n }).catch((refreshError) => {\n refreshPromise = null;\n throw refreshError;\n });\n }\n\n let newToken: string;\n try {\n newToken = await refreshPromise;\n } catch {\n // Refresh failed — re-throw the original 401 error\n throw error;\n }\n\n // Retry the original request with the new token\n const retryConfig = await applyAuth(originalConfig, authConfig);\n // Override the token with the freshly refreshed one\n const retryHeaders: Record<string, string> = {};\n if (retryConfig.headers) {\n Object.assign(retryHeaders, retryConfig.headers);\n }\n retryHeaders['Authorization'] = `Bearer ${newToken}`;\n retryConfig.headers = retryHeaders;\n\n // We return nothing (error not handled), but the auth token is now refreshed.\n // The caller is expected to retry with the updated config.\n return;\n }) as unknown as ResponseErrorInterceptor;\n}\n","/**\n * httix — Pagination utilities\n */\n\nimport type {\n HttixClient,\n HttixRequestConfig,\n HttixResponse,\n PaginationConfig,\n} from '../core/types';\n\n/**\n * Parse an HTTP Link header into a record of rel → URL mappings.\n *\n * Input format: `<url>; rel=\"next\", <url>; rel=\"last\"`\n *\n * Returns an object like `{ next: 'https://...', last: 'https://...' }`.\n */\nexport function parseLinkHeader(linkHeader: string): Record<string, string> {\n const result: Record<string, string> = {};\n\n if (!linkHeader) return result;\n\n // Split by comma, but be careful with commas inside angle brackets (unlikely but safe)\n const parts = linkHeader.split(',');\n\n for (const part of parts) {\n const trimmed = part.trim();\n\n // Extract URL from angle brackets\n const urlMatch = trimmed.match(/<([^>]+)>/);\n if (!urlMatch) continue;\n\n const url = urlMatch[1];\n /* v8 ignore next */ if (url === undefined) continue;\n\n // Extract rel value\n const relMatch = trimmed.match(/rel\\s*=\\s*\"([^\"]+)\"/);\n if (!relMatch) continue;\n\n const rel = relMatch[1]!;\n result[rel] = url;\n }\n\n return result;\n}\n\n/**\n * Create a paginator function that returns an async iterable of pages.\n *\n * Supports three pagination styles:\n * - **offset**: Tracks offset and incrementing by pageSize each iteration.\n * - **cursor**: Extracts a cursor from the response data and passes it\n * as a query parameter for the next request.\n * - **link**: Extracts the next URL from the Link response header.\n *\n * The iterable respects `maxPages`, `stopCondition`, and `dataExtractor`\n * from the PaginationConfig.\n */\nexport function createPaginator<T>(\n client: HttixClient,\n): (\n url: string,\n config?: Partial<HttixRequestConfig> & { pagination?: PaginationConfig<T> },\n) => AsyncIterable<T[]> {\n return async function* paginate(\n url: string,\n config?: Partial<HttixRequestConfig> & { pagination?: PaginationConfig<T> },\n ) {\n const pagination = config?.pagination;\n if (!pagination) {\n return;\n }\n\n const {\n style,\n pageSize = 20,\n maxPages = Infinity,\n offsetParam = 'offset',\n limitParam = 'limit',\n cursorParam = 'cursor',\n cursorExtractor,\n linkExtractor,\n dataExtractor,\n stopCondition,\n } = pagination;\n\n let currentUrl: string | null = url;\n let offset = 0;\n let cursor: string | null | undefined;\n let pageCount = 0;\n\n while (currentUrl && pageCount < maxPages) {\n // Build request config for this page\n const requestConfig: Partial<HttixRequestConfig> = { ...config };\n\n if (style === 'offset') {\n requestConfig.query = {\n ...requestConfig.query,\n [offsetParam]: offset,\n [limitParam]: pageSize,\n } as Record<string, string | number | boolean | null | undefined>;\n } else if (style === 'cursor') {\n requestConfig.query = {\n ...requestConfig.query,\n [cursorParam]: cursor,\n } as Record<string, string | number | boolean | null | undefined>;\n }\n\n let response: HttixResponse<T>;\n\n if (style === 'link' && pageCount > 0) {\n // For link style after the first page, use the URL from the Link header\n response = await client.request<T>({\n url: currentUrl,\n ...requestConfig,\n } as HttixRequestConfig);\n } else {\n response = await client.request<T>({\n url: currentUrl,\n ...requestConfig,\n } as HttixRequestConfig);\n }\n\n pageCount++;\n\n // Extract the page data\n let pageData: T[];\n\n if (dataExtractor) {\n pageData = dataExtractor(response.data);\n } else {\n // Default: assume response.data is the array\n pageData = (response.data ?? []) as T[];\n }\n\n // Check stop condition (on raw data, not extracted array)\n if (stopCondition && stopCondition(response.data)) {\n if (pageData.length > 0) {\n yield pageData;\n }\n return;\n }\n\n // If no data, stop paginating\n if (pageData.length === 0) {\n return;\n }\n\n yield pageData;\n\n // Determine the next page\n switch (style) {\n case 'offset': {\n // If we got fewer items than pageSize, there are no more pages\n if (pageData.length < pageSize) {\n return;\n }\n offset += pageSize;\n break;\n }\n\n case 'cursor': {\n if (cursorExtractor) {\n cursor = cursorExtractor(response.data);\n } else {\n // Default: try to extract from data if it looks like it has a cursor\n cursor = null;\n }\n if (!cursor) {\n return;\n }\n break;\n }\n\n case 'link': {\n if (linkExtractor) {\n currentUrl = linkExtractor(response.headers) ?? null;\n } else {\n // Default: parse the Link header\n const linkHeader = response.headers.get('link');\n if (linkHeader) {\n const links = parseLinkHeader(linkHeader);\n currentUrl = links['next'] ?? null;\n } else {\n currentUrl = null;\n }\n }\n break;\n }\n }\n }\n };\n}\n","/**\n * httix — Streaming utilities (SSE, NDJSON, progress tracking)\n */\n\nimport type { DownloadProgress, SSEEvent } from '../core/types';\n\n/**\n * Parse a ReadableStream of bytes as Server-Sent Events (SSE).\n *\n * Returns an async iterable that yields SSEEvent objects. Handles\n * partial chunks, multi-line data fields, and the standard SSE fields\n * (event, data, id, retry).\n *\n * The stream reader is released when the iterator is broken or returns.\n */\nexport async function* parseSSE(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<SSEEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const parts = buffer.split('\\n\\n');\n // Keep the last (potentially incomplete) part in the buffer\n buffer = parts.pop()!;\n\n for (const part of parts) {\n const event = parseSSEEvent(part);\n if (event !== null) {\n yield event;\n }\n }\n }\n\n // Process any remaining data in the buffer\n if (buffer.trim().length > 0) {\n const event = parseSSEEvent(buffer);\n if (event !== null) {\n yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Parse a single SSE event block into an SSEEvent object.\n * Returns null for empty blocks or comments.\n */\nfunction parseSSEEvent(block: string): SSEEvent | null {\n const lines = block.split('\\n');\n const fields: Partial<SSEEvent> = {};\n\n const dataLines: string[] = [];\n\n for (const line of lines) {\n // Skip empty lines and comments (lines starting with ':')\n if (line === '' || line.startsWith(':')) continue;\n\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n // Field with no value\n const field = line.trim();\n if (field === 'data') {\n dataLines.push('');\n }\n continue;\n }\n\n const field = line.slice(0, colonIndex).trim();\n let value = line.slice(colonIndex + 1);\n\n // Remove leading space from value per SSE spec\n if (value.startsWith(' ')) {\n value = value.slice(1);\n }\n\n switch (field) {\n case 'event':\n fields.type = value;\n break;\n case 'data':\n dataLines.push(value);\n break;\n case 'id':\n fields.id = value;\n break;\n case 'retry':\n fields.retry = parseInt(value, 10);\n break;\n // Ignore unknown fields\n }\n }\n\n // If there are no data lines, this is not a valid event\n if (dataLines.length === 0) return null;\n\n return {\n type: fields.type ?? 'message',\n data: dataLines.join('\\n'),\n id: fields.id,\n retry: fields.retry,\n };\n}\n\n/**\n * Parse a ReadableStream of bytes as Newline-Delimited JSON (NDJSON).\n *\n * Returns an async iterable that yields parsed JSON objects of type T.\n * Empty lines are skipped. Partial lines are buffered until a newline\n * arrives.\n *\n * The stream reader is released when the iterator is broken or returns.\n */\nexport async function* parseNDJSON<T>(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<T> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n // Keep the last (potentially incomplete) line in the buffer\n buffer = lines.pop()!;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n yield JSON.parse(trimmed) as T;\n }\n }\n\n // Process any remaining data in the buffer\n const remaining = buffer.trim();\n if (remaining.length > 0) {\n yield JSON.parse(remaining) as T;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Create a progress-tracking wrapper around a ReadableStream.\n *\n * Returns a new ReadableStream that transparently passes through all\n * chunks while invoking `onProgress` for each chunk received, reporting\n * the number of bytes loaded so far.\n *\n * If `total` is provided (e.g., from Content-Length), `percent` will\n * reflect completion percentage; otherwise it defaults to 0.\n */\nexport function createProgressReader(\n body: ReadableStream<Uint8Array>,\n onProgress: (progress: DownloadProgress) => void,\n total?: number,\n): ReadableStream<Uint8Array> {\n let loaded = 0;\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const reader = body.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n\n loaded += value.byteLength;\n\n const percent = total !== undefined && total > 0\n ? Math.round((loaded / total) * 100)\n : 0;\n\n onProgress({\n loaded,\n total: total !== undefined ? total : undefined,\n percent,\n });\n\n controller.enqueue(value);\n }\n } catch (err) {\n controller.error(err);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n","/**\n * httix — Header manipulation utilities\n */\n\nimport type { HttixHeaders } from '../core/types';\n\n/**\n * Merge default headers with custom headers.\n * Custom headers take precedence over defaults.\n */\nexport function mergeHeaders(\n defaults: HttixHeaders | undefined,\n custom: HttixHeaders | undefined,\n): Headers {\n const merged = new Headers();\n\n if (defaults) {\n addHeadersToInstance(merged, defaults);\n }\n\n if (custom) {\n addHeadersToInstance(merged, custom);\n }\n\n return merged;\n}\n\n/**\n * Capitalize the first letter of each word in a header name.\n * e.g. 'content-type' → 'Content-Type'\n */\nexport function normalizeHeaderName(name: string): string {\n return name\n .split('-')\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase())\n .join('-');\n}\n\n/**\n * Get the Content-Type header from a Headers object (case-insensitive).\n * Returns the value in lowercase, or null if not present.\n */\nexport function getContentType(headers: Headers): string | null {\n const value = headers.get('content-type');\n return value !== null ? value.toLowerCase() : null;\n}\n\n/**\n * Check if the given content type indicates JSON.\n */\nexport function isJSONContentType(contentType: string | null): boolean {\n if (contentType === null) {\n return false;\n }\n return contentType.includes('application/json');\n}\n\n/**\n * Check if the given content type indicates text or XML.\n */\nexport function isTextContentType(contentType: string | null): boolean {\n if (contentType === null) {\n return false;\n }\n return contentType.includes('text/') || contentType.includes('application/xml');\n}\n\n/**\n * Convert HttixHeaders (Record<string, string> or Headers) to a new Headers instance.\n */\nexport function parseHeaders(headersInit: HttixHeaders): Headers {\n const headers = new Headers();\n addHeadersToInstance(headers, headersInit);\n return headers;\n}\n\n/**\n * Internal helper: add entries from an HttixHeaders source into a Headers instance.\n */\nfunction addHeadersToInstance(target: Headers, source: HttixHeaders): void {\n if (source instanceof Headers) {\n source.forEach((value, key) => {\n target.set(key, value);\n });\n } else {\n for (const [key, value] of Object.entries(source)) {\n target.set(key, value);\n }\n }\n}\n","/**\n * httix — Configuration merging utilities\n */\n\nimport type { HttixRequestConfig, QueryParams } from '../core/types';\nimport { mergeHeaders } from './headers';\n\n/**\n * Deep-merge two partial request configs.\n *\n * Rules:\n * - Headers → mergeHeaders (custom overrides defaults)\n * - Query → mergeQueryParams (source overrides target)\n * - Primitive values (string, number, boolean) → source takes precedence\n * - Plain objects → deep merge recursively\n * - Arrays → source replaces target entirely\n * - Neither input is mutated.\n */\nexport function deepMergeConfig(\n target: Partial<HttixRequestConfig>,\n source: Partial<HttixRequestConfig>,\n): Partial<HttixRequestConfig> {\n const result: Partial<HttixRequestConfig> = { ...target };\n\n for (const key of Object.keys(source) as Array<keyof Partial<HttixRequestConfig>>) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n // Headers — use the dedicated merge function\n if (key === 'headers') {\n result.headers = mergeHeaders(\n targetVal as Partial<HttixRequestConfig>['headers'] | undefined,\n sourceVal as Partial<HttixRequestConfig>['headers'] | undefined,\n );\n continue;\n }\n\n // Query — merge query param objects\n if (key === 'query') {\n result.query = mergeQueryParams(\n targetVal as QueryParams | undefined,\n sourceVal as QueryParams | undefined,\n );\n continue;\n }\n\n // Skip undefined source values\n if (sourceVal === undefined) {\n continue;\n }\n\n // Arrays — source replaces target entirely\n if (Array.isArray(sourceVal)) {\n (result as Record<string, unknown>)[key as string] = sourceVal;\n continue;\n }\n\n // If both target and source are plain objects, deep merge\n if (\n sourceVal !== null &&\n targetVal !== null &&\n typeof sourceVal === 'object' &&\n typeof targetVal === 'object' &&\n !Array.isArray(sourceVal) &&\n !Array.isArray(targetVal)\n ) {\n (result as Record<string, unknown>)[key as string] = deepMergePlainObjects(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n );\n continue;\n }\n\n // Primitive values and everything else — source wins\n (result as Record<string, unknown>)[key as string] = sourceVal;\n }\n\n return result;\n}\n\n/**\n * Merge two query-params objects. Source values override target values.\n */\nexport function mergeQueryParams(\n target: QueryParams | undefined,\n source: QueryParams | undefined,\n): QueryParams {\n if (!target && !source) {\n return {};\n }\n if (!target) {\n return { ...source! };\n }\n if (!source) {\n return { ...target };\n }\n return { ...target, ...source };\n}\n\n/**\n * Recursively deep-merge two plain objects (no special cases for headers/query).\n */\nfunction deepMergePlainObjects(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n\n for (const key of Object.keys(source)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (sourceVal === undefined) {\n continue;\n }\n\n // Arrays — source replaces target\n if (Array.isArray(sourceVal)) {\n result[key] = sourceVal;\n continue;\n }\n\n // Both plain objects — recurse\n if (\n sourceVal !== null &&\n targetVal !== null &&\n typeof sourceVal === 'object' &&\n typeof targetVal === 'object' &&\n !Array.isArray(sourceVal) &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMergePlainObjects(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n );\n continue;\n }\n\n // Primitives and everything else — source wins\n result[key] = sourceVal;\n }\n\n return result;\n}\n","/**\n * httix-http — Main HTTP client implementation\n *\n * The HttixClientImpl class is the heart of the library. It orchestrates\n * configuration merging, middleware, interceptors, authentication,\n * deduplication, rate limiting, retries, timeouts, streaming, and\n * pagination into a single cohesive request pipeline.\n */\n\nimport type {\n HttixClient as HttixClientInterface,\n HttixConfig,\n HttixRequestConfig,\n HttixResponse,\n RequestBody,\n MiddlewareFn,\n MiddlewareContext,\n SSEEvent,\n AuthConfig,\n DedupConfig,\n RequestInterceptor,\n RequestErrorInterceptor,\n ResponseInterceptor,\n ResponseErrorInterceptor,\n InterceptorManager as InterceptorManagerInterface,\n} from './types';\nimport { DEFAULT_CONFIG } from './defaults';\nimport {\n HttixRequestError,\n HttixResponseError,\n HttixTimeoutError,\n HttixAbortError,\n} from './errors';\nimport { buildRequest, clearTimeoutSignal } from './request';\nimport { createResponse, parseResponseBody } from './response';\nimport { InterceptorManager } from '../features/interceptors';\nimport {\n runRequestInterceptors,\n runResponseInterceptors,\n runResponseErrorInterceptors,\n} from '../features/interceptors';\nimport { retryRequest } from '../features/retry';\nimport { RequestDeduplicator } from '../features/dedup';\nimport { RateLimiter } from '../features/rateLimit';\nimport { composeMiddleware } from '../features/middleware';\nimport {\n applyAuth,\n createAuthInterceptor,\n createAuthRefreshHandler,\n} from '../features/auth';\nimport { createPaginator } from '../features/pagination';\nimport { parseSSE, parseNDJSON } from '../features/streaming';\nimport { deepMergeConfig } from '../utils/merge';\nimport { generateRequestId } from '../utils/helpers';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Combine multiple AbortSignals into one that aborts when any source aborts.\n */\nfunction combineSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n break;\n }\n signal.addEventListener(\n 'abort',\n () => controller.abort(signal.reason),\n { once: true },\n );\n }\n\n return controller.signal;\n}\n\n// ---------------------------------------------------------------------------\n// HttixClientImpl\n// ---------------------------------------------------------------------------\n\nexport class HttixClientImpl implements HttixClientInterface {\n /** Merged default configuration for this client instance. */\n readonly defaults: HttixConfig;\n\n /** Interceptor managers for request and response pipelines. */\n readonly interceptors: {\n request: InterceptorManager<RequestInterceptor, RequestErrorInterceptor>;\n response: InterceptorManager<ResponseInterceptor<unknown>, ResponseErrorInterceptor>;\n };\n\n /** Stream utilities bound to this client. */\n readonly stream: {\n sse: (url: string, config?: Partial<HttixRequestConfig>) => AsyncIterable<SSEEvent>;\n ndjson: <T = unknown>(url: string, config?: Partial<HttixRequestConfig>) => AsyncIterable<T>;\n };\n\n /** Pagination helper bound to this client. */\n readonly paginate: HttixClientInterface['paginate'];\n\n // -- Private state --------------------------------------------------------\n\n private middlewares: MiddlewareFn[];\n private deduplicator?: RequestDeduplicator;\n private dedupConfig?: boolean | DedupConfig;\n private rateLimiter?: RateLimiter;\n private authConfig?: AuthConfig;\n private pendingControllers: Set<AbortController>;\n\n constructor(config?: Partial<HttixConfig>) {\n // 1. Deep-merge user config with library defaults\n this.defaults = deepMergeConfig(\n DEFAULT_CONFIG,\n config ?? {},\n ) as HttixConfig;\n\n // 2. Interceptor managers\n this.interceptors = {\n request: new InterceptorManager<RequestInterceptor, RequestErrorInterceptor>(),\n response: new InterceptorManager<ResponseInterceptor<unknown>, ResponseErrorInterceptor>(),\n };\n\n // 3. Middleware array (from defaults or empty)\n this.middlewares = this.defaults.middleware\n ? [...this.defaults.middleware]\n : [];\n\n // 4. Deduplication\n this.dedupConfig = this.defaults.dedup;\n if (this.dedupConfig === true || (typeof this.dedupConfig === 'object' && this.dedupConfig.enabled)) {\n const ttl =\n typeof this.dedupConfig === 'object' && this.dedupConfig.ttl !== undefined\n ? this.dedupConfig.ttl\n : 0;\n this.deduplicator = new RequestDeduplicator(ttl);\n }\n\n // 5. Rate limiting\n if (this.defaults.rateLimit) {\n this.rateLimiter = new RateLimiter(\n this.defaults.rateLimit.maxRequests,\n this.defaults.rateLimit.interval,\n );\n }\n\n // 6. Authentication\n this.authConfig = this.defaults.auth;\n if (this.authConfig) {\n // Register a request interceptor that applies auth to every request\n this.interceptors.request.use(createAuthInterceptor(this.authConfig));\n\n // If bearer auth with refresh, register a response-error interceptor\n if (\n this.authConfig.type === 'bearer' &&\n this.authConfig.refreshToken\n ) {\n this.interceptors.response.use(\n ((res: HttixResponse<unknown>) => res) as ResponseInterceptor<unknown>,\n createAuthRefreshHandler(this.authConfig),\n );\n }\n }\n\n // 7. Pending abort controllers for cancelAll()\n this.pendingControllers = new Set();\n\n // 8. Stream helpers (bound methods)\n this.stream = {\n sse: this.executeSSE.bind(this),\n ndjson: this.executeNDJSON.bind(this),\n };\n\n // 9. Pagination helper\n this.paginate = createPaginator(this) as HttixClientInterface['paginate'];\n }\n\n // =========================================================================\n // Core request method\n // =========================================================================\n\n async request<T = unknown>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n // 1. Deep-merge per-request config with client defaults\n const mergedConfig = deepMergeConfig(\n this.defaults,\n config,\n ) as HttixRequestConfig;\n\n // 2. Assign (or preserve) a request ID for tracing\n mergedConfig.requestId = config.requestId ?? generateRequestId();\n\n // 3. Set up cancellation tracking for this request\n const cancelController = new AbortController();\n this.pendingControllers.add(cancelController);\n\n const signals: AbortSignal[] = [cancelController.signal];\n if (mergedConfig.signal) {\n signals.unshift(mergedConfig.signal);\n }\n const combinedSignal = combineSignals(...signals);\n mergedConfig.signal = combinedSignal;\n\n try {\n // 4. Execute the request lifecycle wrapped in middleware\n const context: MiddlewareContext<HttixRequestConfig, HttixResponse<T>> = {\n request: mergedConfig,\n };\n\n let httixResponse!: HttixResponse<T>;\n\n const composed = composeMiddleware(this.middlewares);\n\n await composed(context, async () => {\n // ---- Handler: everything inside middleware's \"next()\" ----\n\n // a. Run request interceptors\n let processedConfig = await runRequestInterceptors(\n context.request,\n this.interceptors.request,\n );\n // Keep context in sync so post-middleware code sees the final config\n context.request = processedConfig;\n\n // b. Auth is handled via interceptors (registered in constructor),\n // but we also support calling applyAuth here for edge cases where\n // a per-request auth override is needed. In normal usage the\n // interceptor already applied auth, so this is a no-op.\n\n // c. Execute with deduplication and rate limiting\n httixResponse = await this.executeWithDedupAndRateLimit<T>(\n processedConfig,\n );\n\n // d. Store response on context for middleware post-processing\n context.response = httixResponse;\n });\n\n return httixResponse;\n } finally {\n this.pendingControllers.delete(cancelController);\n }\n }\n\n // =========================================================================\n // HTTP method shortcuts\n // =========================================================================\n\n async get<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'GET' });\n }\n\n async post<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'POST', body });\n }\n\n async put<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'PUT', body });\n }\n\n async patch<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'PATCH', body });\n }\n\n async delete<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'DELETE' });\n }\n\n async head(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return this.request<void>({ ...config, url, method: 'HEAD' });\n }\n\n async options(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return this.request<void>({ ...config, url, method: 'OPTIONS' });\n }\n\n // =========================================================================\n // Middleware registration\n // =========================================================================\n\n use<T = unknown>(middleware: MiddlewareFn<T>): void {\n this.middlewares.push(middleware as MiddlewareFn);\n }\n\n // =========================================================================\n // Client factory — clone with overrides\n // =========================================================================\n\n create(overrides?: Partial<HttixConfig>): HttixClientInterface {\n const mergedDefaults = deepMergeConfig(\n this.defaults,\n overrides ?? {},\n ) as HttixConfig;\n return new HttixClientImpl(mergedDefaults);\n }\n\n // =========================================================================\n // Cancellation\n // =========================================================================\n\n /**\n * Abort every in-flight request managed by this client.\n */\n cancelAll(reason = 'All requests cancelled'): void {\n for (const controller of this.pendingControllers) {\n controller.abort(new HttixAbortError(reason));\n }\n this.pendingControllers.clear();\n }\n\n /**\n * Check whether an error is a cancellation (abort) error.\n */\n isCancel(error: unknown): error is HttixAbortError {\n return error instanceof HttixAbortError;\n }\n\n // =========================================================================\n // Private — dedup & rate-limit wrapper\n // =========================================================================\n\n /**\n * Wraps the actual fetch in deduplication and rate-limiting layers.\n */\n private async executeWithDedupAndRateLimit<T>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n const doRequest = (): Promise<HttixResponse<T>> =>\n this.doFetch<T>(config);\n\n // Rate limiting\n const throttledRequest = this.rateLimiter\n ? (): Promise<HttixResponse<T>> =>\n this.rateLimiter!.throttle(config.url, doRequest) as Promise<\n HttixResponse<T>\n >\n : doRequest;\n\n // Deduplication\n if (this.deduplicator && this.isDedupEnabled()) {\n const key = this.generateDedupKey(config);\n return this.deduplicator.dedup<HttixResponse<T>>(key, throttledRequest);\n }\n\n return throttledRequest();\n }\n\n private isDedupEnabled(): boolean {\n if (this.dedupConfig === false || this.dedupConfig === undefined) {\n return false;\n }\n if (this.dedupConfig === true) {\n return true;\n }\n return this.dedupConfig.enabled;\n }\n\n private generateDedupKey(config: HttixRequestConfig): string {\n if (\n typeof this.dedupConfig === 'object' &&\n this.dedupConfig.generateKey\n ) {\n return this.dedupConfig.generateKey(config);\n }\n return this.deduplicator!.generateKey(config);\n }\n\n // =========================================================================\n // Private — core fetch with retry, response processing & error handling\n // =========================================================================\n\n /**\n * Build the native Request, execute fetch with retry support, parse the\n * response body, and handle success / error paths.\n */\n private async doFetch<T>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n // retryRequest handles the retry loop. The inner fn is called per-attempt\n // so that a fresh Request is built each time (body streams can only be\n // consumed once).\n return retryRequest<T>(\n async (): Promise<HttixResponse<T>> => {\n // Build the native Request (includes timeout setup)\n const {\n request: fetchRequest,\n timeoutController,\n timeoutId,\n } = buildRequest(config);\n\n const startTime = Date.now();\n\n let rawResponse: Response;\n\n try {\n rawResponse = await fetch(fetchRequest);\n } catch (error) {\n // Distinguish timeout from user-initiated abort from network errors.\n // Check user signal first (user cancel takes priority).\n const isUserAbort = config.signal?.aborted === true;\n const isTimeout =\n timeoutController?.signal?.aborted === true && !isUserAbort;\n\n // Always clean up the timeout timer\n clearTimeoutSignal(timeoutController, timeoutId);\n\n if (isUserAbort) {\n throw new HttixAbortError('Request was aborted', config);\n }\n\n if (isTimeout) {\n /* v8 ignore next */\n throw new HttixTimeoutError(config.timeout ?? 0, config);\n }\n\n // Network / CORS / DNS error\n throw new HttixRequestError(\n error instanceof Error ? error.message : 'Network request failed',\n {\n message: 'Network request failed',\n config,\n cause: error instanceof Error ? error : undefined,\n },\n );\n }\n\n // Request succeeded at the transport level — clean up timeout\n clearTimeoutSignal(timeoutController, timeoutId);\n\n // Parse response body\n const data = await parseResponseBody<T>(rawResponse, config);\n const timing = Date.now() - startTime;\n\n return createResponse<T>(rawResponse, config, data, timing);\n },\n config.retry,\n config,\n ).then((response) => this.processResponse<T>(response, config));\n }\n\n /**\n * Post-retry response processing:\n * - 2xx → run response interceptors\n * - non-2xx + throwOnError → run error interceptors, then throw\n * - non-2xx + !throwOnError → return as-is\n */\n private async processResponse<T>(\n response: HttixResponse<T>,\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n // ---------- 2xx success ----------\n if (response.ok) {\n return runResponseInterceptors<T>(\n response,\n this.interceptors.response as unknown as InterceptorManagerInterface<\n ResponseInterceptor<T>,\n ResponseErrorInterceptor\n >,\n );\n }\n\n // ---------- non-2xx ----------\n // If throwOnError is explicitly false, return the response as-is.\n if (config.throwOnError === false) {\n return response;\n }\n\n // Default: throw on non-2xx\n const error = new HttixResponseError(\n response.status,\n response.statusText,\n response.data,\n response.headers,\n config,\n );\n\n // Give response-error interceptors a chance to recover\n try {\n const recovered = await runResponseErrorInterceptors(\n error,\n this.interceptors.response,\n );\n return recovered as HttixResponse<T>;\n } catch {\n // No interceptor recovered the error — re-throw the original\n throw error;\n }\n }\n\n // =========================================================================\n // Private — stream helpers\n // =========================================================================\n\n /**\n * Execute an SSE stream request.\n *\n * Applies interceptors and auth, then returns an async iterable of\n * SSEEvent objects by piping the response body through parseSSE().\n */\n private async *executeSSE(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): AsyncGenerator<SSEEvent, void, undefined> {\n const mergedConfig = deepMergeConfig(this.defaults, {\n ...config,\n url,\n method: 'GET',\n }) as HttixRequestConfig;\n\n let processedConfig = await runRequestInterceptors(\n mergedConfig,\n this.interceptors.request,\n );\n\n if (this.authConfig) {\n processedConfig = await applyAuth(processedConfig, this.authConfig);\n }\n\n const { request: fetchRequest, timeoutController, timeoutId } =\n buildRequest(processedConfig);\n\n // SSE connections are long-lived; use a generous timeout or respect the\n // caller's explicit timeout. Disable default timeout for SSE if not set.\n if (processedConfig.timeout === this.defaults.timeout && processedConfig.timeout !== 0) {\n // Keep the SSE connection open — don't impose a short timeout\n }\n\n try {\n const rawResponse = await fetch(fetchRequest);\n\n clearTimeoutSignal(timeoutController, timeoutId);\n\n if (!rawResponse.ok) {\n const error = new HttixResponseError(\n rawResponse.status,\n rawResponse.statusText,\n null,\n rawResponse.headers,\n processedConfig,\n );\n throw error;\n }\n\n if (!rawResponse.body) {\n throw new HttixRequestError('Response body is null — cannot parse SSE stream', {\n message: 'Response body is null',\n config: processedConfig,\n });\n }\n\n yield* parseSSE(rawResponse.body);\n } catch (error) {\n clearTimeoutSignal(timeoutController, timeoutId);\n throw error;\n }\n }\n\n /**\n * Execute an NDJSON stream request.\n *\n * Applies interceptors and auth, then returns an async iterable of parsed\n * JSON objects by piping the response body through parseNDJSON().\n */\n private async *executeNDJSON<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): AsyncGenerator<T, void, undefined> {\n const mergedConfig = deepMergeConfig(this.defaults, {\n ...config,\n url,\n method: 'GET',\n }) as HttixRequestConfig;\n\n let processedConfig = await runRequestInterceptors(\n mergedConfig,\n this.interceptors.request,\n );\n\n if (this.authConfig) {\n processedConfig = await applyAuth(processedConfig, this.authConfig);\n }\n\n const { request: fetchRequest, timeoutController, timeoutId } =\n buildRequest(processedConfig);\n\n try {\n const rawResponse = await fetch(fetchRequest);\n\n clearTimeoutSignal(timeoutController, timeoutId);\n\n if (!rawResponse.ok) {\n const error = new HttixResponseError(\n rawResponse.status,\n rawResponse.statusText,\n null,\n rawResponse.headers,\n processedConfig,\n );\n throw error;\n }\n\n if (!rawResponse.body) {\n throw new HttixRequestError(\n 'Response body is null — cannot parse NDJSON stream',\n {\n message: 'Response body is null',\n config: processedConfig,\n },\n );\n }\n\n yield* parseNDJSON<T>(rawResponse.body);\n } catch (error) {\n clearTimeoutSignal(timeoutController, timeoutId);\n throw error;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory function\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new HttixClient with the given configuration.\n *\n * This is the recommended entry-point for creating client instances.\n *\n * @example\n * ```ts\n * import { createHttix } from 'httix';\n *\n * const client = createHttix({\n * baseURL: 'https://api.example.com',\n * headers: { 'X-App-Version': '1.0' },\n * auth: { type: 'bearer', token: 'my-token' },\n * });\n *\n * const { data } = await client.get('/users');\n * ```\n */\nexport function createHttix(\n config?: Partial<HttixConfig>,\n): HttixClientInterface {\n return new HttixClientImpl(config);\n}\n","/**\n * httix — Cancellation / abort utilities\n */\n\nimport type { HttixRequestConfig } from '../core/types';\nimport { HttixAbortError } from '../core/errors';\n\n/**\n * A cancellation token wraps an AbortController, exposing its signal and\n * a promise that rejects when the token is cancelled.\n */\nexport interface CancelToken {\n signal: AbortSignal;\n promise: Promise<never>;\n}\n\n/**\n * Create a new cancel token and its associated cancel function.\n *\n * The returned `cancel` function triggers the underlying AbortController,\n * causing the `signal` to abort and the `promise` to reject.\n */\nexport function createCancelToken(): { token: CancelToken; cancel: (reason?: string) => void } {\n const controller = new AbortController();\n\n let rejectFn: (reason: unknown) => void;\n const promise = new Promise<never>((_, reject) => {\n rejectFn = reject;\n });\n\n const token: CancelToken = {\n signal: controller.signal,\n promise,\n };\n\n const cancel = (reason?: string): void => {\n const error = new HttixAbortError(reason);\n controller.abort(error);\n rejectFn!(error);\n };\n\n return { token, cancel };\n}\n\n/**\n * Check whether an error is a cancellation (abort) error.\n */\nexport function isCancel(error: unknown): boolean {\n return error instanceof HttixAbortError;\n}\n\n/**\n * Create a new HttixAbortError, typically used when a request is\n * cancelled programmatically.\n */\nexport function createCancelError(reason?: string, config?: HttixRequestConfig): HttixAbortError {\n return new HttixAbortError(reason, config);\n}\n","/**\n * httix — Timeout management via AbortController\n */\n\nimport type { HttixRequestConfig } from '../core/types';\nimport { HttixTimeoutError } from '../core/errors';\n\n/**\n * WeakMap that associates an AbortController with its timeout timer ID,\n * allowing the timer to be cleared later without leaking memory.\n */\nexport const timeoutTimers = new WeakMap<AbortController, ReturnType<typeof setTimeout>>();\n\n/**\n * Create an AbortController that will automatically abort after the\n * specified timeout. The abort reason is set to a HttixTimeoutError.\n *\n * If timeout is 0 or negative, the controller will never abort.\n */\nexport function createTimeoutController(\n timeout: number,\n config: HttixRequestConfig,\n): AbortController {\n const controller = new AbortController();\n\n if (timeout <= 0) {\n // No timeout — controller will never abort\n return controller;\n }\n\n const timerId = setTimeout(() => {\n const error = new HttixTimeoutError(timeout, config);\n controller.abort(error);\n }, timeout);\n\n timeoutTimers.set(controller, timerId);\n\n return controller;\n}\n\n/**\n * Clear a pending timeout timer on an AbortController, preventing it from\n * firing if the request completes before the timeout.\n */\nexport function clearTimeoutController(controller: AbortController): void {\n const timerId = timeoutTimers.get(controller);\n if (timerId !== undefined) {\n clearTimeout(timerId);\n timeoutTimers.delete(controller);\n }\n}\n","/**\n * httix — GET method factory\n *\n * Creates a standalone GET function bound to a client instance.\n * Useful for composition patterns where methods are passed around\n * independently of the client object.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create a GET method bound to the given client.\n *\n * @example\n * ```ts\n * const get = createGetMethod(client);\n * const { data } = await get<User[]>('/users');\n * ```\n */\nexport function createGetMethod(\n client: HttixClient,\n): HttixClient['get'] {\n return async function get<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'GET',\n });\n };\n}\n","/**\n * httix — POST method factory\n *\n * Creates a standalone POST function bound to a client instance.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a POST method bound to the given client.\n *\n * @example\n * ```ts\n * const post = createPostMethod(client);\n * const { data } = await post<User>('/users', { name: 'Alice' });\n * ```\n */\nexport function createPostMethod(\n client: HttixClient,\n): HttixClient['post'] {\n return async function post<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'POST',\n body,\n });\n };\n}\n","/**\n * httix — PUT method factory\n *\n * Creates a standalone PUT function bound to a client instance.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a PUT method bound to the given client.\n *\n * @example\n * ```ts\n * const put = createPutMethod(client);\n * const { data } = await put<User>('/users/1', { name: 'Bob' });\n * ```\n */\nexport function createPutMethod(\n client: HttixClient,\n): HttixClient['put'] {\n return async function put<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'PUT',\n body,\n });\n };\n}\n","/**\n * httix — PATCH method factory\n *\n * Creates a standalone PATCH function bound to a client instance.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a PATCH method bound to the given client.\n *\n * @example\n * ```ts\n * const patch = createPatchMethod(client);\n * const { data } = await patch<User>('/users/1', { name: 'Charlie' });\n * ```\n */\nexport function createPatchMethod(\n client: HttixClient,\n): HttixClient['patch'] {\n return async function patch<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'PATCH',\n body,\n });\n };\n}\n","/**\n * httix — DELETE method factory\n *\n * Creates a standalone DELETE function bound to a client instance.\n * Supports an optional body (some APIs accept request bodies with DELETE).\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a DELETE method bound to the given client.\n *\n * @example\n * ```ts\n * const remove = createDeleteMethod(client);\n * const { data } = await remove<void>('/users/1');\n *\n * // With body (API-specific)\n * const { data } = await remove<void>('/batch', { ids: [1, 2, 3] });\n * ```\n */\nexport function createDeleteMethod(\n client: HttixClient,\n): (\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n) => Promise<HttixResponse<unknown>> {\n return async function remove<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'DELETE',\n ...(body !== undefined ? { body } : {}),\n });\n };\n}\n","/**\n * httix — HEAD method factory\n *\n * Creates a standalone HEAD function bound to a client instance.\n * HEAD requests must not have a body, so only headers and status are returned.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create a HEAD method bound to the given client.\n *\n * The response type is `void` because HEAD responses have no body.\n *\n * @example\n * ```ts\n * const head = createHeadMethod(client);\n * const { status, headers } = await head('/users/1');\n * if (status === 200) {\n * const contentLength = headers.get('content-length');\n * }\n * ```\n */\nexport function createHeadMethod(\n client: HttixClient,\n): HttixClient['head'] {\n return async function head(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return client.request<void>({\n ...config,\n url,\n method: 'HEAD',\n });\n };\n}\n","/**\n * httix — OPTIONS method factory\n *\n * Creates a standalone OPTIONS function bound to a client instance.\n * OPTIONS requests are typically used for CORS preflight or discovering\n * allowed methods on a resource.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create an OPTIONS method bound to the given client.\n *\n * The response type is `void` because OPTIONS responses typically have no body.\n *\n * @example\n * ```ts\n * const options = createOptionsMethod(client);\n * const { headers } = await options('/users/1');\n * const allow = headers.get('allow'); // e.g. \"GET, PUT, DELETE\"\n * ```\n */\nexport function createOptionsMethod(\n client: HttixClient,\n): HttixClient['options'] {\n return async function options(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return client.request<void>({\n ...config,\n url,\n method: 'OPTIONS',\n });\n };\n}\n","/**\n * httix — Generic request method factory\n *\n * Creates a standalone request function bound to a client instance.\n * This is the lowest-level factory — the caller provides the full\n * HttixRequestConfig including method, url, headers, body, etc.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create a generic request method bound to the given client.\n *\n * @example\n * ```ts\n * const request = createRequestMethod(client);\n * const { data } = await request<User>({ url: '/users/1', method: 'GET' });\n * ```\n */\nexport function createRequestMethod(\n client: HttixClient,\n): HttixClient['request'] {\n return async function request<T = unknown>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n return client.request<T>(config);\n };\n}\n"],"mappings":"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","names":["src_exports","__export","DEFAULT_CONFIG","DEFAULT_HEADERS","DEFAULT_REQUEST_CONFIG","DEFAULT_RETRY","DEFAULT_TIMEOUT","HttixAbortError","HttixClientImpl","HttixError","HttixRequestError","HttixResponseError","HttixRetryError","HttixTimeoutError","InterceptorManager","RateLimiter","RequestDeduplicator","applyAuth","clearTimeoutController","composeMiddleware","createAuthInterceptor","createAuthRefreshHandler","createCancelError","createCancelToken","createDeleteMethod","createGetMethod","createHeadMethod","createHttix","createOptionsMethod","createPaginator","createPatchMethod","createPostMethod","createProgressReader","createPutMethod","createRequestMethod","createTimeoutController","src_default","isCancel","parseLinkHeader","parseNDJSON","parseRetryAfter","parseSSE","retryRequest","__toCommonJS","DEFAULT_RETRY","DEFAULT_TIMEOUT","DEFAULT_HEADERS","DEFAULT_REQUEST_CONFIG","DEFAULT_CONFIG","HttixError","message","options","ErrorConstructor","HttixRequestError","HttixResponseError","status","statusText","data","headers","config","HttixTimeoutError","timeout","HttixAbortError","reason","HttixRetryError","attempts","lastError","buildRequest","config","url","buildUrl","headers","mergeHeaders","DEFAULT_HEADERS","body","serializeBody","requestInit","timeout","timeoutController","timeoutId","combineSignals","clearTimeoutSignal","controller","signals","signal","baseURL","params","query","full","base","path","key","value","separator","encodeQueryParams","parts","item","defaults","custom","merged","applyHeaders","target","source","createResponse","raw","config","data","timing","parseResponseBody","response","contentType","parseWithType","autoParse","responseType","lowerCt","text","InterceptorManager","fulfilled","rejected","id","runRequestInterceptors","config","interceptors","currentConfig","handler","err","result","runResponseInterceptors","response","currentResponse","runResponseErrorInterceptors","error","delay","ms","resolve","generateRequestId","calculateDelay","attempt","backoff","baseDelay","maxDelay","jitter","calculated","SAFE_METHODS","parseRetryAfter","value","seconds","date","diff","retryRequest","fn","config","requestConfig","retryCfg","DEFAULT_RETRY","maxAttempts","method","lastError","attempt","response","responseError","HttixResponseError","shouldRetry","retryAfterMs","backoffMs","calculateDelay","finalDelay","delay","err","httixErr","error","HttixRequestError","RequestDeduplicator","ttl","key","requestFn","cached","inflight","promise","result","error","config","url","sortedQuery","k","RateLimiter","maxRequests","interval","key","requestFn","count","resolve","result","queue","toProcess","item","timer","composeMiddleware","middlewares","ctx","next","index","dispatch","fn","resolveValue","value","cloneConfig","config","applyAuth","authConfig","result","headers","key","query","token","credentials","encoded","createAuthInterceptor","createAuthRefreshHandler","_error","refreshPromise","error","HttixResponseError","originalConfig","newToken","refreshError","retryConfig","retryHeaders","parseLinkHeader","linkHeader","result","parts","part","trimmed","urlMatch","url","relMatch","rel","createPaginator","client","config","pagination","style","pageSize","maxPages","offsetParam","limitParam","cursorParam","cursorExtractor","linkExtractor","dataExtractor","stopCondition","currentUrl","offset","cursor","pageCount","requestConfig","response","pageData","parseSSE","stream","reader","decoder","buffer","done","value","parts","part","event","parseSSEEvent","block","lines","fields","dataLines","line","colonIndex","field","parseNDJSON","trimmed","remaining","createProgressReader","body","onProgress","total","loaded","controller","percent","err","mergeHeaders","defaults","custom","merged","addHeadersToInstance","addHeadersToInstance","target","source","value","key","deepMergeConfig","target","source","result","key","sourceVal","targetVal","mergeHeaders","mergeQueryParams","deepMergePlainObjects","combineSignals","signals","controller","signal","HttixClientImpl","_HttixClientImpl","config","deepMergeConfig","DEFAULT_CONFIG","InterceptorManager","ttl","RequestDeduplicator","RateLimiter","createAuthInterceptor","res","createAuthRefreshHandler","createPaginator","mergedConfig","generateRequestId","cancelController","combinedSignal","context","httixResponse","composeMiddleware","processedConfig","runRequestInterceptors","url","body","middleware","overrides","mergedDefaults","reason","HttixAbortError","error","doRequest","throttledRequest","key","retryRequest","fetchRequest","timeoutController","timeoutId","buildRequest","startTime","rawResponse","isUserAbort","isTimeout","clearTimeoutSignal","HttixTimeoutError","HttixRequestError","data","parseResponseBody","timing","createResponse","response","runResponseInterceptors","HttixResponseError","runResponseErrorInterceptors","applyAuth","parseSSE","parseNDJSON","createHttix","createCancelToken","controller","rejectFn","promise","_","reject","reason","error","HttixAbortError","isCancel","createCancelError","config","timeoutTimers","createTimeoutController","timeout","config","controller","timerId","error","HttixTimeoutError","clearTimeoutController","createGetMethod","client","url","config","createPostMethod","client","url","body","config","createPutMethod","client","url","body","config","createPatchMethod","client","url","body","config","createDeleteMethod","client","url","body","config","createHeadMethod","client","url","config","createOptionsMethod","client","url","config","createRequestMethod","client","config","defaultClient","HttixClientImpl","httix","config","isCancel","src_default"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/core/defaults.ts","../../src/core/errors.ts","../../src/core/request.ts","../../src/core/response.ts","../../src/features/interceptors.ts","../../src/utils/helpers.ts","../../src/features/retry.ts","../../src/features/dedup.ts","../../src/features/rateLimit.ts","../../src/features/middleware.ts","../../src/features/auth.ts","../../src/features/pagination.ts","../../src/features/streaming.ts","../../src/utils/headers.ts","../../src/utils/merge.ts","../../src/core/client.ts","../../src/features/abort.ts","../../src/features/timeout.ts","../../src/methods/get.ts","../../src/methods/post.ts","../../src/methods/put.ts","../../src/methods/patch.ts","../../src/methods/delete.ts","../../src/methods/head.ts","../../src/methods/options.ts","../../src/methods/request.ts"],"sourcesContent":["/**\n * httix-http — Main entry point\n *\n * Re-exports every public API surface from the library and creates a\n * pre-configured default client instance for convenience.\n *\n * @example\n * ```ts\n * // 1. Use the default instance directly\n * import httix from 'httix-http';\n * const { data } = await httix.get('/users');\n *\n * // 2. Create a custom instance\n * import { createHttix } from 'httix-http';\n * const api = createHttix({ baseURL: 'https://api.example.com' });\n * const { data } = await api.get('/users');\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\nexport { HttixClientImpl, createHttix } from './core/client';\nexport type { HttixClient as HttixClientInterface } from './core/types';\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport {\n HttixError,\n HttixRequestError,\n HttixResponseError,\n HttixTimeoutError,\n HttixAbortError,\n HttixRetryError,\n} from './core/errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type {\n HttpMethod,\n RequestBody,\n QueryParamValue,\n QueryParams,\n PathParams,\n HttixHeaders,\n BackoffStrategy,\n RetryConfig,\n RateLimitConfig,\n DedupConfig,\n AuthConfig,\n BearerAuthConfig,\n BasicAuthConfig,\n ApiKeyAuthConfig,\n PaginationStyle,\n PaginationConfig,\n DownloadProgress,\n SSEEvent,\n StreamConfig,\n MiddlewareContext,\n MiddlewareFn,\n RequestInterceptor,\n RequestErrorInterceptor,\n ResponseInterceptor,\n ResponseErrorInterceptor,\n InterceptorHandler,\n InterceptorManager as InterceptorManagerInterface,\n HttixConfig,\n HttixRequestConfig,\n HttixResponse,\n HttixPlugin,\n} from './core/types';\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nexport {\n DEFAULT_CONFIG,\n DEFAULT_RETRY,\n DEFAULT_TIMEOUT,\n DEFAULT_HEADERS,\n DEFAULT_REQUEST_CONFIG,\n} from './core/defaults';\n\n// ---------------------------------------------------------------------------\n// Features\n// ---------------------------------------------------------------------------\n\nexport { InterceptorManager } from './features/interceptors';\nexport { createCancelToken, isCancel, createCancelError } from './features/abort';\nexport { RequestDeduplicator } from './features/dedup';\nexport { RateLimiter } from './features/rateLimit';\nexport { composeMiddleware } from './features/middleware';\nexport { parseSSE, parseNDJSON, createProgressReader } from './features/streaming';\nexport { retryRequest, parseRetryAfter } from './features/retry';\nexport { createTimeoutController, clearTimeoutController } from './features/timeout';\nexport { applyAuth, createAuthInterceptor, createAuthRefreshHandler } from './features/auth';\nexport { createPaginator, parseLinkHeader } from './features/pagination';\n\n// ---------------------------------------------------------------------------\n// Method factories\n// ---------------------------------------------------------------------------\n\nexport { createGetMethod } from './methods/get';\nexport { createPostMethod } from './methods/post';\nexport { createPutMethod } from './methods/put';\nexport { createPatchMethod } from './methods/patch';\nexport { createDeleteMethod } from './methods/delete';\nexport { createHeadMethod } from './methods/head';\nexport { createOptionsMethod } from './methods/options';\nexport { createRequestMethod } from './methods/request';\n\n// ---------------------------------------------------------------------------\n// Default instance\n// ---------------------------------------------------------------------------\n\nimport { HttixClientImpl } from './core/client';\nimport { isCancel } from './features/abort';\n\n/**\n * Pre-configured default client instance.\n *\n * All HTTP methods are pre-bound so they can be destructured or passed\n * around without losing the `this` context.\n *\n * @example\n * ```ts\n * import httix from 'httix-http';\n *\n * // Direct usage\n * const { data } = await httix.get('/users');\n *\n * // Destructure for ergonomic usage\n * const { get, post, put, patch, delete: remove } = httix;\n *\n * // Create a derived client with different defaults\n * const adminApi = httix.create({\n * baseURL: 'https://admin.api.example.com',\n * auth: { type: 'bearer', token: adminToken },\n * });\n * ```\n */\nconst defaultClient = new HttixClientImpl();\n\nconst httix = {\n /** Core request method */\n request: defaultClient.request.bind(defaultClient),\n\n /** HTTP method shortcuts */\n get: defaultClient.get.bind(defaultClient),\n post: defaultClient.post.bind(defaultClient),\n put: defaultClient.put.bind(defaultClient),\n patch: defaultClient.patch.bind(defaultClient),\n delete: defaultClient.delete.bind(defaultClient),\n head: defaultClient.head.bind(defaultClient),\n options: defaultClient.options.bind(defaultClient),\n\n /** Interceptor managers */\n interceptors: defaultClient.interceptors,\n\n /** Stream utilities */\n stream: defaultClient.stream,\n\n /** Pagination helper */\n paginate: defaultClient.paginate,\n\n /** Client defaults */\n defaults: defaultClient.defaults,\n\n /** Register middleware */\n use: defaultClient.use.bind(defaultClient),\n\n /** Create a new client with merged configuration */\n create: (config?: Partial<import('./core/types').HttixConfig>) =>\n new HttixClientImpl(config),\n\n /** Cancel all in-flight requests */\n cancelAll: defaultClient.cancelAll.bind(defaultClient),\n\n /** Check whether an error is a cancellation error */\n isCancel,\n\n /**\n * Alias for {@link createHttix} — create a new client instance.\n */\n createHttix: (config?: Partial<import('./core/types').HttixConfig>) =>\n new HttixClientImpl(config),\n};\n\nexport default httix;\n","/**\n * httix — Default configuration values\n */\n\nimport type { HttixConfig, HttixRequestConfig, RetryConfig } from './types';\n\n/** Default retry configuration */\nexport const DEFAULT_RETRY: Required<RetryConfig> = {\n attempts: 3,\n backoff: 'exponential',\n baseDelay: 1000,\n maxDelay: 30000,\n jitter: true,\n retryOn: [408, 429, 500, 502, 503, 504],\n retryOnNetworkError: true,\n retryOnSafeMethodsOnly: false,\n retryCondition: () => true,\n onRetry: () => {},\n};\n\n/** Default timeout in milliseconds */\nexport const DEFAULT_TIMEOUT = 30000;\n\n/** Default headers */\nexport const DEFAULT_HEADERS: Record<string, string> = {\n Accept: 'application/json, text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n 'Accept-Language': '*',\n};\n\n/** Default request configuration */\nexport const DEFAULT_REQUEST_CONFIG: Partial<HttixRequestConfig> = {\n method: 'GET',\n timeout: DEFAULT_TIMEOUT,\n throwOnError: true,\n credentials: 'same-origin',\n mode: 'cors',\n redirect: 'follow',\n cache: 'default',\n};\n\n/** Default client configuration */\nexport const DEFAULT_CONFIG: HttixConfig = {\n url: '',\n baseURL: '',\n headers: DEFAULT_HEADERS,\n timeout: DEFAULT_TIMEOUT,\n throwOnError: true,\n credentials: 'same-origin',\n mode: 'cors',\n redirect: 'follow',\n cache: 'default',\n retry: DEFAULT_RETRY,\n dedup: false,\n};\n","/**\n * httix — Error class hierarchy\n */\n\nimport type { HttixErrorOptions, HttixRequestConfig } from './types';\n\n/**\n * Base error class for all httix errors.\n */\nexport class HttixError extends Error {\n public readonly name: string = 'HttixError';\n public readonly config?: HttixRequestConfig;\n public override readonly cause?: Error;\n\n constructor(message: string, options?: HttixErrorOptions) {\n super(message);\n this.name = 'HttixError';\n this.config = options?.config;\n this.cause = options?.cause;\n\n // Restore proper prototype chain (required for extending built-ins in TS)\n Object.setPrototypeOf(this, new.target.prototype);\n\n // Maintain proper stack trace in V8 environments\n const ErrorConstructor = Error as unknown as {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (ErrorConstructor.captureStackTrace) {\n ErrorConstructor.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when a network-level request failure occurs\n * (e.g., DNS failure, connection refused, CORS error).\n */\nexport class HttixRequestError extends HttixError {\n public readonly name: string = 'HttixRequestError';\n\n constructor(message: string, options?: HttixErrorOptions) {\n super(message, options);\n this.name = 'HttixRequestError';\n }\n}\n\n/**\n * Error thrown when the server responds with a 4xx or 5xx status code.\n */\nexport class HttixResponseError extends HttixError {\n public readonly name: string = 'HttixResponseError';\n public readonly status: number;\n public readonly statusText: string;\n public readonly data: unknown;\n public readonly headers?: Headers;\n public override readonly config?: HttixRequestConfig;\n\n constructor(\n status: number,\n statusText: string,\n data: unknown,\n headers?: Headers,\n config?: HttixRequestConfig,\n ) {\n const message = `Request failed with status ${status}: ${statusText}`;\n super(message, { message, config });\n this.name = 'HttixResponseError';\n this.status = status;\n this.statusText = statusText;\n this.data = data;\n this.headers = headers;\n this.config = config;\n }\n}\n\n/**\n * Error thrown when a request exceeds its configured timeout.\n */\nexport class HttixTimeoutError extends HttixError {\n public readonly name: string = 'HttixTimeoutError';\n public readonly timeout: number;\n\n constructor(timeout: number, config?: HttixRequestConfig) {\n const message = `Request timed out after ${timeout}ms`;\n super(message, { message, config });\n this.name = 'HttixTimeoutError';\n this.timeout = timeout;\n }\n}\n\n/**\n * Error thrown when a request is cancelled via AbortController.\n */\nexport class HttixAbortError extends HttixError {\n public readonly name: string = 'HttixAbortError';\n public readonly reason: string;\n\n constructor(reason?: string, config?: HttixRequestConfig) {\n const message = reason ?? 'Request was aborted';\n super(message, { message, config });\n this.name = 'HttixAbortError';\n this.reason = message;\n }\n}\n\n/**\n * Error thrown when all retry attempts have been exhausted.\n */\nexport class HttixRetryError extends HttixError {\n public readonly name: string = 'HttixRetryError';\n public readonly attempts: number;\n public readonly lastError: HttixError;\n\n constructor(attempts: number, lastError: HttixError, config?: HttixRequestConfig) {\n const message = `Request failed after ${attempts} attempt${attempts === 1 ? '' : 's'}`;\n super(message, { message, config, cause: lastError });\n this.name = 'HttixRetryError';\n this.attempts = attempts;\n this.lastError = lastError;\n }\n}\n","/**\n * httix — Request builder\n *\n * Transforms an HttixRequestConfig into a native `Request` instance ready\n * for `fetch()`, handling URL interpolation, header merging, body\n * serialisation, timeout scheduling, and abort-signal composition.\n */\n\nimport type {\n HttixHeaders,\n HttixRequestConfig,\n PathParams,\n QueryParams,\n RequestBody,\n} from './types';\nimport { DEFAULT_HEADERS } from './defaults';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface BuildRequestResult {\n request: globalThis.Request;\n timeoutController?: AbortController;\n timeoutId?: ReturnType<typeof setTimeout>;\n}\n\n/**\n * Builds a native `Request` from an `HttixRequestConfig`.\n *\n * The returned `timeoutController` / `timeoutId` must be cleared by the\n * caller via `clearTimeoutSignal` once the request settles, otherwise the\n * timer will leak and keep the event-loop alive.\n */\nexport function buildRequest(config: HttixRequestConfig): BuildRequestResult {\n // 1. Build the full URL (baseURL + url interpolation + query string)\n const url = buildUrl(config.baseURL, config.url, config.params, config.query);\n\n // 2. Merge default headers with per-request headers (request wins)\n const headers = mergeHeaders(DEFAULT_HEADERS, config.headers);\n\n // 3. Serialise the request body (may mutate `headers` to set Content-Type)\n const body = serializeBody(config.body, headers);\n\n // 4. Create the native Request object\n const method = config.method ?? 'GET';\n const requestInit: globalThis.RequestInit = {\n method,\n headers,\n body,\n credentials: config.credentials,\n mode: config.mode,\n cache: config.cache,\n redirect: config.redirect,\n referrerPolicy: config.referrerPolicy,\n };\n\n // 5. Compose abort signals (config.signal + optional timeout)\n const timeout = config.timeout ?? 0;\n let timeoutController: AbortController | undefined;\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeout > 0) {\n timeoutController = new AbortController();\n timeoutId = setTimeout(() => {\n timeoutController!.abort(new DOMException(`Request timed out after ${timeout}ms`, 'TimeoutError'));\n }, timeout);\n\n if (config.signal) {\n // Both signals exist — combine so that *either* aborting cancels the request\n requestInit.signal = combineSignals(config.signal, timeoutController.signal);\n } else {\n requestInit.signal = timeoutController.signal;\n }\n } else if (config.signal) {\n requestInit.signal = config.signal;\n }\n\n const request = new globalThis.Request(url, requestInit);\n\n return { request, timeoutController, timeoutId };\n}\n\n/**\n * Cleans up the timeout timer and abort controller created by `buildRequest`.\n * Should be called in a `finally` block after the fetch settles.\n */\nexport function clearTimeoutSignal(\n _controller: AbortController | undefined,\n timeoutId: ReturnType<typeof setTimeout> | undefined,\n): void {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n // Note: We do NOT abort the controller here - the timeout signal is\n // combined with the user signal, and aborting it would cause the\n // response body parsing (response.json(), response.text(), etc.) to fail\n // with an AbortError. The controller will be garbage collected naturally.\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Combines multiple `AbortSignal`s into a single signal that aborts when\n * *any* of the source signals abort.\n */\nfunction combineSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n break;\n }\n signal.addEventListener(\n 'abort',\n () => controller.abort(signal.reason),\n { once: true },\n );\n }\n\n return controller.signal;\n}\n\n/**\n * Builds the full request URL by:\n * 1. Joining `baseURL` + `url` (handling slashes)\n * 2. Replacing `:paramName` path parameters\n * 3. Appending query-string parameters\n */\nfunction buildUrl(\n baseURL: string | undefined,\n url: string,\n params: PathParams | undefined,\n query: QueryParams | undefined,\n): string {\n let full = url;\n\n // Combine baseURL + url\n if (baseURL) {\n const base = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL;\n const path = full.startsWith('/') ? full : `/${full}`;\n full = `${base}${path}`;\n }\n\n // Interpolate path parameters (:paramName → value)\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n full = full.replace(`:${key}`, encodeURIComponent(String(value)));\n }\n }\n\n // Append query parameters\n if (query && Object.keys(query).length > 0) {\n const separator = full.includes('?') ? '&' : '?';\n full += `${separator}${encodeQueryParams(query)}`;\n }\n\n return full;\n}\n\n/**\n * Encodes a `QueryParams` object into a URL query string.\n * Handles arrays as repeated keys: `?key=a&key=b`\n */\nfunction encodeQueryParams(query: QueryParams): string {\n const parts: string[] = [];\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n // Skip nullish values entirely\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item !== undefined && item !== null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`);\n }\n }\n } else {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n\n return parts.join('&');\n}\n\n/**\n * Merges default headers with per-request headers.\n * Request headers always take precedence over defaults.\n */\nfunction mergeHeaders(\n defaults: HttixHeaders,\n custom?: HttixHeaders,\n): Headers {\n const merged = new Headers();\n\n // Apply defaults first\n applyHeaders(merged, defaults);\n\n // Custom headers override defaults\n if (custom) {\n applyHeaders(merged, custom);\n }\n\n return merged;\n}\n\n/**\n * Applies a `HttixHeaders` value to a `Headers` instance.\n */\nfunction applyHeaders(target: Headers, source: HttixHeaders): void {\n if (source instanceof Headers) {\n source.forEach((value, key) => {\n target.set(key, value);\n });\n } else {\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined) {\n target.set(key, value);\n }\n }\n }\n}\n\n/**\n * Serialises an `RequestBody` into a value suitable for the Fetch API\n * `body` parameter. Mutates `headers` to set `Content-Type` when JSON\n * serialisation is performed and no explicit Content-Type is present.\n *\n * Returns `undefined` when there is no body to send (which is correct for\n * GET/HEAD requests in the Fetch API).\n */\nfunction serializeBody(\n body: RequestBody | undefined,\n headers: Headers,\n): globalThis.BodyInit | undefined {\n if (body === undefined || body === null) {\n return undefined;\n }\n\n // Pass through natively-supported body types directly\n if (\n typeof body === 'string' ||\n body instanceof FormData ||\n body instanceof URLSearchParams ||\n body instanceof Blob ||\n body instanceof ArrayBuffer ||\n body instanceof ReadableStream\n ) {\n return body;\n }\n\n // Objects and arrays → JSON\n if (typeof body === 'object') {\n // Set Content-Type to application/json if not already set\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n return JSON.stringify(body);\n }\n\n // Primitives (number, boolean)\n // number / boolean — serialise as JSON string for consistency\n if (typeof body === 'number' || typeof body === 'boolean') {\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n return JSON.stringify(body);\n }\n\n return undefined;\n}\n","/**\n * httix — Response wrapper and body parsing utilities\n */\n\nimport type { HttixRequestConfig, HttixResponse } from './types';\n\n/**\n * Creates a fully-populated HttixResponse from a raw Fetch Response.\n */\nexport function createResponse<T>(\n raw: Response,\n config: HttixRequestConfig,\n data: T,\n timing: number,\n): HttixResponse<T> {\n return {\n data,\n status: raw.status,\n statusText: raw.statusText,\n headers: raw.headers,\n ok: raw.ok,\n raw,\n timing,\n config,\n };\n}\n\n/**\n * Parses the body of a Fetch Response according to the request configuration.\n *\n * Resolution order:\n * 1. Custom `parseResponse` function on config\n * 2. Explicit `responseType` ('json' | 'text' | 'blob' | 'arrayBuffer')\n * 3. Auto-detection based on Content-Type header and status code\n */\nexport async function parseResponseBody<T>(\n response: Response,\n config: HttixRequestConfig,\n): Promise<T> {\n // 1. Custom parser takes absolute precedence\n if (typeof config.parseResponse === 'function') {\n return (await config.parseResponse(response)) as T;\n }\n\n // 204 No Content — nothing to parse\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get('Content-Type') ?? '';\n\n // 2. Explicit responseType override\n if (config.responseType) {\n return parseWithType<T>(response, config.responseType);\n }\n\n // 3. Auto-detection\n return autoParse<T>(response, contentType);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nasync function parseWithType<T>(\n response: Response,\n responseType: NonNullable<HttixRequestConfig['responseType']>,\n): Promise<T> {\n switch (responseType) {\n case 'json': {\n try {\n return (await response.json()) as T;\n } catch {\n return undefined as T;\n }\n }\n case 'text': {\n try {\n return (await response.text()) as T;\n } catch {\n return undefined as T;\n }\n }\n case 'blob': {\n try {\n return (await response.blob()) as T;\n } catch {\n return undefined as T;\n }\n }\n case 'arrayBuffer': {\n try {\n return (await response.arrayBuffer()) as T;\n } catch {\n return undefined as T;\n }\n }\n }\n}\n\nasync function autoParse<T>(response: Response, contentType: string): Promise<T> {\n const lowerCt = contentType.toLowerCase();\n\n // application/json\n if (lowerCt.includes('application/json')) {\n try {\n return (await response.json()) as T;\n } catch {\n return undefined as T;\n }\n }\n\n // text/*\n if (lowerCt.includes('text/')) {\n try {\n return (await response.text()) as T;\n } catch {\n return undefined as T;\n }\n }\n\n // Null body (e.g. 204 already handled, but defensive check for zero-length)\n if (!response.body) {\n return undefined as T;\n }\n\n // Best-effort: read as text first, then try JSON.parse.\n // We cannot call response.json() then response.text() because the body\n // stream is consumed after the first read. Reading as text first lets us\n // attempt JSON parsing on the resulting string without double-consuming.\n try {\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n try {\n return JSON.parse(text) as T;\n } catch {\n // Not valid JSON — return the raw text as a best-effort fallback\n return text as T;\n }\n /* v8 ignore next 4 */\n } catch {\n // Body stream error — defensive fallback\n return undefined as T;\n }\n}\n","/**\n * httix — Interceptor management and execution\n */\n\nimport type {\n HttixRequestConfig,\n HttixResponse,\n InterceptorHandler,\n InterceptorManager as InterceptorManagerInterface,\n RequestInterceptor,\n RequestErrorInterceptor,\n ResponseErrorInterceptor,\n ResponseInterceptor,\n} from '../core/types';\nimport type { HttixError } from '../core/errors';\n\n/**\n * Manages a list of interceptor handlers for requests or responses.\n * Handlers can be added, ejected by id, or cleared entirely.\n */\nexport class InterceptorManager<F, E> implements InterceptorManagerInterface<F, E> {\n handlers: InterceptorHandler<F, E>[] = [];\n\n use(fulfilled: F, rejected?: E): number {\n this.handlers.push({ fulfilled, rejected });\n return this.handlers.length - 1;\n }\n\n eject(id: number): void {\n if (id >= 0 && id < this.handlers.length) {\n this.handlers[id] = null as unknown as InterceptorHandler<F, E>;\n }\n }\n\n clear(): void {\n this.handlers = [];\n }\n}\n\n/**\n * Run request interceptors sequentially, chaining each fulfilled handler's\n * output as the next handler's input. If a handler's fulfilled function\n * throws and it has a rejected handler, the rejected handler is called.\n * If the rejected handler returns a config the chain continues; if it\n * re-throws, the error propagates.\n */\nexport async function runRequestInterceptors(\n config: HttixRequestConfig,\n interceptors: InterceptorManagerInterface<RequestInterceptor, RequestErrorInterceptor>,\n): Promise<HttixRequestConfig> {\n let currentConfig = config;\n\n for (const handler of interceptors.handlers) {\n if (handler === null) continue;\n\n try {\n currentConfig = await handler.fulfilled(currentConfig);\n } catch (err) {\n if (handler.rejected) {\n try {\n const result = await handler.rejected(err as HttixError);\n // If rejected returns a config, continue the chain with it\n if (result !== undefined) {\n currentConfig = result;\n }\n // If rejected returns void, continue with the current config\n } catch {\n // Rejected handler threw — propagate the error\n throw err;\n }\n } else {\n // No rejected handler — propagate the error\n throw err;\n }\n }\n }\n\n return currentConfig;\n}\n\n/**\n * Run response interceptors sequentially, chaining each fulfilled handler's\n * output as the next handler's input. Error handling mirrors\n * runRequestInterceptors.\n */\nexport async function runResponseInterceptors<T>(\n response: HttixResponse<T>,\n interceptors: InterceptorManagerInterface<ResponseInterceptor<T>, ResponseErrorInterceptor>,\n): Promise<HttixResponse<T>> {\n let currentResponse = response;\n\n for (const handler of interceptors.handlers) {\n if (handler === null) continue;\n\n try {\n currentResponse = await handler.fulfilled(currentResponse);\n } catch (err) {\n if (handler.rejected) {\n try {\n const result = await handler.rejected(err as HttixError);\n if (result !== undefined) {\n currentResponse = result as HttixResponse<T>;\n }\n } catch {\n throw err;\n }\n } else {\n throw err;\n }\n }\n }\n\n return currentResponse;\n}\n\n/**\n * Attempt to handle a response error through response interceptors' rejected\n * handlers. If any rejected handler returns a response, the error is considered\n * \"handled\" and that response is returned. If no handler resolves the error,\n * the original error is re-thrown.\n */\nexport async function runResponseErrorInterceptors(\n error: HttixError,\n interceptors: InterceptorManagerInterface<ResponseInterceptor<unknown>, ResponseErrorInterceptor>,\n): Promise<HttixResponse<unknown>> {\n for (const handler of interceptors.handlers) {\n if (handler === null) continue;\n\n if (handler.rejected) {\n try {\n const result = await handler.rejected(error);\n // If the rejected handler returns a response, the error is handled\n if (result !== undefined && result !== null) {\n return result;\n }\n // If rejected returns void, continue to next handler\n } catch {\n // Rejected handler threw — continue to next handler\n continue;\n }\n }\n }\n\n // No handler resolved the error — re-throw the original\n throw error;\n}\n","/**\n * httix — General-purpose helper utilities\n */\n\nimport type { BackoffStrategy } from '../core/types';\nimport { HttixRequestError, HttixResponseError, type HttixError } from '../core/errors';\nimport { isAbsoluteURL } from './url';\n\n// Re-export isAbsoluteURL from url.ts so consumers can import from helpers\nexport { isAbsoluteURL };\n\n/**\n * Return a promise that resolves after the given number of milliseconds.\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise<void>((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Generate a unique request ID useful for tracing.\n * Format: `req_<timestamp>_<random7chars>`\n */\nexport function generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * Determine whether an error is eligible for automatic retry.\n *\n * - HttixRequestError (network-level failures) → retryable\n * - HttixResponseError with retryable status codes → retryable\n * - Everything else → not retryable\n */\nexport function isRetryableError(error: HttixError): boolean {\n if (error instanceof HttixRequestError) {\n return true;\n }\n\n if (error instanceof HttixResponseError) {\n return isRetryableStatus(error.status);\n }\n\n return false;\n}\n\n/**\n * Check whether an HTTP status code is considered retryable.\n */\nexport function isRetryableStatus(status: number): boolean {\n return [408, 429, 500, 502, 503, 504].includes(status);\n}\n\n/**\n * Calculate the delay in milliseconds before the next retry attempt.\n *\n * @param attempt - The current attempt number (1-based)\n * @param backoff - The backoff strategy to use\n * @param baseDelay - The base delay in milliseconds\n * @param maxDelay - The maximum allowed delay in milliseconds\n * @param jitter - Whether to apply random jitter (50%–100% of calculated delay)\n */\nexport function calculateDelay(\n attempt: number,\n backoff: BackoffStrategy,\n baseDelay: number,\n maxDelay: number,\n jitter: boolean,\n): number {\n let calculated: number;\n\n switch (backoff) {\n case 'fixed':\n calculated = baseDelay;\n break;\n case 'linear':\n calculated = baseDelay * attempt;\n break;\n case 'exponential':\n calculated = baseDelay * Math.pow(2, attempt - 1);\n break;\n default:\n // Fallback for unknown strategies — should never happen with valid BackoffStrategy\n calculated = baseDelay;\n break;\n }\n\n // Clamp to maxDelay\n calculated = Math.min(calculated, maxDelay);\n\n // Apply jitter: random value between 50% and 100% of the calculated delay\n if (jitter) {\n calculated = calculated * (0.5 + Math.random() * 0.5);\n }\n\n // Ensure the delay is never negative\n return Math.max(0, calculated);\n}\n","/**\n * httix — Retry logic\n */\n\nimport type { HttixRequestConfig, HttixResponse, RetryConfig } from '../core/types';\nimport { DEFAULT_RETRY } from '../core/defaults';\nimport { HttixRequestError, HttixResponseError } from '../core/errors';\nimport { calculateDelay, delay } from '../utils/helpers';\n\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\n\n/**\n * Parse a Retry-After header value.\n *\n * - If the value is a plain number, it represents seconds to wait.\n * - If the value is an ISO date string, calculate the number of seconds\n * from now until that date.\n * - Returns null if the value cannot be parsed.\n */\nexport function parseRetryAfter(value: string | null): number | null {\n if (value === null) return null;\n\n // Try parsing as a number of seconds\n const seconds = Number(value);\n if (!Number.isNaN(seconds) && seconds > 0 && String(seconds) === value.trim()) {\n return seconds * 1000;\n }\n\n // Try parsing as an ISO date string\n const date = Date.parse(value);\n if (!Number.isNaN(date)) {\n const diff = date - Date.now();\n return diff > 0 ? diff : 0;\n }\n\n return null;\n}\n\n/**\n * Execute a request function with retry support.\n *\n * Merges the provided retry configuration with defaults, evaluates retry\n * conditions on each failure, applies backoff delay, and throws\n * HttixRetryError if all attempts are exhausted.\n */\nexport async function retryRequest<T>(\n fn: () => Promise<HttixResponse<T>>,\n config: RetryConfig | false | undefined,\n requestConfig: HttixRequestConfig,\n): Promise<HttixResponse<T>> {\n // If retry is explicitly disabled, just execute once\n if (config === false || config === undefined) {\n return fn();\n }\n\n // Merge user config over defaults\n const retryCfg: Required<RetryConfig> = {\n attempts: config.attempts ?? DEFAULT_RETRY.attempts,\n backoff: config.backoff ?? DEFAULT_RETRY.backoff,\n baseDelay: config.baseDelay ?? DEFAULT_RETRY.baseDelay,\n maxDelay: config.maxDelay ?? DEFAULT_RETRY.maxDelay,\n jitter: config.jitter ?? DEFAULT_RETRY.jitter,\n retryOn: config.retryOn ?? DEFAULT_RETRY.retryOn,\n retryOnNetworkError: config.retryOnNetworkError ?? DEFAULT_RETRY.retryOnNetworkError,\n retryOnSafeMethodsOnly: config.retryOnSafeMethodsOnly ?? DEFAULT_RETRY.retryOnSafeMethodsOnly,\n retryCondition: config.retryCondition ?? DEFAULT_RETRY.retryCondition,\n onRetry: config.onRetry ?? DEFAULT_RETRY.onRetry,\n };\n\n const maxAttempts = retryCfg.attempts;\n const method = (requestConfig.method ?? 'GET').toUpperCase();\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const response = await fn();\n\n // Successful 2xx — return immediately\n if (response.status >= 200 && response.status < 300) {\n return response;\n }\n\n // Non-2xx response: check if retryable\n if (!retryCfg.retryOn.includes(response.status)) {\n return response;\n }\n\n // Create an HttixResponseError for consistency\n const responseError = new HttixResponseError(\n response.status,\n response.statusText,\n response.data,\n response.headers,\n requestConfig,\n );\n lastError = responseError;\n\n if (!shouldRetry(responseError, attempt, maxAttempts, retryCfg, method)) {\n throw responseError;\n }\n\n // Calculate and apply delay\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));\n const backoffMs = calculateDelay(\n attempt + 1,\n retryCfg.backoff,\n retryCfg.baseDelay,\n retryCfg.maxDelay,\n retryCfg.jitter,\n );\n const finalDelay = retryAfterMs !== null ? retryAfterMs : backoffMs;\n\n retryCfg.onRetry(attempt + 1, responseError, finalDelay);\n await delay(finalDelay);\n } catch (err) {\n lastError = err;\n\n if (!shouldRetry(err as Error, attempt, maxAttempts, retryCfg, method)) {\n throw err;\n }\n\n const httixErr = err as HttixRequestError | HttixResponseError;\n\n // Calculate and apply delay\n const retryAfterMs =\n httixErr instanceof HttixResponseError\n ? parseRetryAfter(httixErr.headers?.get('retry-after') ?? null)\n : null;\n const backoffMs = calculateDelay(\n attempt + 1,\n retryCfg.backoff,\n retryCfg.baseDelay,\n retryCfg.maxDelay,\n retryCfg.jitter,\n );\n const finalDelay = retryAfterMs !== null ? retryAfterMs : backoffMs;\n\n retryCfg.onRetry(attempt + 1, httixErr, finalDelay);\n await delay(finalDelay);\n }\n }\n\n // All attempts exhausted — defensive fallback\n /* v8 ignore start */\n if (!lastError) throw new Error('All retry attempts exhausted');\n throw lastError;\n}\n/* v8 ignore stop */\n\n/**\n * Determine whether the request should be retried based on the error\n * type, retry configuration, and current attempt.\n */\nfunction shouldRetry(\n error: Error,\n attempt: number,\n maxAttempts: number,\n config: Required<RetryConfig>,\n method: string,\n): boolean {\n // Check if attempts remaining\n if (attempt + 1 >= maxAttempts) {\n return false;\n }\n\n // Check safe methods restriction\n if (config.retryOnSafeMethodsOnly && !SAFE_METHODS.has(method)) {\n return false;\n }\n\n // Check custom retry condition\n if (!config.retryCondition(error as HttixResponseError & HttixRequestError)) {\n return false;\n }\n\n // Network error\n if (error instanceof HttixRequestError) {\n return config.retryOnNetworkError;\n }\n\n // Response error — check status against retryOn list\n if (error instanceof HttixResponseError) {\n return config.retryOn.includes(error.status);\n }\n\n return false;\n}\n","/**\n * httix — Request deduplication\n */\n\nimport type { HttixRequestConfig } from '../core/types';\n\n/**\n * Deduplicates in-flight requests and optionally caches responses\n * for a configurable TTL.\n *\n * - When `ttl` is 0 (default), only coalesces concurrent requests with\n * the same key — once the request resolves, subsequent calls execute\n * a new request.\n * - When `ttl` > 0, resolved responses are cached for the specified\n * duration and returned for matching keys without re-executing.\n */\nexport class RequestDeduplicator {\n private inflight = new Map<string, Promise<unknown>>();\n private cache = new Map<string, { data: unknown; timestamp: number }>();\n private ttl: number;\n\n constructor(ttl = 0) {\n this.ttl = ttl;\n }\n\n /**\n * Deduplicate a request by key.\n *\n * If a cached response is available (and not expired), return it.\n * If a request is already in-flight, return the same promise.\n * Otherwise, execute `requestFn`, cache the result (if TTL > 0),\n * and return it.\n */\n async dedup<T>(key: string, requestFn: () => Promise<T>): Promise<T> {\n // Check cache first (if TTL > 0)\n if (this.ttl > 0) {\n const cached = this.cache.get(key);\n if (cached && Date.now() - cached.timestamp < this.ttl) {\n return cached.data as T;\n }\n }\n\n // Check in-flight requests\n const inflight = this.inflight.get(key);\n if (inflight) {\n return inflight as Promise<T>;\n }\n\n // Execute the request\n const promise = requestFn().then((result) => {\n // Cache result if TTL > 0\n if (this.ttl > 0) {\n this.cache.set(key, { data: result, timestamp: Date.now() });\n }\n this.inflight.delete(key);\n return result;\n }).catch((error) => {\n this.inflight.delete(key);\n throw error;\n });\n\n this.inflight.set(key, promise);\n return promise;\n }\n\n /**\n * Generate a deduplication key from a request config.\n *\n * The key is composed of the HTTP method, origin, pathname, and\n * sorted query parameters.\n */\n generateKey(config: HttixRequestConfig): string {\n const url = new URL(config.url, config.baseURL);\n const sortedQuery = config.query\n ? Object.keys(config.query)\n .sort()\n .map((k) => `${k}=${String((config.query as Record<string, unknown>)[k])}`)\n .join('&')\n : '';\n return `${config.method || 'GET'}:${url.origin}${url.pathname}${sortedQuery ? '?' + sortedQuery : ''}`;\n }\n\n /**\n * Clear all in-flight requests and cached responses.\n */\n clear(): void {\n this.inflight.clear();\n this.cache.clear();\n }\n}\n","/**\n * httix — Rate limiting\n */\n\n/**\n * Token-bucket-style rate limiter that limits the number of concurrent\n * requests within a sliding time window per key.\n *\n * When the maximum number of requests for a key is reached, additional\n * requests are queued and drained when the next interval starts.\n */\nexport class RateLimiter {\n private queues = new Map<string, Array<{ execute: () => Promise<void>; resolve: (v: unknown) => void }>>();\n private activeCounts = new Map<string, number>();\n private timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n constructor(\n private maxRequests: number,\n private interval: number,\n ) {}\n\n /**\n * Throttle a request function by key.\n *\n * If the number of active requests for the given key is below\n * `maxRequests`, the request executes immediately. Otherwise, it is\n * queued and will execute when the next interval starts.\n */\n async throttle(key: string, requestFn: () => Promise<unknown>): Promise<unknown> {\n // If there's no active window, reset count (timer already fired)\n if (!this.timers.has(key)) {\n this.activeCounts.set(key, 0);\n }\n\n const count = this.activeCounts.get(key) || 0;\n\n if (count < this.maxRequests) {\n // Execute immediately\n this.activeCounts.set(key, count + 1);\n if (count === 0) {\n // Start the interval timer on first request of a new window\n this.timers.set(key, setTimeout(() => {\n this.activeCounts.set(key, 0);\n this.timers.delete(key);\n // Drain queue\n this.drainQueue(key);\n }, this.interval));\n }\n return requestFn();\n }\n\n // Queue the request — it will be resolved when drainQueue executes it\n return new Promise((resolve) => {\n if (!this.queues.has(key)) {\n this.queues.set(key, []);\n }\n this.queues.get(key)!.push({\n execute: async () => {\n const result = await requestFn();\n resolve(result);\n },\n /* v8 ignore next */\n resolve: () => {},\n });\n });\n }\n\n /**\n * Drain queued requests for a given key, processing up to maxRequests\n * and starting a new interval timer.\n */\n private drainQueue(key: string): void {\n const queue = this.queues.get(key);\n if (!queue || queue.length === 0) return;\n\n const toProcess = queue.splice(0, this.maxRequests);\n this.activeCounts.set(key, toProcess.length);\n\n // Restart timer for the next window\n this.timers.set(key, setTimeout(() => {\n this.activeCounts.set(key, 0);\n this.timers.delete(key);\n this.drainQueue(key);\n }, this.interval));\n\n for (const item of toProcess) {\n item.execute();\n }\n }\n\n /**\n * Clear all queues, timers, and active counts.\n */\n clear(): void {\n for (const timer of this.timers.values()) {\n clearTimeout(timer);\n }\n this.queues.clear();\n this.activeCounts.clear();\n this.timers.clear();\n }\n\n /**\n * Get the number of queued (waiting) requests for a given key.\n */\n getQueueSize(key: string): number {\n return this.queues.get(key)?.length || 0;\n }\n}\n","/**\n * httix — Koa-style middleware composition\n */\n\nimport type { HttixRequestConfig, HttixResponse, MiddlewareContext, MiddlewareFn } from '../core/types';\n\n/**\n * Compose an array of middleware functions into a single function.\n *\n * The composition follows the Koa \"onion\" model: each middleware is called\n * with a context and a `next` function that invokes the next middleware in\n * the chain. Code before `await next()` runs on the way in; code after\n * `await next()` runs on the way out (in reverse order).\n *\n * If no middlewares are provided, the composed function simply calls `next`.\n *\n * @throws {Error} If `next()` is called more than once in a single middleware.\n */\nexport function composeMiddleware<T>(\n middlewares: MiddlewareFn<T>[],\n): (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void> {\n return function composed(ctx, next) {\n let index = -1;\n\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n const fn = middlewares[i];\n if (!fn) {\n return next();\n }\n\n await fn(ctx as MiddlewareContext<HttixRequestConfig, HttixResponse<T>>, () => dispatch(i + 1));\n }\n\n return dispatch(0);\n };\n}\n","/**\n * httix — Authentication utilities\n */\n\nimport type {\n AuthConfig,\n BearerAuthConfig,\n HttixRequestConfig,\n RequestInterceptor,\n ResponseErrorInterceptor,\n} from '../core/types';\nimport type { HttixError } from '../core/errors';\nimport { HttixResponseError as HttixResponseErrorCls } from '../core/errors';\n\n/**\n * Resolve an auth value that may be a static value or an async resolver function.\n */\nasync function resolveValue(value: string | (() => string | Promise<string>)): Promise<string> {\n return typeof value === 'function' ? value() : value;\n}\n\n/**\n * Deep-clone a request config so mutations don't affect the original.\n */\nfunction cloneConfig(config: HttixRequestConfig): HttixRequestConfig {\n return { ...config };\n}\n\n/**\n * Apply authentication headers or query parameters to a request config\n * based on the provided auth configuration.\n *\n * Returns a new config object — the original is not mutated.\n */\nexport async function applyAuth(\n config: HttixRequestConfig,\n authConfig: AuthConfig,\n): Promise<HttixRequestConfig> {\n const result = cloneConfig(config);\n\n // Ensure headers is a plain object we can mutate\n const headers: Record<string, string> = {};\n if (result.headers) {\n if (result.headers instanceof Headers) {\n result.headers.forEach((value, key) => {\n headers[key] = value;\n });\n } else {\n Object.assign(headers, result.headers);\n }\n }\n result.headers = headers;\n\n // Ensure query is a mutable object\n const query: Record<string, string | number | boolean | null | undefined> = {\n ...(result.query as Record<string, string | number | boolean | null | undefined> | undefined),\n };\n\n switch (authConfig.type) {\n case 'bearer': {\n const token = await resolveValue(authConfig.token);\n headers['Authorization'] = `Bearer ${token}`;\n break;\n }\n\n case 'basic': {\n const credentials = `${authConfig.username}:${authConfig.password}`;\n const encoded = btoa(credentials);\n headers['Authorization'] = `Basic ${encoded}`;\n break;\n }\n\n case 'apiKey': {\n const value = await resolveValue(authConfig.value);\n if (authConfig.in === 'header') {\n headers[authConfig.key] = value;\n } else {\n // 'query'\n query[authConfig.key] = value;\n }\n break;\n }\n }\n\n // Only set query if we actually added something\n if (Object.keys(query).length > Object.keys(result.query ?? {}).length || authConfig.type === 'apiKey' && authConfig.in === 'query') {\n result.query = query;\n }\n\n return result;\n}\n\n/**\n * Create a request interceptor that applies authentication to every\n * outgoing request.\n */\nexport function createAuthInterceptor(authConfig: AuthConfig): RequestInterceptor {\n return async (config: HttixRequestConfig): Promise<HttixRequestConfig> => {\n return applyAuth(config, authConfig);\n };\n}\n\n/**\n * Create a response error interceptor that handles 401 Unauthorized\n * errors by refreshing the bearer token and retrying the original request.\n *\n * If no `refreshToken` is configured, returns a no-op interceptor.\n * Concurrent 401 errors are deduplicated — only one token refresh\n * happens at a time, and other callers wait for the same refresh.\n */\nexport function createAuthRefreshHandler(\n authConfig: BearerAuthConfig,\n): ResponseErrorInterceptor {\n // No-op if no refresh mechanism is configured\n if (!authConfig.refreshToken) {\n return (_error: HttixError): void => {\n // Signal the error is not handled\n };\n }\n\n let refreshPromise: Promise<string> | null = null;\n\n return (async (error: HttixError) => {\n // Only handle 401 errors\n if (!(error instanceof HttixResponseErrorCls) || error.status !== 401) {\n return;\n }\n\n const originalConfig = error.config;\n if (!originalConfig) {\n return;\n }\n\n // Dedup concurrent refreshes\n if (!refreshPromise) {\n refreshPromise = authConfig.refreshToken!().then((newToken) => {\n // Persist the new token if a callback is provided\n if (authConfig.onTokenRefresh) {\n authConfig.onTokenRefresh(newToken);\n }\n // Update the static token so future requests use it\n if (typeof authConfig.token === 'string') {\n (authConfig as { token: string }).token = newToken;\n }\n refreshPromise = null;\n return newToken;\n }).catch((refreshError) => {\n refreshPromise = null;\n throw refreshError;\n });\n }\n\n let newToken: string;\n try {\n newToken = await refreshPromise;\n } catch {\n // Refresh failed — re-throw the original 401 error\n throw error;\n }\n\n // Retry the original request with the new token\n const retryConfig = await applyAuth(originalConfig, authConfig);\n // Override the token with the freshly refreshed one\n const retryHeaders: Record<string, string> = {};\n if (retryConfig.headers) {\n Object.assign(retryHeaders, retryConfig.headers);\n }\n retryHeaders['Authorization'] = `Bearer ${newToken}`;\n retryConfig.headers = retryHeaders;\n\n // We return nothing (error not handled), but the auth token is now refreshed.\n // The caller is expected to retry with the updated config.\n return;\n }) as unknown as ResponseErrorInterceptor;\n}\n","/**\n * httix — Pagination utilities\n */\n\nimport type {\n HttixClient,\n HttixRequestConfig,\n HttixResponse,\n PaginationConfig,\n} from '../core/types';\n\n/**\n * Parse an HTTP Link header into a record of rel → URL mappings.\n *\n * Input format: `<url>; rel=\"next\", <url>; rel=\"last\"`\n *\n * Returns an object like `{ next: 'https://...', last: 'https://...' }`.\n */\nexport function parseLinkHeader(linkHeader: string): Record<string, string> {\n const result: Record<string, string> = {};\n\n if (!linkHeader) return result;\n\n // Split by comma, but be careful with commas inside angle brackets (unlikely but safe)\n const parts = linkHeader.split(',');\n\n for (const part of parts) {\n const trimmed = part.trim();\n\n // Extract URL from angle brackets\n const urlMatch = trimmed.match(/<([^>]+)>/);\n if (!urlMatch) continue;\n\n const url = urlMatch[1];\n /* v8 ignore next */ if (url === undefined) continue;\n\n // Extract rel value\n const relMatch = trimmed.match(/rel\\s*=\\s*\"([^\"]+)\"/);\n if (!relMatch) continue;\n\n const rel = relMatch[1]!;\n result[rel] = url;\n }\n\n return result;\n}\n\n/**\n * Create a paginator function that returns an async iterable of pages.\n *\n * Supports three pagination styles:\n * - **offset**: Tracks offset and incrementing by pageSize each iteration.\n * - **cursor**: Extracts a cursor from the response data and passes it\n * as a query parameter for the next request.\n * - **link**: Extracts the next URL from the Link response header.\n *\n * The iterable respects `maxPages`, `stopCondition`, and `dataExtractor`\n * from the PaginationConfig.\n */\nexport function createPaginator<T>(\n client: HttixClient,\n): (\n url: string,\n config?: Partial<HttixRequestConfig> & { pagination?: PaginationConfig<T> },\n) => AsyncIterable<T[]> {\n return async function* paginate(\n url: string,\n config?: Partial<HttixRequestConfig> & { pagination?: PaginationConfig<T> },\n ) {\n const pagination = config?.pagination;\n if (!pagination) {\n return;\n }\n\n const {\n style,\n pageSize = 20,\n maxPages = Infinity,\n offsetParam = 'offset',\n limitParam = 'limit',\n cursorParam = 'cursor',\n cursorExtractor,\n linkExtractor,\n dataExtractor,\n stopCondition,\n } = pagination;\n\n let currentUrl: string | null = url;\n let offset = 0;\n let cursor: string | null | undefined;\n let pageCount = 0;\n\n while (currentUrl && pageCount < maxPages) {\n // Build request config for this page\n const requestConfig: Partial<HttixRequestConfig> = { ...config };\n\n if (style === 'offset') {\n requestConfig.query = {\n ...requestConfig.query,\n [offsetParam]: offset,\n [limitParam]: pageSize,\n } as Record<string, string | number | boolean | null | undefined>;\n } else if (style === 'cursor') {\n requestConfig.query = {\n ...requestConfig.query,\n [cursorParam]: cursor,\n } as Record<string, string | number | boolean | null | undefined>;\n }\n\n let response: HttixResponse<T>;\n\n if (style === 'link' && pageCount > 0) {\n // For link style after the first page, use the URL from the Link header\n response = await client.request<T>({\n url: currentUrl,\n ...requestConfig,\n } as HttixRequestConfig);\n } else {\n response = await client.request<T>({\n url: currentUrl,\n ...requestConfig,\n } as HttixRequestConfig);\n }\n\n pageCount++;\n\n // Extract the page data\n let pageData: T[];\n\n if (dataExtractor) {\n pageData = dataExtractor(response.data);\n } else {\n // Default: assume response.data is the array\n pageData = (response.data ?? []) as T[];\n }\n\n // Check stop condition (on raw data, not extracted array)\n if (stopCondition && stopCondition(response.data)) {\n if (pageData.length > 0) {\n yield pageData;\n }\n return;\n }\n\n // If no data, stop paginating\n if (pageData.length === 0) {\n return;\n }\n\n yield pageData;\n\n // Determine the next page\n switch (style) {\n case 'offset': {\n // If we got fewer items than pageSize, there are no more pages\n if (pageData.length < pageSize) {\n return;\n }\n offset += pageSize;\n break;\n }\n\n case 'cursor': {\n if (cursorExtractor) {\n cursor = cursorExtractor(response.data);\n } else {\n // Default: try to extract from data if it looks like it has a cursor\n cursor = null;\n }\n if (!cursor) {\n return;\n }\n break;\n }\n\n case 'link': {\n if (linkExtractor) {\n currentUrl = linkExtractor(response.headers) ?? null;\n } else {\n // Default: parse the Link header\n const linkHeader = response.headers.get('link');\n if (linkHeader) {\n const links = parseLinkHeader(linkHeader);\n currentUrl = links['next'] ?? null;\n } else {\n currentUrl = null;\n }\n }\n break;\n }\n }\n }\n };\n}\n","/**\n * httix — Streaming utilities (SSE, NDJSON, progress tracking)\n */\n\nimport type { DownloadProgress, SSEEvent } from '../core/types';\n\n/**\n * Parse a ReadableStream of bytes as Server-Sent Events (SSE).\n *\n * Returns an async iterable that yields SSEEvent objects. Handles\n * partial chunks, multi-line data fields, and the standard SSE fields\n * (event, data, id, retry).\n *\n * The stream reader is released when the iterator is broken or returns.\n */\nexport async function* parseSSE(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<SSEEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const parts = buffer.split('\\n\\n');\n // Keep the last (potentially incomplete) part in the buffer\n buffer = parts.pop()!;\n\n for (const part of parts) {\n const event = parseSSEEvent(part);\n if (event !== null) {\n yield event;\n }\n }\n }\n\n // Process any remaining data in the buffer\n if (buffer.trim().length > 0) {\n const event = parseSSEEvent(buffer);\n if (event !== null) {\n yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Parse a single SSE event block into an SSEEvent object.\n * Returns null for empty blocks or comments.\n */\nfunction parseSSEEvent(block: string): SSEEvent | null {\n const lines = block.split('\\n');\n const fields: Partial<SSEEvent> = {};\n\n const dataLines: string[] = [];\n\n for (const line of lines) {\n // Skip empty lines and comments (lines starting with ':')\n if (line === '' || line.startsWith(':')) continue;\n\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n // Field with no value\n const field = line.trim();\n if (field === 'data') {\n dataLines.push('');\n }\n continue;\n }\n\n const field = line.slice(0, colonIndex).trim();\n let value = line.slice(colonIndex + 1);\n\n // Remove leading space from value per SSE spec\n if (value.startsWith(' ')) {\n value = value.slice(1);\n }\n\n switch (field) {\n case 'event':\n fields.type = value;\n break;\n case 'data':\n dataLines.push(value);\n break;\n case 'id':\n fields.id = value;\n break;\n case 'retry':\n fields.retry = parseInt(value, 10);\n break;\n // Ignore unknown fields\n }\n }\n\n // If there are no data lines, this is not a valid event\n if (dataLines.length === 0) return null;\n\n return {\n type: fields.type ?? 'message',\n data: dataLines.join('\\n'),\n id: fields.id,\n retry: fields.retry,\n };\n}\n\n/**\n * Parse a ReadableStream of bytes as Newline-Delimited JSON (NDJSON).\n *\n * Returns an async iterable that yields parsed JSON objects of type T.\n * Empty lines are skipped. Partial lines are buffered until a newline\n * arrives.\n *\n * The stream reader is released when the iterator is broken or returns.\n */\nexport async function* parseNDJSON<T>(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<T> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n // Keep the last (potentially incomplete) line in the buffer\n buffer = lines.pop()!;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n yield JSON.parse(trimmed) as T;\n }\n }\n\n // Process any remaining data in the buffer\n const remaining = buffer.trim();\n if (remaining.length > 0) {\n yield JSON.parse(remaining) as T;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Create a progress-tracking wrapper around a ReadableStream.\n *\n * Returns a new ReadableStream that transparently passes through all\n * chunks while invoking `onProgress` for each chunk received, reporting\n * the number of bytes loaded so far.\n *\n * If `total` is provided (e.g., from Content-Length), `percent` will\n * reflect completion percentage; otherwise it defaults to 0.\n */\nexport function createProgressReader(\n body: ReadableStream<Uint8Array>,\n onProgress: (progress: DownloadProgress) => void,\n total?: number,\n): ReadableStream<Uint8Array> {\n let loaded = 0;\n\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n const reader = body.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n\n loaded += value.byteLength;\n\n const percent = total !== undefined && total > 0\n ? Math.round((loaded / total) * 100)\n : 0;\n\n onProgress({\n loaded,\n total: total !== undefined ? total : undefined,\n percent,\n });\n\n controller.enqueue(value);\n }\n } catch (err) {\n controller.error(err);\n } finally {\n reader.releaseLock();\n }\n },\n });\n}\n","/**\n * httix — Header manipulation utilities\n */\n\nimport type { HttixHeaders } from '../core/types';\n\n/**\n * Merge default headers with custom headers.\n * Custom headers take precedence over defaults.\n */\nexport function mergeHeaders(\n defaults: HttixHeaders | undefined,\n custom: HttixHeaders | undefined,\n): Headers {\n const merged = new Headers();\n\n if (defaults) {\n addHeadersToInstance(merged, defaults);\n }\n\n if (custom) {\n addHeadersToInstance(merged, custom);\n }\n\n return merged;\n}\n\n/**\n * Capitalize the first letter of each word in a header name.\n * e.g. 'content-type' → 'Content-Type'\n */\nexport function normalizeHeaderName(name: string): string {\n return name\n .split('-')\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase())\n .join('-');\n}\n\n/**\n * Get the Content-Type header from a Headers object (case-insensitive).\n * Returns the value in lowercase, or null if not present.\n */\nexport function getContentType(headers: Headers): string | null {\n const value = headers.get('content-type');\n return value !== null ? value.toLowerCase() : null;\n}\n\n/**\n * Check if the given content type indicates JSON.\n */\nexport function isJSONContentType(contentType: string | null): boolean {\n if (contentType === null) {\n return false;\n }\n return contentType.includes('application/json');\n}\n\n/**\n * Check if the given content type indicates text or XML.\n */\nexport function isTextContentType(contentType: string | null): boolean {\n if (contentType === null) {\n return false;\n }\n return contentType.includes('text/') || contentType.includes('application/xml');\n}\n\n/**\n * Convert HttixHeaders (Record<string, string> or Headers) to a new Headers instance.\n */\nexport function parseHeaders(headersInit: HttixHeaders): Headers {\n const headers = new Headers();\n addHeadersToInstance(headers, headersInit);\n return headers;\n}\n\n/**\n * Internal helper: add entries from an HttixHeaders source into a Headers instance.\n */\nfunction addHeadersToInstance(target: Headers, source: HttixHeaders): void {\n if (source instanceof Headers) {\n source.forEach((value, key) => {\n target.set(key, value);\n });\n } else {\n for (const [key, value] of Object.entries(source)) {\n target.set(key, value);\n }\n }\n}\n","/**\n * httix — Configuration merging utilities\n */\n\nimport type { HttixRequestConfig, QueryParams } from '../core/types';\nimport { mergeHeaders } from './headers';\n\n/**\n * Deep-merge two partial request configs.\n *\n * Rules:\n * - Headers → mergeHeaders (custom overrides defaults)\n * - Query → mergeQueryParams (source overrides target)\n * - Primitive values (string, number, boolean) → source takes precedence\n * - Plain objects → deep merge recursively\n * - Arrays → source replaces target entirely\n * - Neither input is mutated.\n */\nexport function deepMergeConfig(\n target: Partial<HttixRequestConfig>,\n source: Partial<HttixRequestConfig>,\n): Partial<HttixRequestConfig> {\n const result: Partial<HttixRequestConfig> = { ...target };\n\n for (const key of Object.keys(source) as Array<keyof Partial<HttixRequestConfig>>) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n // Headers — use the dedicated merge function\n if (key === 'headers') {\n result.headers = mergeHeaders(\n targetVal as Partial<HttixRequestConfig>['headers'] | undefined,\n sourceVal as Partial<HttixRequestConfig>['headers'] | undefined,\n );\n continue;\n }\n\n // Query — merge query param objects\n if (key === 'query') {\n result.query = mergeQueryParams(\n targetVal as QueryParams | undefined,\n sourceVal as QueryParams | undefined,\n );\n continue;\n }\n\n // Skip undefined source values\n if (sourceVal === undefined) {\n continue;\n }\n\n // Arrays — source replaces target entirely\n if (Array.isArray(sourceVal)) {\n (result as Record<string, unknown>)[key as string] = sourceVal;\n continue;\n }\n\n // If both target and source are plain objects, deep merge\n if (\n sourceVal !== null &&\n targetVal !== null &&\n typeof sourceVal === 'object' &&\n typeof targetVal === 'object' &&\n !Array.isArray(sourceVal) &&\n !Array.isArray(targetVal)\n ) {\n (result as Record<string, unknown>)[key as string] = deepMergePlainObjects(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n );\n continue;\n }\n\n // Primitive values and everything else — source wins\n (result as Record<string, unknown>)[key as string] = sourceVal;\n }\n\n return result;\n}\n\n/**\n * Merge two query-params objects. Source values override target values.\n */\nexport function mergeQueryParams(\n target: QueryParams | undefined,\n source: QueryParams | undefined,\n): QueryParams {\n if (!target && !source) {\n return {};\n }\n if (!target) {\n return { ...source! };\n }\n if (!source) {\n return { ...target };\n }\n return { ...target, ...source };\n}\n\n/**\n * Recursively deep-merge two plain objects (no special cases for headers/query).\n */\nfunction deepMergePlainObjects(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n\n for (const key of Object.keys(source)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (sourceVal === undefined) {\n continue;\n }\n\n // Arrays — source replaces target\n if (Array.isArray(sourceVal)) {\n result[key] = sourceVal;\n continue;\n }\n\n // Both plain objects — recurse\n if (\n sourceVal !== null &&\n targetVal !== null &&\n typeof sourceVal === 'object' &&\n typeof targetVal === 'object' &&\n !Array.isArray(sourceVal) &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMergePlainObjects(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n );\n continue;\n }\n\n // Primitives and everything else — source wins\n result[key] = sourceVal;\n }\n\n return result;\n}\n","/**\n * httix-http — Main HTTP client implementation\n *\n * The HttixClientImpl class is the heart of the library. It orchestrates\n * configuration merging, middleware, interceptors, authentication,\n * deduplication, rate limiting, retries, timeouts, streaming, and\n * pagination into a single cohesive request pipeline.\n */\n\nimport type {\n HttixClient as HttixClientInterface,\n HttixConfig,\n HttixRequestConfig,\n HttixResponse,\n RequestBody,\n MiddlewareFn,\n MiddlewareContext,\n SSEEvent,\n AuthConfig,\n DedupConfig,\n RequestInterceptor,\n RequestErrorInterceptor,\n ResponseInterceptor,\n ResponseErrorInterceptor,\n InterceptorManager as InterceptorManagerInterface,\n} from './types';\nimport { DEFAULT_CONFIG } from './defaults';\nimport {\n HttixRequestError,\n HttixResponseError,\n HttixTimeoutError,\n HttixAbortError,\n} from './errors';\nimport { buildRequest, clearTimeoutSignal } from './request';\nimport { createResponse, parseResponseBody } from './response';\nimport { InterceptorManager } from '../features/interceptors';\nimport {\n runRequestInterceptors,\n runResponseInterceptors,\n runResponseErrorInterceptors,\n} from '../features/interceptors';\nimport { retryRequest } from '../features/retry';\nimport { RequestDeduplicator } from '../features/dedup';\nimport { RateLimiter } from '../features/rateLimit';\nimport { composeMiddleware } from '../features/middleware';\nimport {\n applyAuth,\n createAuthInterceptor,\n createAuthRefreshHandler,\n} from '../features/auth';\nimport { createPaginator } from '../features/pagination';\nimport { parseSSE, parseNDJSON } from '../features/streaming';\nimport { deepMergeConfig } from '../utils/merge';\nimport { generateRequestId } from '../utils/helpers';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Combine multiple AbortSignals into one that aborts when any source aborts.\n */\nfunction combineSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n break;\n }\n signal.addEventListener(\n 'abort',\n () => controller.abort(signal.reason),\n { once: true },\n );\n }\n\n return controller.signal;\n}\n\n// ---------------------------------------------------------------------------\n// HttixClientImpl\n// ---------------------------------------------------------------------------\n\nexport class HttixClientImpl implements HttixClientInterface {\n /** Merged default configuration for this client instance. */\n readonly defaults: HttixConfig;\n\n /** Interceptor managers for request and response pipelines. */\n readonly interceptors: {\n request: InterceptorManager<RequestInterceptor, RequestErrorInterceptor>;\n response: InterceptorManager<ResponseInterceptor<unknown>, ResponseErrorInterceptor>;\n };\n\n /** Stream utilities bound to this client. */\n readonly stream: {\n sse: (url: string, config?: Partial<HttixRequestConfig>) => AsyncIterable<SSEEvent>;\n ndjson: <T = unknown>(url: string, config?: Partial<HttixRequestConfig>) => AsyncIterable<T>;\n };\n\n /** Pagination helper bound to this client. */\n readonly paginate: HttixClientInterface['paginate'];\n\n // -- Private state --------------------------------------------------------\n\n private middlewares: MiddlewareFn[];\n private deduplicator?: RequestDeduplicator;\n private dedupConfig?: boolean | DedupConfig;\n private rateLimiter?: RateLimiter;\n private authConfig?: AuthConfig;\n private pendingControllers: Set<AbortController>;\n\n constructor(config?: Partial<HttixConfig>) {\n // 1. Deep-merge user config with library defaults\n this.defaults = deepMergeConfig(\n DEFAULT_CONFIG,\n config ?? {},\n ) as HttixConfig;\n\n // 2. Interceptor managers\n this.interceptors = {\n request: new InterceptorManager<RequestInterceptor, RequestErrorInterceptor>(),\n response: new InterceptorManager<ResponseInterceptor<unknown>, ResponseErrorInterceptor>(),\n };\n\n // 3. Middleware array (from defaults or empty)\n this.middlewares = this.defaults.middleware\n ? [...this.defaults.middleware]\n : [];\n\n // 4. Deduplication\n this.dedupConfig = this.defaults.dedup;\n if (this.dedupConfig === true || (typeof this.dedupConfig === 'object' && this.dedupConfig.enabled)) {\n const ttl =\n typeof this.dedupConfig === 'object' && this.dedupConfig.ttl !== undefined\n ? this.dedupConfig.ttl\n : 0;\n this.deduplicator = new RequestDeduplicator(ttl);\n }\n\n // 5. Rate limiting\n if (this.defaults.rateLimit) {\n this.rateLimiter = new RateLimiter(\n this.defaults.rateLimit.maxRequests,\n this.defaults.rateLimit.interval,\n );\n }\n\n // 6. Authentication\n this.authConfig = this.defaults.auth;\n if (this.authConfig) {\n // Register a request interceptor that applies auth to every request\n this.interceptors.request.use(createAuthInterceptor(this.authConfig));\n\n // If bearer auth with refresh, register a response-error interceptor\n if (\n this.authConfig.type === 'bearer' &&\n this.authConfig.refreshToken\n ) {\n this.interceptors.response.use(\n ((res: HttixResponse<unknown>) => res) as ResponseInterceptor<unknown>,\n createAuthRefreshHandler(this.authConfig),\n );\n }\n }\n\n // 7. Pending abort controllers for cancelAll()\n this.pendingControllers = new Set();\n\n // 8. Stream helpers (bound methods)\n this.stream = {\n sse: this.executeSSE.bind(this),\n ndjson: this.executeNDJSON.bind(this),\n };\n\n // 9. Pagination helper\n this.paginate = createPaginator(this) as HttixClientInterface['paginate'];\n }\n\n // =========================================================================\n // Core request method\n // =========================================================================\n\n async request<T = unknown>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n // 1. Deep-merge per-request config with client defaults\n const mergedConfig = deepMergeConfig(\n this.defaults,\n config,\n ) as HttixRequestConfig;\n\n // 2. Assign (or preserve) a request ID for tracing\n mergedConfig.requestId = config.requestId ?? generateRequestId();\n\n // 3. Set up cancellation tracking for this request\n const cancelController = new AbortController();\n this.pendingControllers.add(cancelController);\n\n const signals: AbortSignal[] = [cancelController.signal];\n if (mergedConfig.signal) {\n signals.unshift(mergedConfig.signal);\n }\n const combinedSignal = combineSignals(...signals);\n mergedConfig.signal = combinedSignal;\n\n try {\n // 4. Execute the request lifecycle wrapped in middleware\n const context: MiddlewareContext<HttixRequestConfig, HttixResponse<T>> = {\n request: mergedConfig,\n };\n\n let httixResponse!: HttixResponse<T>;\n\n const composed = composeMiddleware(this.middlewares);\n\n await composed(context, async () => {\n // ---- Handler: everything inside middleware's \"next()\" ----\n\n // a. Run request interceptors\n let processedConfig = await runRequestInterceptors(\n context.request,\n this.interceptors.request,\n );\n // Keep context in sync so post-middleware code sees the final config\n context.request = processedConfig;\n\n // b. Auth is handled via interceptors (registered in constructor),\n // but we also support calling applyAuth here for edge cases where\n // a per-request auth override is needed. In normal usage the\n // interceptor already applied auth, so this is a no-op.\n\n // c. Execute with deduplication and rate limiting\n httixResponse = await this.executeWithDedupAndRateLimit<T>(\n processedConfig,\n );\n\n // d. Store response on context for middleware post-processing\n context.response = httixResponse;\n });\n\n return httixResponse;\n } finally {\n this.pendingControllers.delete(cancelController);\n }\n }\n\n // =========================================================================\n // HTTP method shortcuts\n // =========================================================================\n\n async get<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'GET' });\n }\n\n async post<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'POST', body });\n }\n\n async put<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'PUT', body });\n }\n\n async patch<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'PATCH', body });\n }\n\n async delete<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return this.request<T>({ ...config, url, method: 'DELETE' });\n }\n\n async head(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return this.request<void>({ ...config, url, method: 'HEAD' });\n }\n\n async options(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return this.request<void>({ ...config, url, method: 'OPTIONS' });\n }\n\n // =========================================================================\n // Middleware registration\n // =========================================================================\n\n use<T = unknown>(middleware: MiddlewareFn<T>): void {\n this.middlewares.push(middleware as MiddlewareFn);\n }\n\n // =========================================================================\n // Client factory — clone with overrides\n // =========================================================================\n\n create(overrides?: Partial<HttixConfig>): HttixClientInterface {\n const mergedDefaults = deepMergeConfig(\n this.defaults,\n overrides ?? {},\n ) as HttixConfig;\n return new HttixClientImpl(mergedDefaults);\n }\n\n // =========================================================================\n // Cancellation\n // =========================================================================\n\n /**\n * Abort every in-flight request managed by this client.\n */\n cancelAll(reason = 'All requests cancelled'): void {\n for (const controller of this.pendingControllers) {\n controller.abort(new HttixAbortError(reason));\n }\n this.pendingControllers.clear();\n }\n\n /**\n * Check whether an error is a cancellation (abort) error.\n */\n isCancel(error: unknown): error is HttixAbortError {\n return error instanceof HttixAbortError;\n }\n\n // =========================================================================\n // Private — dedup & rate-limit wrapper\n // =========================================================================\n\n /**\n * Wraps the actual fetch in deduplication and rate-limiting layers.\n */\n private async executeWithDedupAndRateLimit<T>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n const doRequest = (): Promise<HttixResponse<T>> =>\n this.doFetch<T>(config);\n\n // Rate limiting\n const throttledRequest = this.rateLimiter\n ? (): Promise<HttixResponse<T>> =>\n this.rateLimiter!.throttle(config.url, doRequest) as Promise<\n HttixResponse<T>\n >\n : doRequest;\n\n // Deduplication\n if (this.deduplicator && this.isDedupEnabled()) {\n const key = this.generateDedupKey(config);\n return this.deduplicator.dedup<HttixResponse<T>>(key, throttledRequest);\n }\n\n return throttledRequest();\n }\n\n private isDedupEnabled(): boolean {\n if (this.dedupConfig === false || this.dedupConfig === undefined) {\n return false;\n }\n if (this.dedupConfig === true) {\n return true;\n }\n return this.dedupConfig.enabled;\n }\n\n private generateDedupKey(config: HttixRequestConfig): string {\n if (\n typeof this.dedupConfig === 'object' &&\n this.dedupConfig.generateKey\n ) {\n return this.dedupConfig.generateKey(config);\n }\n return this.deduplicator!.generateKey(config);\n }\n\n // =========================================================================\n // Private — core fetch with retry, response processing & error handling\n // =========================================================================\n\n /**\n * Build the native Request, execute fetch with retry support, parse the\n * response body, and handle success / error paths.\n */\n private async doFetch<T>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n // retryRequest handles the retry loop. The inner fn is called per-attempt\n // so that a fresh Request is built each time (body streams can only be\n // consumed once).\n return retryRequest<T>(\n async (): Promise<HttixResponse<T>> => {\n // Build the native Request (includes timeout setup)\n const {\n request: fetchRequest,\n timeoutController,\n timeoutId,\n } = buildRequest(config);\n\n const startTime = Date.now();\n\n let rawResponse: Response;\n\n try {\n rawResponse = await fetch(fetchRequest);\n } catch (error) {\n // Distinguish timeout from user-initiated abort from network errors.\n // Check user signal first (user cancel takes priority).\n const isUserAbort = config.signal?.aborted === true;\n const isTimeout =\n timeoutController?.signal?.aborted === true && !isUserAbort;\n\n // Always clean up the timeout timer\n clearTimeoutSignal(timeoutController, timeoutId);\n\n if (isUserAbort) {\n throw new HttixAbortError('Request was aborted', config);\n }\n\n if (isTimeout) {\n /* v8 ignore next */\n throw new HttixTimeoutError(config.timeout ?? 0, config);\n }\n\n // Network / CORS / DNS error\n throw new HttixRequestError(\n error instanceof Error ? error.message : 'Network request failed',\n {\n message: 'Network request failed',\n config,\n cause: error instanceof Error ? error : undefined,\n },\n );\n }\n\n // Request succeeded at the transport level — clean up timeout\n clearTimeoutSignal(timeoutController, timeoutId);\n\n // Parse response body\n const data = await parseResponseBody<T>(rawResponse, config);\n const timing = Date.now() - startTime;\n\n return createResponse<T>(rawResponse, config, data, timing);\n },\n config.retry,\n config,\n ).then((response) => this.processResponse<T>(response, config));\n }\n\n /**\n * Post-retry response processing:\n * - 2xx → run response interceptors\n * - non-2xx + throwOnError → run error interceptors, then throw\n * - non-2xx + !throwOnError → return as-is\n */\n private async processResponse<T>(\n response: HttixResponse<T>,\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n // ---------- 2xx success ----------\n if (response.ok) {\n return runResponseInterceptors<T>(\n response,\n this.interceptors.response as unknown as InterceptorManagerInterface<\n ResponseInterceptor<T>,\n ResponseErrorInterceptor\n >,\n );\n }\n\n // ---------- non-2xx ----------\n // If throwOnError is explicitly false, return the response as-is.\n if (config.throwOnError === false) {\n return response;\n }\n\n // Default: throw on non-2xx\n const error = new HttixResponseError(\n response.status,\n response.statusText,\n response.data,\n response.headers,\n config,\n );\n\n // Give response-error interceptors a chance to recover\n try {\n const recovered = await runResponseErrorInterceptors(\n error,\n this.interceptors.response,\n );\n return recovered as HttixResponse<T>;\n } catch {\n // No interceptor recovered the error — re-throw the original\n throw error;\n }\n }\n\n // =========================================================================\n // Private — stream helpers\n // =========================================================================\n\n /**\n * Execute an SSE stream request.\n *\n * Applies interceptors and auth, then returns an async iterable of\n * SSEEvent objects by piping the response body through parseSSE().\n */\n private async *executeSSE(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): AsyncGenerator<SSEEvent, void, undefined> {\n const mergedConfig = deepMergeConfig(this.defaults, {\n ...config,\n url,\n method: 'GET',\n }) as HttixRequestConfig;\n\n let processedConfig = await runRequestInterceptors(\n mergedConfig,\n this.interceptors.request,\n );\n\n if (this.authConfig) {\n processedConfig = await applyAuth(processedConfig, this.authConfig);\n }\n\n const { request: fetchRequest, timeoutController, timeoutId } =\n buildRequest(processedConfig);\n\n // SSE connections are long-lived; use a generous timeout or respect the\n // caller's explicit timeout. Disable default timeout for SSE if not set.\n if (processedConfig.timeout === this.defaults.timeout && processedConfig.timeout !== 0) {\n // Keep the SSE connection open — don't impose a short timeout\n }\n\n try {\n const rawResponse = await fetch(fetchRequest);\n\n clearTimeoutSignal(timeoutController, timeoutId);\n\n if (!rawResponse.ok) {\n const error = new HttixResponseError(\n rawResponse.status,\n rawResponse.statusText,\n null,\n rawResponse.headers,\n processedConfig,\n );\n throw error;\n }\n\n if (!rawResponse.body) {\n throw new HttixRequestError('Response body is null — cannot parse SSE stream', {\n message: 'Response body is null',\n config: processedConfig,\n });\n }\n\n yield* parseSSE(rawResponse.body);\n } catch (error) {\n clearTimeoutSignal(timeoutController, timeoutId);\n throw error;\n }\n }\n\n /**\n * Execute an NDJSON stream request.\n *\n * Applies interceptors and auth, then returns an async iterable of parsed\n * JSON objects by piping the response body through parseNDJSON().\n */\n private async *executeNDJSON<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): AsyncGenerator<T, void, undefined> {\n const mergedConfig = deepMergeConfig(this.defaults, {\n ...config,\n url,\n method: 'GET',\n }) as HttixRequestConfig;\n\n let processedConfig = await runRequestInterceptors(\n mergedConfig,\n this.interceptors.request,\n );\n\n if (this.authConfig) {\n processedConfig = await applyAuth(processedConfig, this.authConfig);\n }\n\n const { request: fetchRequest, timeoutController, timeoutId } =\n buildRequest(processedConfig);\n\n try {\n const rawResponse = await fetch(fetchRequest);\n\n clearTimeoutSignal(timeoutController, timeoutId);\n\n if (!rawResponse.ok) {\n const error = new HttixResponseError(\n rawResponse.status,\n rawResponse.statusText,\n null,\n rawResponse.headers,\n processedConfig,\n );\n throw error;\n }\n\n if (!rawResponse.body) {\n throw new HttixRequestError(\n 'Response body is null — cannot parse NDJSON stream',\n {\n message: 'Response body is null',\n config: processedConfig,\n },\n );\n }\n\n yield* parseNDJSON<T>(rawResponse.body);\n } catch (error) {\n clearTimeoutSignal(timeoutController, timeoutId);\n throw error;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory function\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new HttixClient with the given configuration.\n *\n * This is the recommended entry-point for creating client instances.\n *\n * @example\n * ```ts\n * import { createHttix } from 'httix';\n *\n * const client = createHttix({\n * baseURL: 'https://api.example.com',\n * headers: { 'X-App-Version': '1.0' },\n * auth: { type: 'bearer', token: 'my-token' },\n * });\n *\n * const { data } = await client.get('/users');\n * ```\n */\nexport function createHttix(\n config?: Partial<HttixConfig>,\n): HttixClientInterface {\n return new HttixClientImpl(config);\n}\n","/**\n * httix — Cancellation / abort utilities\n */\n\nimport type { HttixRequestConfig } from '../core/types';\nimport { HttixAbortError } from '../core/errors';\n\n/**\n * A cancellation token wraps an AbortController, exposing its signal and\n * a promise that rejects when the token is cancelled.\n */\nexport interface CancelToken {\n signal: AbortSignal;\n promise: Promise<never>;\n}\n\n/**\n * Create a new cancel token and its associated cancel function.\n *\n * The returned `cancel` function triggers the underlying AbortController,\n * causing the `signal` to abort and the `promise` to reject.\n */\nexport function createCancelToken(): { token: CancelToken; cancel: (reason?: string) => void } {\n const controller = new AbortController();\n\n let rejectFn: (reason: unknown) => void;\n const promise = new Promise<never>((_, reject) => {\n rejectFn = reject;\n });\n\n const token: CancelToken = {\n signal: controller.signal,\n promise,\n };\n\n const cancel = (reason?: string): void => {\n const error = new HttixAbortError(reason);\n controller.abort(error);\n rejectFn!(error);\n };\n\n return { token, cancel };\n}\n\n/**\n * Check whether an error is a cancellation (abort) error.\n */\nexport function isCancel(error: unknown): boolean {\n return error instanceof HttixAbortError;\n}\n\n/**\n * Create a new HttixAbortError, typically used when a request is\n * cancelled programmatically.\n */\nexport function createCancelError(reason?: string, config?: HttixRequestConfig): HttixAbortError {\n return new HttixAbortError(reason, config);\n}\n","/**\n * httix — Timeout management via AbortController\n */\n\nimport type { HttixRequestConfig } from '../core/types';\nimport { HttixTimeoutError } from '../core/errors';\n\n/**\n * WeakMap that associates an AbortController with its timeout timer ID,\n * allowing the timer to be cleared later without leaking memory.\n */\nexport const timeoutTimers = new WeakMap<AbortController, ReturnType<typeof setTimeout>>();\n\n/**\n * Create an AbortController that will automatically abort after the\n * specified timeout. The abort reason is set to a HttixTimeoutError.\n *\n * If timeout is 0 or negative, the controller will never abort.\n */\nexport function createTimeoutController(\n timeout: number,\n config: HttixRequestConfig,\n): AbortController {\n const controller = new AbortController();\n\n if (timeout <= 0) {\n // No timeout — controller will never abort\n return controller;\n }\n\n const timerId = setTimeout(() => {\n const error = new HttixTimeoutError(timeout, config);\n controller.abort(error);\n }, timeout);\n\n timeoutTimers.set(controller, timerId);\n\n return controller;\n}\n\n/**\n * Clear a pending timeout timer on an AbortController, preventing it from\n * firing if the request completes before the timeout.\n */\nexport function clearTimeoutController(controller: AbortController): void {\n const timerId = timeoutTimers.get(controller);\n if (timerId !== undefined) {\n clearTimeout(timerId);\n timeoutTimers.delete(controller);\n }\n}\n","/**\n * httix — GET method factory\n *\n * Creates a standalone GET function bound to a client instance.\n * Useful for composition patterns where methods are passed around\n * independently of the client object.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create a GET method bound to the given client.\n *\n * @example\n * ```ts\n * const get = createGetMethod(client);\n * const { data } = await get<User[]>('/users');\n * ```\n */\nexport function createGetMethod(\n client: HttixClient,\n): HttixClient['get'] {\n return async function get<T = unknown>(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'GET',\n });\n };\n}\n","/**\n * httix — POST method factory\n *\n * Creates a standalone POST function bound to a client instance.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a POST method bound to the given client.\n *\n * @example\n * ```ts\n * const post = createPostMethod(client);\n * const { data } = await post<User>('/users', { name: 'Alice' });\n * ```\n */\nexport function createPostMethod(\n client: HttixClient,\n): HttixClient['post'] {\n return async function post<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'POST',\n body,\n });\n };\n}\n","/**\n * httix — PUT method factory\n *\n * Creates a standalone PUT function bound to a client instance.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a PUT method bound to the given client.\n *\n * @example\n * ```ts\n * const put = createPutMethod(client);\n * const { data } = await put<User>('/users/1', { name: 'Bob' });\n * ```\n */\nexport function createPutMethod(\n client: HttixClient,\n): HttixClient['put'] {\n return async function put<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'PUT',\n body,\n });\n };\n}\n","/**\n * httix — PATCH method factory\n *\n * Creates a standalone PATCH function bound to a client instance.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a PATCH method bound to the given client.\n *\n * @example\n * ```ts\n * const patch = createPatchMethod(client);\n * const { data } = await patch<User>('/users/1', { name: 'Charlie' });\n * ```\n */\nexport function createPatchMethod(\n client: HttixClient,\n): HttixClient['patch'] {\n return async function patch<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'PATCH',\n body,\n });\n };\n}\n","/**\n * httix — DELETE method factory\n *\n * Creates a standalone DELETE function bound to a client instance.\n * Supports an optional body (some APIs accept request bodies with DELETE).\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n RequestBody,\n} from '../core/types';\n\n/**\n * Create a DELETE method bound to the given client.\n *\n * @example\n * ```ts\n * const remove = createDeleteMethod(client);\n * const { data } = await remove<void>('/users/1');\n *\n * // With body (API-specific)\n * const { data } = await remove<void>('/batch', { ids: [1, 2, 3] });\n * ```\n */\nexport function createDeleteMethod(\n client: HttixClient,\n): (\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n) => Promise<HttixResponse<unknown>> {\n return async function remove<T = unknown>(\n url: string,\n body?: RequestBody,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<T>> {\n return client.request<T>({\n ...config,\n url,\n method: 'DELETE',\n ...(body !== undefined ? { body } : {}),\n });\n };\n}\n","/**\n * httix — HEAD method factory\n *\n * Creates a standalone HEAD function bound to a client instance.\n * HEAD requests must not have a body, so only headers and status are returned.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create a HEAD method bound to the given client.\n *\n * The response type is `void` because HEAD responses have no body.\n *\n * @example\n * ```ts\n * const head = createHeadMethod(client);\n * const { status, headers } = await head('/users/1');\n * if (status === 200) {\n * const contentLength = headers.get('content-length');\n * }\n * ```\n */\nexport function createHeadMethod(\n client: HttixClient,\n): HttixClient['head'] {\n return async function head(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return client.request<void>({\n ...config,\n url,\n method: 'HEAD',\n });\n };\n}\n","/**\n * httix — OPTIONS method factory\n *\n * Creates a standalone OPTIONS function bound to a client instance.\n * OPTIONS requests are typically used for CORS preflight or discovering\n * allowed methods on a resource.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create an OPTIONS method bound to the given client.\n *\n * The response type is `void` because OPTIONS responses typically have no body.\n *\n * @example\n * ```ts\n * const options = createOptionsMethod(client);\n * const { headers } = await options('/users/1');\n * const allow = headers.get('allow'); // e.g. \"GET, PUT, DELETE\"\n * ```\n */\nexport function createOptionsMethod(\n client: HttixClient,\n): HttixClient['options'] {\n return async function options(\n url: string,\n config?: Partial<HttixRequestConfig>,\n ): Promise<HttixResponse<void>> {\n return client.request<void>({\n ...config,\n url,\n method: 'OPTIONS',\n });\n };\n}\n","/**\n * httix — Generic request method factory\n *\n * Creates a standalone request function bound to a client instance.\n * This is the lowest-level factory — the caller provides the full\n * HttixRequestConfig including method, url, headers, body, etc.\n */\n\nimport type {\n HttixClient,\n HttixResponse,\n HttixRequestConfig,\n} from '../core/types';\n\n/**\n * Create a generic request method bound to the given client.\n *\n * @example\n * ```ts\n * const request = createRequestMethod(client);\n * const { data } = await request<User>({ url: '/users/1', method: 'GET' });\n * ```\n */\nexport function createRequestMethod(\n client: HttixClient,\n): HttixClient['request'] {\n return async function request<T = unknown>(\n config: HttixRequestConfig,\n ): Promise<HttixResponse<T>> {\n return client.request<T>(config);\n };\n}\n"],"mappings":"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","names":["src_exports","__export","DEFAULT_CONFIG","DEFAULT_HEADERS","DEFAULT_REQUEST_CONFIG","DEFAULT_RETRY","DEFAULT_TIMEOUT","HttixAbortError","HttixClientImpl","HttixError","HttixRequestError","HttixResponseError","HttixRetryError","HttixTimeoutError","InterceptorManager","RateLimiter","RequestDeduplicator","applyAuth","clearTimeoutController","composeMiddleware","createAuthInterceptor","createAuthRefreshHandler","createCancelError","createCancelToken","createDeleteMethod","createGetMethod","createHeadMethod","createHttix","createOptionsMethod","createPaginator","createPatchMethod","createPostMethod","createProgressReader","createPutMethod","createRequestMethod","createTimeoutController","src_default","isCancel","parseLinkHeader","parseNDJSON","parseRetryAfter","parseSSE","retryRequest","__toCommonJS","DEFAULT_RETRY","DEFAULT_TIMEOUT","DEFAULT_HEADERS","DEFAULT_REQUEST_CONFIG","DEFAULT_CONFIG","HttixError","message","options","ErrorConstructor","HttixRequestError","HttixResponseError","status","statusText","data","headers","config","HttixTimeoutError","timeout","HttixAbortError","reason","HttixRetryError","attempts","lastError","buildRequest","config","url","buildUrl","headers","mergeHeaders","DEFAULT_HEADERS","body","serializeBody","requestInit","timeout","timeoutController","timeoutId","combineSignals","clearTimeoutSignal","_controller","signals","controller","signal","baseURL","params","query","full","base","path","key","value","separator","encodeQueryParams","parts","item","defaults","custom","merged","applyHeaders","target","source","createResponse","raw","config","data","timing","parseResponseBody","response","contentType","parseWithType","autoParse","responseType","lowerCt","text","InterceptorManager","fulfilled","rejected","id","runRequestInterceptors","config","interceptors","currentConfig","handler","err","result","runResponseInterceptors","response","currentResponse","runResponseErrorInterceptors","error","delay","ms","resolve","generateRequestId","calculateDelay","attempt","backoff","baseDelay","maxDelay","jitter","calculated","SAFE_METHODS","parseRetryAfter","value","seconds","date","diff","retryRequest","fn","config","requestConfig","retryCfg","DEFAULT_RETRY","maxAttempts","method","lastError","attempt","response","responseError","HttixResponseError","shouldRetry","retryAfterMs","backoffMs","calculateDelay","finalDelay","delay","err","httixErr","error","HttixRequestError","RequestDeduplicator","ttl","key","requestFn","cached","inflight","promise","result","error","config","url","sortedQuery","k","RateLimiter","maxRequests","interval","key","requestFn","count","resolve","result","queue","toProcess","item","timer","composeMiddleware","middlewares","ctx","next","index","dispatch","fn","resolveValue","value","cloneConfig","config","applyAuth","authConfig","result","headers","key","query","token","credentials","encoded","createAuthInterceptor","createAuthRefreshHandler","_error","refreshPromise","error","HttixResponseError","originalConfig","newToken","refreshError","retryConfig","retryHeaders","parseLinkHeader","linkHeader","result","parts","part","trimmed","urlMatch","url","relMatch","rel","createPaginator","client","config","pagination","style","pageSize","maxPages","offsetParam","limitParam","cursorParam","cursorExtractor","linkExtractor","dataExtractor","stopCondition","currentUrl","offset","cursor","pageCount","requestConfig","response","pageData","parseSSE","stream","reader","decoder","buffer","done","value","parts","part","event","parseSSEEvent","block","lines","fields","dataLines","line","colonIndex","field","parseNDJSON","trimmed","remaining","createProgressReader","body","onProgress","total","loaded","controller","percent","err","mergeHeaders","defaults","custom","merged","addHeadersToInstance","addHeadersToInstance","target","source","value","key","deepMergeConfig","target","source","result","key","sourceVal","targetVal","mergeHeaders","mergeQueryParams","deepMergePlainObjects","combineSignals","signals","controller","signal","HttixClientImpl","_HttixClientImpl","config","deepMergeConfig","DEFAULT_CONFIG","InterceptorManager","ttl","RequestDeduplicator","RateLimiter","createAuthInterceptor","res","createAuthRefreshHandler","createPaginator","mergedConfig","generateRequestId","cancelController","combinedSignal","context","httixResponse","composeMiddleware","processedConfig","runRequestInterceptors","url","body","middleware","overrides","mergedDefaults","reason","HttixAbortError","error","doRequest","throttledRequest","key","retryRequest","fetchRequest","timeoutController","timeoutId","buildRequest","startTime","rawResponse","isUserAbort","isTimeout","clearTimeoutSignal","HttixTimeoutError","HttixRequestError","data","parseResponseBody","timing","createResponse","response","runResponseInterceptors","HttixResponseError","runResponseErrorInterceptors","applyAuth","parseSSE","parseNDJSON","createHttix","createCancelToken","controller","rejectFn","promise","_","reject","reason","error","HttixAbortError","isCancel","createCancelError","config","timeoutTimers","createTimeoutController","timeout","config","controller","timerId","error","HttixTimeoutError","clearTimeoutController","createGetMethod","client","url","config","createPostMethod","client","url","body","config","createPutMethod","client","url","body","config","createPatchMethod","client","url","body","config","createDeleteMethod","client","url","body","config","createHeadMethod","client","url","config","createOptionsMethod","client","url","config","createRequestMethod","client","config","defaultClient","HttixClientImpl","httix","config","isCancel","src_default"]}