arthron 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -48
- package/dist/index.cjs +679 -261
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +306 -83
- package/dist/index.d.mts +306 -83
- package/dist/index.mjs +679 -262
- package/dist/index.mjs.map +1 -1
- package/llms.txt +46 -30
- package/package.json +2 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/body.ts","../src/error.ts","../src/headers.ts","../src/pipeline.ts","../src/stream.ts","../src/promise.ts","../src/url.ts","../src/client.ts","../src/define.ts","../src/plugins/logging.ts","../src/plugins/retry.ts","../src/plugins/timeout.ts"],"sourcesContent":["type Serialized = {\n body: BodyInit | undefined;\n headers: Record<string, string>;\n};\n\nconst RAW_CTORS = [\n \"FormData\",\n \"Blob\",\n \"ArrayBuffer\",\n \"URLSearchParams\",\n \"ReadableStream\",\n] as const;\n\n/** Bodies fetch already knows how to send. Content-Type is left to the caller / runtime. */\nfunction isRawBody(body: unknown): body is BodyInit {\n if (typeof body === \"string\") return true;\n if (ArrayBuffer.isView(body)) return true;\n return RAW_CTORS.some((name) => {\n const ctor = (globalThis as Record<string, unknown>)[name];\n return typeof ctor === \"function\" && body instanceof ctor;\n });\n}\n\n/**\n * Turn a caller-supplied body into something fetch accepts. Raw bodies pass\n * through untouched; anything else is JSON with `content-type` set — unless\n * the caller already set one (headers arrive lowercased, so a plain lookup is\n * enough).\n */\nexport function serializeBody(\n body: unknown,\n headers: Record<string, string>,\n): Serialized {\n if (body === undefined) return { body: undefined, headers };\n if (isRawBody(body)) return { body, headers };\n const withType =\n \"content-type\" in headers\n ? headers\n : { ...headers, \"content-type\": \"application/json\" };\n return { body: JSON.stringify(body), headers: withType };\n}\n","import type { RequestContext } from \"./types\";\n\nexport type ErrorMessageResolver = (\n data: unknown,\n response: Response,\n) => string | undefined;\n\ntype ArthronErrorInit = {\n message: string;\n status: number;\n statusText: string;\n headers: Headers;\n data: unknown;\n request: RequestContext;\n response?: Response;\n cause?: unknown;\n};\n\n/**\n * The only error arthron itself produces. Two sources: a response with\n * `ok === false`, or fetch rejecting outright (network failure, `status` 0).\n * Everything else — cancellation, interceptor bugs — is rethrown untouched.\n */\nexport class ArthronError extends Error {\n override readonly name = \"ArthronError\";\n /** HTTP status of the failed response; `0` when fetch itself failed (network). */\n readonly status: number;\n readonly statusText: string;\n /** Response headers; empty for network failures. */\n readonly headers: Headers;\n /** Parsed body: JSON if it parses, else the text, else `undefined`. */\n readonly data: unknown;\n /** The context that was sent — url and init after request interceptors. */\n readonly request: RequestContext;\n /** The original Response, still readable (the body was parsed from a clone). Absent for network failures. */\n readonly response: Response | undefined;\n /** The underlying error for network failures. */\n override readonly cause: unknown;\n\n constructor(init: ArthronErrorInit) {\n super(init.message);\n this.status = init.status;\n this.statusText = init.statusText;\n this.headers = init.headers;\n this.data = init.data;\n this.request = init.request;\n this.response = init.response;\n this.cause = init.cause;\n }\n}\n\n/** `true` for errors arthron produced: a `!ok` response or a network failure. Cancellations and plugin bugs are not ArthronErrors. */\nexport function isArthronError(error: unknown): error is ArthronError {\n return error instanceof ArthronError;\n}\n\n/** Cancellation is not an HTTP failure. Matched by name so it works across realms. */\nexport function isCancellation(error: unknown): boolean {\n const name = (error as { name?: unknown } | null | undefined)?.name;\n return name === \"AbortError\" || name === \"TimeoutError\";\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\n/** `message` → `error` (string) → `error.message` → `detail`. */\nexport function defaultErrorMessage(data: unknown): string | undefined {\n if (!isRecord(data)) return undefined;\n if (typeof data.message === \"string\") return data.message;\n if (typeof data.error === \"string\") return data.error;\n if (isRecord(data.error) && typeof data.error.message === \"string\") {\n return data.error.message;\n }\n if (typeof data.detail === \"string\") return data.detail;\n return undefined;\n}\n\n/** Body as JSON if it parses, else as text, else `undefined` when empty. */\nasync function readBody(response: Response): Promise<unknown> {\n const text = await response.text().catch(() => \"\");\n if (text === \"\") return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nexport async function responseError(\n response: Response,\n request: RequestContext,\n resolve: ErrorMessageResolver = defaultErrorMessage,\n): Promise<ArthronError> {\n // Read from a clone so `error.response` stays usable by the caller.\n const data = await readBody(response.clone());\n return new ArthronError({\n message:\n resolve(data, response) ??\n `Request failed with status ${response.status}`,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n data,\n request,\n response,\n });\n}\n\nexport function networkError(\n cause: unknown,\n request: RequestContext,\n): ArthronError {\n return new ArthronError({\n message: cause instanceof Error ? cause.message : \"Network error\",\n status: 0,\n statusText: \"\",\n headers: new Headers(),\n data: undefined,\n request,\n cause,\n });\n}\n","/**\n * Normalize any `HeadersInit` (plain object, `Headers`, tuple array) into a\n * plain record. Keys come back lowercased — `Headers` does that for us.\n */\nexport function toHeaderRecord(\n headers: HeadersInit | undefined,\n): Record<string, string> {\n if (!headers) return {};\n return Object.fromEntries(new Headers(headers).entries());\n}\n\n/**\n * Layer `override` on top of `base`. Names are compared case-insensitively and\n * the override wins, so a caller's `content-type` replaces a default\n * `Content-Type` instead of fetch sending both values joined.\n */\nexport function mergeHeaders(\n base: HeadersInit | undefined,\n override: HeadersInit | undefined,\n): Record<string, string> {\n return { ...toHeaderRecord(base), ...toHeaderRecord(override) };\n}\n","import { isArthronError } from \"./error\";\nimport { toHeaderRecord } from \"./headers\";\nimport type {\n ErrorInterceptor,\n Middleware,\n Plugin,\n RequestContext,\n RequestInterceptor,\n ResponseInterceptor,\n} from \"./types\";\n\n/**\n * Interceptors mutate the context in place. A middleware that calls `next`\n * again (retry) must not see the previous attempt's changes, so every attempt\n * starts from a fresh copy.\n */\nfunction cloneContext({ url, init }: RequestContext): RequestContext {\n return { url, init: { ...init, headers: toHeaderRecord(init.headers) } };\n}\n\n/**\n * Owns the order of one request.\n *\n * Middleware wraps the whole call, outermost first in registration order.\n * Each attempt below it runs request interceptors → `send` → response\n * interceptors. Only an `ArthronError` reaches the error interceptors; whatever\n * they return is thrown. Anything else that is thrown — cancellation, a bug\n * in a plugin — propagates untouched.\n */\nexport async function runPipeline(\n plugins: readonly Plugin[],\n ctx: RequestContext,\n send: (ctx: RequestContext) => Promise<Response>,\n): Promise<Response> {\n const middlewares: Middleware[] = [];\n const request: RequestInterceptor[] = [];\n const response: ResponseInterceptor[] = [];\n const error: ErrorInterceptor[] = [];\n for (const plugin of plugins) {\n if (plugin.middleware) middlewares.push(plugin.middleware);\n if (plugin.request) request.push(plugin.request);\n if (plugin.response) response.push(plugin.response);\n if (plugin.error) error.push(plugin.error);\n }\n\n const attempt = async (input: RequestContext): Promise<Response> => {\n let current = cloneContext(input);\n try {\n for (const interceptor of request) current = await interceptor(current);\n let res = await send(current);\n for (const interceptor of response) res = await interceptor(res, current);\n return res;\n } catch (thrown) {\n if (!isArthronError(thrown)) throw thrown;\n let err = thrown;\n for (const interceptor of error) err = await interceptor(err, current);\n throw err;\n }\n };\n\n const dispatch = (\n index: number,\n input: RequestContext,\n ): Promise<Response> => {\n const middleware = middlewares[index];\n if (!middleware) return attempt(input);\n return middleware(input, (next) => dispatch(index + 1, next));\n };\n return dispatch(0, ctx);\n}\n","/** One server-sent event, as described by the WHATWG EventSource spec. */\nexport type SseEvent = {\n /** The `event:` field, when the server sent one. */\n event?: string;\n /** All `data:` lines of the block, joined with `\\n`. */\n data: string;\n /** The `id:` field, when present. */\n id?: string;\n /** The `retry:` field in ms, when present and numeric. */\n retry?: number;\n};\n\n/** Yield the body line by line, reassembling lines split across chunks. */\nasync function* lines(response: Response): AsyncGenerator<string> {\n if (!response.body) return;\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n while (true) {\n const { value, done } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n const parts = buffer.split(/\\r\\n|\\r|\\n/);\n buffer = parts.pop() ?? \"\";\n for (const line of parts) yield line;\n if (done) break;\n }\n if (buffer) yield buffer;\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Parse a `text/event-stream` body into events. Follows the spec: a blank\n * line dispatches, `data:` lines are joined with `\\n`, one leading space\n * after the colon is dropped, lines starting with `:` are comments, and a\n * block without `data` is not dispatched. Provider sentinels like\n * `[DONE]` are passed through untouched — they are not part of the spec.\n */\nexport async function* parseSse(response: Response): AsyncGenerator<SseEvent> {\n let data: string[] = [];\n let event: string | undefined;\n let id: string | undefined;\n let retry: number | undefined;\n\n const flush = (): SseEvent | undefined => {\n if (data.length === 0) {\n event = id = retry = undefined;\n return undefined;\n }\n const out: SseEvent = { data: data.join(\"\\n\") };\n if (event !== undefined) out.event = event;\n if (id !== undefined) out.id = id;\n if (retry !== undefined) out.retry = retry;\n data = [];\n event = id = retry = undefined;\n return out;\n };\n\n for await (const line of lines(response)) {\n if (line === \"\") {\n const out = flush();\n if (out) yield out;\n continue;\n }\n if (line.startsWith(\":\")) continue;\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n switch (field) {\n case \"data\":\n data.push(value);\n break;\n case \"event\":\n event = value;\n break;\n case \"id\":\n id = value;\n break;\n case \"retry\": {\n const ms = Number(value);\n if (Number.isInteger(ms) && ms >= 0) retry = ms;\n break;\n }\n default:\n break; // unknown fields are ignored, per spec\n }\n }\n const out = flush();\n if (out) yield out;\n}\n\n/**\n * Parse newline-delimited JSON. Blank lines are skipped; a malformed line\n * rejects the iteration with the `SyntaxError` from `JSON.parse`.\n */\nexport async function* parseNdjson<T = unknown>(\n response: Response,\n): AsyncGenerator<T> {\n for await (const line of lines(response)) {\n if (line.trim() === \"\") continue;\n yield JSON.parse(line) as T;\n }\n}\n","import { parseNdjson, parseSse } from \"./stream\";\nimport type { ArthronPromise } from \"./types\";\n\n/** Defer the Response until iteration starts, so the helper itself never rejects. */\nfunction iterate<T>(\n promise: Promise<Response>,\n parse: (res: Response) => AsyncGenerator<T>,\n): AsyncIterable<T> {\n return {\n async *[Symbol.asyncIterator]() {\n yield* parse(await promise);\n },\n };\n}\n\n/**\n * Sugar over `Promise<Response>`: `.json()` is `(await p).json()`. Awaiting\n * without a helper still yields the untouched `Response`.\n */\nexport function toArthronPromise(promise: Promise<Response>): ArthronPromise {\n return Object.assign(promise, {\n json: <T = unknown>() => promise.then((res) => res.json() as Promise<T>),\n text: () => promise.then((res) => res.text()),\n blob: () => promise.then((res) => res.blob()),\n arrayBuffer: () => promise.then((res) => res.arrayBuffer()),\n formData: () => promise.then((res) => res.formData()),\n sse: () => iterate(promise, parseSse),\n ndjson: <T = unknown>() => iterate(promise, parseNdjson<T>),\n });\n}\n","export type QueryParams = Record<\n string,\n string | number | boolean | null | undefined\n>;\n\nconst ABSOLUTE_URL = /^[a-z][a-z0-9+.-]*:\\/\\//i;\n\nexport function isAbsoluteUrl(path: string): boolean {\n return ABSOLUTE_URL.test(path);\n}\n\nfunction toQueryString(params: QueryParams | undefined): string {\n if (!params) return \"\";\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value === null || value === undefined) continue;\n search.append(key, String(value));\n }\n return search.toString();\n}\n\n/**\n * Join `baseURL` and `path` by plain string concatenation so a path prefix in\n * the base (`/v1`) survives a leading slash in the path. WHATWG `new URL()`\n * would drop it. Absolute paths skip the base entirely.\n */\nexport function resolveUrl(\n baseURL: string | undefined,\n path: string,\n params?: QueryParams,\n): string {\n let url: string;\n if (isAbsoluteUrl(path)) {\n url = path;\n } else {\n if (baseURL === undefined) {\n throw new TypeError(\n `arthron: relative path \"${path}\" needs a baseURL — pass baseURL in arthron({ baseURL }) or use an absolute URL`,\n );\n }\n url = `${baseURL.replace(/\\/+$/, \"\")}/${path.replace(/^\\/+/, \"\")}`;\n }\n const query = toQueryString(params);\n if (!query) return url;\n // The query goes before any #fragment, or the server never sees it.\n const hash = url.indexOf(\"#\");\n const [base, fragment] =\n hash === -1 ? [url, \"\"] : [url.slice(0, hash), url.slice(hash)];\n return `${base}${base.includes(\"?\") ? \"&\" : \"?\"}${query}${fragment}`;\n}\n","import { serializeBody } from \"./body\";\nimport { isCancellation, networkError, responseError } from \"./error\";\nimport { mergeHeaders, toHeaderRecord } from \"./headers\";\nimport { runPipeline } from \"./pipeline\";\nimport { toArthronPromise } from \"./promise\";\nimport type {\n Arthron,\n ArthronConfig,\n ArthronPromise,\n Plugin,\n RequestContext,\n RequestInitWithBody,\n RequestOptions,\n} from \"./types\";\nimport { resolveUrl } from \"./url\";\n\nconst BODYLESS_METHODS = new Set([\"GET\", \"HEAD\"]);\n\ntype Resolved = Omit<ArthronConfig, \"headers\" | \"use\"> & {\n headers: Record<string, string>;\n use: readonly Plugin[];\n};\n\n/** Normalize once so `extend` can merge headers and append plugins cheaply. */\nfunction resolveConfig(config: ArthronConfig): Resolved {\n const { headers, use, ...rest } = config;\n return { ...rest, headers: toHeaderRecord(headers), use: use ?? [] };\n}\n\n/**\n * Build a client from config. The result is immutable — `use` and `extend`\n * return new clients and never touch the one they were called on.\n */\nexport function arthron(config: ArthronConfig = {}): Arthron {\n const resolved = resolveConfig(config);\n\n /** The one place a failure becomes an ArthronError. Cancellation passes through. */\n const send = async (ctx: RequestContext): Promise<Response> => {\n // Resolved per call, not per client: a global patched after the client was\n // created (msw's `server.listen()`, for one) must still be honoured.\n const fetchImpl = resolved.fetch ?? globalThis.fetch;\n let res: Response;\n try {\n res = await fetchImpl(ctx.url, ctx.init);\n } catch (thrown) {\n if (isCancellation(thrown)) throw thrown;\n throw networkError(thrown, ctx);\n }\n if (!res.ok) throw await responseError(res, ctx, resolved.errorMessage);\n return res;\n };\n\n const dispatch = (\n path: string,\n method: string,\n rawBody: unknown,\n { params, headers: callHeaders, ...init }: RequestOptions,\n ): ArthronPromise => {\n try {\n if (rawBody !== undefined && BODYLESS_METHODS.has(method.toUpperCase())) {\n // fetch rejects these with a TypeError that would otherwise be mistaken for a network failure and retried.\n throw new TypeError(\n `arthron: ${method.toUpperCase()} requests cannot carry a body — send it as params (query) or switch to POST`,\n );\n }\n const url = resolveUrl(resolved.baseURL, path, params);\n const { body, headers } = serializeBody(\n rawBody,\n mergeHeaders(resolved.headers, callHeaders),\n );\n // Config credentials sit underneath so a per-call value wins, like every other option.\n const requestInit: RequestInit = {\n ...(resolved.credentials !== undefined && {\n credentials: resolved.credentials,\n }),\n ...init,\n method,\n headers,\n };\n if (body !== undefined) requestInit.body = body;\n return toArthronPromise(\n runPipeline(resolved.use, { url, init: requestInit }, send),\n );\n } catch (thrown) {\n // Argument errors (no baseURL, unserializable body) reject like everything else.\n return toArthronPromise(Promise.reject(thrown));\n }\n };\n\n const derive = (next: Partial<ArthronConfig>): Arthron => {\n const merged: ArthronConfig = {\n ...resolved,\n ...next,\n headers: mergeHeaders(resolved.headers, next.headers),\n use: [...resolved.use, ...(next.use ?? [])],\n };\n return arthron(merged);\n };\n\n return {\n get: (path, init = {}) => dispatch(path, \"GET\", undefined, init),\n delete: (path, init = {}) => dispatch(path, \"DELETE\", undefined, init),\n head: (path, init = {}) => dispatch(path, \"HEAD\", undefined, init),\n post: (path, body, init = {}) => dispatch(path, \"POST\", body, init),\n put: (path, body, init = {}) => dispatch(path, \"PUT\", body, init),\n patch: (path, body, init = {}) => dispatch(path, \"PATCH\", body, init),\n request: (path, init: RequestInitWithBody) => {\n const { method, body, ...rest } = init;\n if (!method) {\n return toArthronPromise(\n Promise.reject(\n new TypeError(\n 'arthron: request() needs init.method — e.g. request(path, { method: \"OPTIONS\" }); use get/post/... for the common verbs',\n ),\n ),\n );\n }\n return dispatch(path, method, body, rest);\n },\n use: (...plugins) => derive({ use: plugins }),\n extend: (next) => derive(next),\n };\n}\n","import type {\n ErrorInterceptor,\n Middleware,\n Plugin,\n RequestInterceptor,\n ResponseInterceptor,\n} from \"./types\";\n\n/*\n * Identity helpers. They do nothing at runtime; they exist so a plugin written\n * in its own file gets contextual typing without an explicit annotation.\n */\n\n/** Identity helper: gives a middleware written in its own file the right parameter types. */\nexport const defineMiddleware = (middleware: Middleware): Middleware =>\n middleware;\n\n/** Identity helpers for each interceptor kind — `defineInterceptor.request(fn)` etc. */\nexport const defineInterceptor = {\n request: (interceptor: RequestInterceptor): RequestInterceptor => interceptor,\n response: (interceptor: ResponseInterceptor): ResponseInterceptor =>\n interceptor,\n error: (interceptor: ErrorInterceptor): ErrorInterceptor => interceptor,\n};\n\n/** Identity helper: type-checks a plugin object literal without an annotation. */\nexport const definePlugin = (plugin: Plugin): Plugin => plugin;\n","import { isArthronError, isCancellation } from \"../error\";\nimport type { Plugin } from \"../types\";\n\ntype LogEventBase = { method: string; path: string };\nexport type LogEvent =\n | ({ phase: \"start\" } & LogEventBase)\n | ({ phase: \"success\"; status: number; ms: number } & LogEventBase)\n | ({\n phase: \"error\";\n /** HTTP status for an ArthronError (0 = network); undefined for anything else. */\n status: number | undefined;\n ms: number;\n error: unknown;\n } & LogEventBase);\n\nexport type LoggingOptions = {\n /** Default `true`. The library never reads `NODE_ENV` — pass `isDev` yourself. */\n enabled?: boolean;\n logger?: Pick<Console, \"log\" | \"error\">;\n /** Receive structured events instead of the default console lines. */\n onEvent?: (event: LogEvent) => void;\n /** Clock in ms. Injectable for tests. */\n now?: () => number;\n};\n\n/** Origin + pathname only — the query and userinfo tend to carry secrets. */\nfunction displayPath(url: string): string {\n try {\n const parsed = new URL(url);\n return `${parsed.origin}${parsed.pathname}`;\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nfunction consoleSink(logger: Pick<Console, \"log\" | \"error\">) {\n return (e: LogEvent) => {\n if (e.phase === \"start\") {\n logger.log(`[arthron] → ${e.method} ${e.path}`);\n } else if (e.phase === \"success\") {\n logger.log(`[arthron] ← ${e.method} ${e.path} ${e.status} ${e.ms}ms`);\n } else {\n logger.error(\n `[arthron] ✕ ${e.method} ${e.path} ${e.status ?? \"-\"} ${e.ms}ms`,\n );\n }\n };\n}\n\n/**\n * One event when a request starts, one when it settles, with status and\n * elapsed time. Wraps the whole call, so retries are included in the time.\n * Default output is a console line per event; pass `onEvent` to get the\n * structured event instead. Cancellations are not reported.\n */\nexport function logging(options: LoggingOptions = {}): Plugin {\n const {\n enabled = true,\n logger = console,\n onEvent,\n now = () => performance.now(),\n } = options;\n const emit = onEvent ?? consoleSink(logger);\n return {\n name: \"logging\",\n middleware: async (ctx, next) => {\n if (!enabled) return next(ctx);\n const method = ctx.init.method ?? \"GET\";\n const path = displayPath(ctx.url);\n const started = now();\n const ms = () => Math.round(now() - started);\n\n emit({ phase: \"start\", method, path });\n try {\n const res = await next(ctx);\n emit({ phase: \"success\", method, path, status: res.status, ms: ms() });\n return res;\n } catch (error) {\n if (!isCancellation(error)) {\n const status = isArthronError(error) ? error.status : undefined;\n emit({ phase: \"error\", method, path, status, ms: ms(), error });\n }\n throw error;\n }\n },\n };\n}\n","import { type ArthronError, isArthronError } from \"../error\";\nimport type { Plugin, RequestContext } from \"../types\";\n\nexport type RetryOptions = {\n /** Number of retries after the first attempt. Default 2 (3 requests total). */\n retries?: number;\n /** Statuses worth retrying. Network errors (status 0) always are. */\n retryOn?: readonly number[];\n /** Methods safe to repeat. Compared case-insensitively. */\n methods?: readonly string[];\n /** Backoff in ms for retry number `retry` (0-based). Default 300 · 2^retry. */\n delay?: (retry: number, error: ArthronError) => number;\n /** Injectable for tests. Default `setTimeout`; rejects with the abort reason. */\n sleep?: (ms: number, signal?: AbortSignal | null) => Promise<void>;\n /**\n * Longest `Retry-After` (ms) worth honouring. Beyond it the request is not\n * retried at all. Default 60 000. Also guards `setTimeout`'s 2^31-1 ms cap,\n * past which timers fire immediately.\n */\n maxRetryAfter?: number;\n};\n\nconst DEFAULT_RETRY_ON = [408, 429, 500, 502, 503, 504] as const;\nconst DEFAULT_METHODS = [\"GET\", \"HEAD\", \"OPTIONS\", \"PUT\", \"DELETE\"] as const;\nconst DEFAULT_MAX_RETRY_AFTER = 60_000;\n\nfunction defaultSleep(ms: number, signal?: AbortSignal | null): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/** `Retry-After` as ms — seconds or an HTTP-date. `undefined` when absent or unparsable. */\nfunction retryAfterMs(error: ArthronError): number | undefined {\n const value = error.headers.get(\"retry-after\")?.trim();\n if (!value) return undefined;\n const seconds = Number(value);\n if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1000);\n const at = Date.parse(value);\n if (Number.isNaN(at)) return undefined;\n return Math.max(0, at - Date.now());\n}\n\nfunction isStreamBody(ctx: RequestContext): boolean {\n return (\n typeof ReadableStream !== \"undefined\" &&\n ctx.init.body instanceof ReadableStream\n );\n}\n\n/**\n * Retry on network errors and the configured statuses by calling `next`\n * again — the whole attempt (request interceptors included) is re-run.\n * Only `ArthronError` is considered; cancellation and plugin bugs pass through.\n */\nexport function retry(options: RetryOptions = {}): Plugin {\n const {\n retries = 2,\n retryOn = DEFAULT_RETRY_ON,\n methods = DEFAULT_METHODS,\n delay = (retry) => 300 * 2 ** retry,\n sleep = defaultSleep,\n maxRetryAfter = DEFAULT_MAX_RETRY_AFTER,\n } = options;\n const allowed = new Set(methods.map((m) => m.toUpperCase()));\n\n return {\n name: \"retry\",\n middleware: async (ctx, next) => {\n const method = (ctx.init.method ?? \"GET\").toUpperCase();\n const eligible = allowed.has(method) && !isStreamBody(ctx);\n\n for (let attempt = 0; ; attempt += 1) {\n try {\n return await next(ctx);\n } catch (thrown) {\n if (!eligible || attempt >= retries) throw thrown;\n if (!isArthronError(thrown)) throw thrown;\n if (thrown.status !== 0 && !retryOn.includes(thrown.status)) {\n throw thrown;\n }\n if (ctx.init.signal?.aborted) throw thrown;\n const retryAfter = retryAfterMs(thrown);\n if (retryAfter !== undefined && retryAfter > maxRetryAfter) {\n throw thrown;\n }\n await sleep(retryAfter ?? delay(attempt, thrown), ctx.init.signal);\n }\n }\n },\n };\n}\n","import type { Plugin } from \"../types\";\n\n/**\n * Wrap `body` so the deadline keeps running until it is fully read, and so an\n * abort while reading surfaces as a stream error instead of a silent stall.\n */\nfunction guardBody(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n finish: () => void,\n): ReadableStream<Uint8Array> {\n const reader = body.getReader();\n return new ReadableStream<Uint8Array>({\n start(controller) {\n signal.addEventListener(\n \"abort\",\n () => {\n controller.error(signal.reason);\n reader.cancel(signal.reason).catch(() => {});\n },\n { once: true },\n );\n },\n async pull(controller) {\n const { value, done } = await reader.read();\n if (done) {\n finish();\n controller.close();\n return;\n }\n controller.enqueue(value);\n },\n cancel(reason) {\n finish();\n return reader.cancel(reason);\n },\n });\n}\n\n/**\n * Abort the request when it takes longer than `ms` — counted from the start\n * of the attempt until the body has been fully read, so a server that sends\n * headers and then stalls still trips it. Rejects with a `TimeoutError` (a\n * `DOMException`, like `AbortSignal.timeout()` would give); it is not an\n * `ArthronError`, so error interceptors and `retry` leave it alone.\n *\n * Built on `AbortController` + `setTimeout` rather than `AbortSignal.any` /\n * `AbortSignal.timeout` so it runs on Node 18.\n */\nexport function timeout(ms: number): Plugin {\n return {\n name: \"timeout\",\n middleware: async (ctx, next) => {\n const controller = new AbortController();\n const outer = ctx.init.signal;\n const forward = () => controller.abort(outer?.reason);\n if (outer?.aborted) forward();\n else outer?.addEventListener(\"abort\", forward, { once: true });\n\n const timer = setTimeout(\n () =>\n controller.abort(\n new DOMException(\n `arthron: request timed out after ${ms}ms`,\n \"TimeoutError\",\n ),\n ),\n ms,\n );\n const finish = () => {\n clearTimeout(timer);\n outer?.removeEventListener(\"abort\", forward);\n };\n\n let res: Response;\n try {\n res = await next({\n ...ctx,\n init: { ...ctx.init, signal: controller.signal },\n });\n } catch (thrown) {\n finish();\n throw thrown;\n }\n if (!res.body) {\n finish();\n return res;\n }\n return new Response(guardBody(res.body, controller.signal, finish), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["MAX_TIMER_MS"],"sources":["../src/request/url.ts","../src/error/arthron-error.ts","../src/request/headers.ts","../src/pipeline/pipeline.ts","../src/request/body.ts","../src/response/schema-validation.ts","../src/response/stream-parser.ts","../src/response/arthron-promise.ts","../src/client/resolve-config.ts","../src/response/rebuild-response.ts","../src/error/create-error.ts","../src/client/send.ts","../src/client/client.ts","../src/pipeline/define-plugin.ts","../src/plugins/logging/logging.ts","../src/plugins/retry/retry.ts","../src/plugins/timeout/timeout.ts"],"sourcesContent":["import type { QueryParams } from \"../types/request.types\";\n\nconst ABSOLUTE_URL = /^[a-z][a-z0-9+.-]*:\\/\\//i;\nconst HTTP_URL = /^https?:\\/\\//i;\n\nexport function isAbsoluteUrl(path: string): boolean {\n return ABSOLUTE_URL.test(path);\n}\n\n/**\n * Origin + pathname only — the query and userinfo tend to carry secrets.\n * For anything printed: log lines, error messages, `ArthronError.toJSON`.\n */\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n return `${parsed.origin}${parsed.pathname}`;\n } catch {\n return url.split(/[?#]/)[0] ?? url;\n }\n}\n\n/**\n * `undefined` when `url` has no origin of its own. A relative baseURL takes\n * the page's origin in a browser and has none elsewhere.\n */\nfunction originOf(url: string): string | undefined {\n const page = (globalThis as { location?: { href?: string } }).location?.href;\n try {\n return new URL(url, page).origin;\n } catch {\n return undefined;\n }\n}\n\n/** `path` is absolute and points away from `baseURL`'s origin. */\nexport function leavesBase(baseURL: string | undefined, path: string): boolean {\n if (baseURL === undefined || !isAbsoluteUrl(path)) return false;\n const base = originOf(baseURL);\n return base === undefined || originOf(path) !== base;\n}\n\nfunction toQueryString(params: QueryParams | undefined): string {\n if (!params) return \"\";\n if (Object.prototype.toString.call(params) === \"[object URLSearchParams]\") {\n return params.toString();\n }\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n for (const item of Array.isArray(value) ? value : [value]) {\n if (item === null || item === undefined) continue;\n // `String({})` is \"[object Object]\" and a Date prints in local time —\n // neither is what a server expects.\n if (typeof item === \"object\" || typeof item === \"function\") {\n throw new TypeError(\n `arthron: params.${key} is not a string, number or boolean — pass one of those or an array of them (dates: date.toISOString())`,\n );\n }\n search.append(key, String(item));\n }\n }\n return search.toString();\n}\n\n/**\n * Fill `{name}` placeholders with encoded values, so each one stays inside\n * its segment: \"/\", \"?\" and \"#\" are encoded, and the values WHATWG URL would\n * turn into a different path — \"\", \".\" and \"..\" — are refused. A placeholder\n * without a value, or a value without a placeholder, is a mistake too.\n */\nexport function fillPath(\n template: string,\n values: Record<string, string | number>,\n): string {\n const used = new Set<string>();\n const filled = template.replace(/\\{([^{}/]+)\\}/g, (_, name: string) => {\n if (!Object.hasOwn(values, name)) {\n throw new TypeError(\n `arthron: path \"${template}\" has {${name}} but no value for it — pass path: { ${name}: … }`,\n );\n }\n used.add(name);\n const value = String(values[name]);\n if (value === \"\" || value === \".\" || value === \"..\") {\n throw new TypeError(\n `arthron: path value ${name}=${JSON.stringify(value)} would change the path, not fill a segment — pass a real id`,\n );\n }\n return encodeURIComponent(value);\n });\n const unused = Object.keys(values).find((name) => !used.has(name));\n if (unused !== undefined) {\n throw new TypeError(\n `arthron: path \"${template}\" has no {${unused}} — add the placeholder or drop the value`,\n );\n }\n return filled;\n}\n\n/**\n * Join `baseURL` and `path` by plain string concatenation so a path prefix in\n * the base (`/v1`) survives a leading slash in the path. WHATWG `new URL()`\n * would drop it. An absolute path replaces the base only when it stays on the\n * base's origin, or when `allowAbsoluteUrls` says other origins are fine — a\n * path built from user input or an API response must not carry the client's\n * credentials somewhere else.\n */\nexport function resolveUrl(\n baseURL: string | undefined,\n path: string,\n params?: QueryParams,\n allowAbsoluteUrls = false,\n): string {\n let url: string;\n if (isAbsoluteUrl(path)) {\n if (!HTTP_URL.test(path)) {\n const scheme = path.slice(0, path.indexOf(\":\") + 1);\n throw new TypeError(\n `arthron: only http(s) URLs can be requested, got a \"${scheme}\" URL — use an http:// or https:// URL`,\n );\n }\n if (!allowAbsoluteUrls && leavesBase(baseURL, path)) {\n throw new TypeError(\n `arthron: ${originOf(path)} is outside baseURL ${(baseURL && originOf(baseURL)) ?? baseURL} — pass a path relative to baseURL, or set arthron({ allowAbsoluteUrls: true }) to allow other origins (config headers are not sent to them)`,\n );\n }\n url = path;\n } else {\n if (baseURL === undefined) {\n throw new TypeError(\n `arthron: relative path \"${redactUrl(path)}\" needs a baseURL — pass baseURL in arthron({ baseURL }) or use an absolute URL`,\n );\n }\n url = `${baseURL.replace(/\\/+$/, \"\")}/${path.replace(/^\\/+/, \"\")}`;\n }\n const query = toQueryString(params);\n if (!query) return url;\n // The query goes before any #fragment, or the server never sees it.\n const hash = url.indexOf(\"#\");\n const [base, fragment] =\n hash === -1 ? [url, \"\"] : [url.slice(0, hash), url.slice(hash)];\n return `${base}${base.includes(\"?\") ? \"&\" : \"?\"}${query}${fragment}`;\n}\n","import { redactUrl } from \"../request/url\";\nimport type { RequestContext } from \"../types/request.types\";\n\ntype ArthronErrorInit = {\n message: string;\n status: number;\n statusText: string;\n headers: Headers;\n data: unknown;\n detail?: string | undefined;\n request: RequestContext;\n response?: Response;\n cause?: unknown;\n};\n\n/**\n * Marks an ArthronError across copies of this package. The ESM and CJS\n * builds can both end up loaded (a CJS dependency creates the client, ESM\n * app code catches), each with its own class — `Symbol.for` is shared.\n */\nconst BRAND = Symbol.for(\"arthron.ArthronError\");\n\n/**\n * The only error arthron itself produces. Two sources: a response with\n * `ok === false`, or fetch rejecting outright (network failure, `status` 0).\n * Everything else — cancellation, interceptor bugs — is rethrown untouched.\n */\nexport class ArthronError extends Error {\n override readonly name = \"ArthronError\";\n /** HTTP status of the failed response; `0` when fetch itself failed (network). */\n readonly status: number;\n readonly statusText: string;\n /** Response headers; empty for network failures. Not enumerable — kept out of logs. */\n declare readonly headers: Headers;\n /** Parsed body: JSON if it parses, else the text, else `undefined`. */\n readonly data: unknown;\n /**\n * The server's own explanation, picked out of `data` (by default\n * `message` → `error` → `error.message` → `detail`; see the `errorDetail`\n * config). `undefined` when the body had none. Untrusted server text: show\n * it to users as text, never as HTML. `message`, by contrast, is written by\n * arthron — method, URL without query, status — and is meant for logs.\n */\n readonly detail: string | undefined;\n /**\n * The context that was sent — url and init after request interceptors.\n * Not enumerable: it holds credentials, so `JSON.stringify`, `console.error`\n * and error trackers leave it out. Read it directly when you need it.\n */\n declare readonly request: RequestContext;\n /** The failed Response, still readable — its body holds what arthron read (at most 64 KiB). Absent for network failures. Not enumerable. */\n declare readonly response: Response | undefined;\n /** The underlying error for network failures. */\n override readonly cause: unknown;\n\n constructor(init: ArthronErrorInit) {\n super(init.message);\n this.status = init.status;\n this.statusText = init.statusText;\n this.data = init.data;\n this.detail = init.detail;\n this.cause = init.cause;\n Object.defineProperties(this, {\n headers: { value: init.headers },\n request: { value: init.request },\n response: { value: init.response },\n [BRAND]: { value: true },\n });\n }\n\n /** `instanceof ArthronError` holds for an error from any copy of the package. */\n static override [Symbol.hasInstance](value: unknown): boolean {\n return this === ArthronError\n ? isArthronError(value)\n : Function.prototype[Symbol.hasInstance].call(this, value);\n }\n\n /** What serializers see: no headers, no body, no query or userinfo. */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n detail: this.detail,\n status: this.status,\n statusText: this.statusText,\n method: this.request.init.method ?? \"GET\",\n url: redactUrl(this.request.url),\n data: this.data,\n };\n }\n}\n\n/** `true` for errors arthron produced: a `!ok` response or a network failure. Cancellations and plugin bugs are not ArthronErrors. */\nexport function isArthronError(error: unknown): error is ArthronError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as { [BRAND]?: unknown })[BRAND] === true\n );\n}\n","import type { HeadersOption } from \"../types/request.types\";\n\nconst isPlainRecord = (\n headers: HeadersOption,\n): headers is Record<string, string | null | undefined> =>\n !Array.isArray(headers) &&\n Object.prototype.toString.call(headers) !== \"[object Headers]\";\n\n/**\n * Layer header sets left to right into one plain record. Names are compared\n * case-insensitively and come back lowercased; a later layer wins, so a\n * caller's `content-type` replaces a default `Content-Type` instead of fetch\n * sending both values joined. `Headers` validates every value it sets.\n */\nexport function mergeHeaders(\n ...layers: (HeadersOption | undefined)[]\n): Record<string, string> {\n const merged = new Headers();\n for (const layer of layers) {\n if (!layer) continue;\n if (isPlainRecord(layer)) {\n for (const [name, value] of Object.entries(layer)) {\n if (value == null) merged.delete(name);\n else merged.set(name, value);\n }\n } else {\n for (const [name, value] of new Headers(layer)) merged.set(name, value);\n }\n }\n return Object.fromEntries(merged);\n}\n\n/** Normalize any header shape into a plain record with lowercased names. */\nexport function toHeaderRecord(\n headers: HeadersOption | undefined,\n): Record<string, string> {\n return mergeHeaders(headers);\n}\n","import { isArthronError } from \"../error/arthron-error\";\nimport { toHeaderRecord } from \"../request/headers\";\nimport type {\n ErrorInterceptor,\n Middleware,\n Plugin,\n RequestInterceptor,\n ResponseInterceptor,\n} from \"../types/plugin.types\";\nimport type { RequestContext } from \"../types/request.types\";\n\n/** The mutable body kinds an interceptor can `append` to; anything else is shared as is. */\nfunction cloneBody(body: BodyInit): BodyInit {\n if (typeof FormData !== \"undefined\" && body instanceof FormData) {\n const copy = new FormData();\n for (const [name, value] of body) copy.append(name, value);\n return copy;\n }\n if (body instanceof URLSearchParams) return new URLSearchParams(body);\n return body;\n}\n\n/**\n * Interceptors mutate the context in place. A middleware that calls `next`\n * again (retry) must not see the previous attempt's changes, so every attempt\n * starts from a fresh copy of the headers and of a FormData/URLSearchParams body.\n */\nfunction cloneContext({ url, init, meta }: RequestContext): RequestContext {\n const copy: RequestContext[\"init\"] = {\n ...init,\n headers: toHeaderRecord(init.headers),\n };\n if (init.body) copy.body = cloneBody(init.body);\n return { url, init: copy, meta: { ...meta } };\n}\n\n/**\n * Put headers back into a plain lowercase record. A plugin written in JS (or\n * with a cast) may hand back a `Headers` object, and the next plugin's\n * `{ ...ctx.init.headers }` would otherwise drop every header.\n */\nfunction normalize(\n ctx: RequestContext,\n previous: RequestContext,\n): RequestContext {\n return {\n ...ctx,\n init: { ...ctx.init, headers: toHeaderRecord(ctx.init.headers) },\n // A plugin that builds a fresh `{ url, init }` must not lose the call's meta.\n meta: ctx.meta ?? previous.meta,\n };\n}\n\n/**\n * Owns the order of one request.\n *\n * Middleware wraps the whole call, outermost first in registration order.\n * Each attempt below it runs request interceptors → `send` → response\n * interceptors. Only an `ArthronError` reaches the error interceptors; whatever\n * they return is thrown. Anything else that is thrown — cancellation, a bug\n * in a plugin — propagates untouched.\n */\nexport async function runPipeline(\n plugins: readonly Plugin[],\n ctx: RequestContext,\n send: (ctx: RequestContext) => Promise<Response>,\n): Promise<Response> {\n const middlewares: Middleware[] = [];\n const request: RequestInterceptor[] = [];\n const response: ResponseInterceptor[] = [];\n const error: ErrorInterceptor[] = [];\n for (const plugin of plugins) {\n if (plugin.middleware) middlewares.push(plugin.middleware);\n if (plugin.request) request.push(plugin.request);\n if (plugin.response) response.push(plugin.response);\n if (plugin.error) error.push(plugin.error);\n }\n\n const attempt = async (input: RequestContext): Promise<Response> => {\n let current = cloneContext(input);\n try {\n for (const interceptor of request) {\n current = normalize(await interceptor(current), current);\n }\n let res = await send(current);\n for (const interceptor of response) res = await interceptor(res, current);\n return res;\n } catch (thrown) {\n if (!isArthronError(thrown)) throw thrown;\n let err = thrown;\n for (const interceptor of error) err = await interceptor(err, current);\n throw err;\n }\n };\n\n const dispatch = (\n index: number,\n input: RequestContext,\n ): Promise<Response> => {\n const middleware = middlewares[index];\n if (!middleware) return attempt(input);\n // A middleware that builds a fresh `{ url, init }` keeps the call's meta.\n return middleware(input, (next) =>\n dispatch(index + 1, { ...next, meta: next.meta ?? input.meta }),\n );\n };\n return dispatch(0, ctx);\n}\n","type Serialized = {\n body: BodyInit | undefined;\n headers: Record<string, string>;\n};\n\nconst RAW_TAGS = new Set([\n \"FormData\",\n \"Blob\",\n \"File\",\n \"ArrayBuffer\",\n \"URLSearchParams\",\n \"ReadableStream\",\n]);\n\n/**\n * `Symbol.toStringTag`, not `instanceof`: a body from another realm or a\n * polyfill (formdata-node, fetch-blob) must not be JSON-encoded into `{}`.\n */\nconst tagOf = (value: unknown): string =>\n Object.prototype.toString.call(value).slice(8, -1);\n\nexport function isReadableStream(value: unknown): value is ReadableStream {\n return tagOf(value) === \"ReadableStream\";\n}\n\n/**\n * What JSON.stringify would turn into `{}`, `undefined` or internal state\n * instead of the data — with the fix, so it reads as an error message.\n */\nfunction mangledByJson(body: unknown): string | undefined {\n if (typeof body === \"function\" || typeof body === \"symbol\") {\n return `a ${typeof body}, which JSON cannot carry — send its data instead`;\n }\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) {\n return undefined;\n }\n if (Symbol.asyncIterator in body) {\n return \"an async iterable (a Node stream?) — pass a ReadableStream (Readable.toWeb(stream)) or collect it first\";\n }\n if (Symbol.iterator in body) {\n return \"an iterable such as a Map, Set or generator — convert it to an array or plain object first\";\n }\n return undefined;\n}\n\n/** Bodies fetch already knows how to send. Content-Type is left to the caller / runtime. */\nfunction isRawBody(body: unknown): body is BodyInit {\n if (typeof body === \"string\") return true;\n if (ArrayBuffer.isView(body)) return true;\n return RAW_TAGS.has(tagOf(body));\n}\n\n/**\n * Turn a caller-supplied body into something fetch accepts. Raw bodies pass\n * through untouched; anything else is JSON with `content-type` set — unless\n * the caller already set one (headers arrive lowercased, so a plain lookup is\n * enough).\n */\nexport function serializeBody(\n body: unknown,\n headers: Record<string, string>,\n): Serialized {\n if (body === undefined) return { body: undefined, headers };\n if (tagOf(body) === \"FormData\") {\n // The runtime must write `multipart/form-data; boundary=…` itself; any\n // content-type set here (a JSON default, typically) breaks the upload.\n const { \"content-type\": _dropped, ...rest } = headers;\n return { body: body as FormData, headers: rest };\n }\n if (isRawBody(body)) return { body, headers };\n const mangled = mangledByJson(body);\n if (mangled) {\n throw new TypeError(`arthron: the body is ${mangled}`);\n }\n const type = headers[\"content-type\"];\n if (type !== undefined && !/\\bjson\\b/i.test(type)) {\n throw new TypeError(\n `arthron: a ${typeof body} body is sent as JSON, but content-type is \"${type}\" — pass a string, URLSearchParams or FormData for that content type, or drop the header`,\n );\n }\n const withType =\n \"content-type\" in headers\n ? headers\n : { ...headers, \"content-type\": \"application/json\" };\n return { body: JSON.stringify(body), headers: withType };\n}\n","import type {\n InferOutput,\n SchemaIssue,\n StandardSchemaV1,\n} from \"../types/response.types\";\n\nconst pathOf = (issue: SchemaIssue): string =>\n (issue.path ?? [])\n .map((part) =>\n String(typeof part === \"object\" && part !== null ? part.key : part),\n )\n .join(\".\");\n\n/**\n * `.json(schema)` got a body that does not match. Not an ArthronError: the\n * request succeeded — the data is what is wrong.\n */\nexport class SchemaError extends Error {\n override readonly name = \"SchemaError\";\n /** Every problem the validator reported, with the path to it. */\n readonly issues: readonly SchemaIssue[];\n\n constructor(issues: readonly SchemaIssue[]) {\n const [first] = issues;\n const where = first ? pathOf(first) : \"\";\n const more = issues.length > 1 ? ` (+${issues.length - 1} more)` : \"\";\n super(\n `arthron: the response body does not match the schema — ${where ? `${where}: ` : \"\"}${first?.message ?? \"invalid\"}${more}. See error.issues`,\n );\n this.issues = issues;\n }\n}\n\n/** Validate `data`; resolve with the schema's output or reject with a SchemaError. */\nexport async function validate<S extends StandardSchemaV1>(\n schema: S,\n data: unknown,\n): Promise<InferOutput<S>> {\n const result = await schema[\"~standard\"].validate(data);\n if (result.issues) throw new SchemaError(result.issues);\n return result.value as InferOutput<S>;\n}\n","import type {\n NdjsonOptions,\n SseEvent,\n SseOptions,\n} from \"../types/response.types\";\n\nconst DEFAULT_LIMIT = 8 * 1024 * 1024;\n\n/**\n * Yield the body line by line, reassembling lines split across chunks. Only\n * the newly arrived text is scanned, so a long line costs linear time; a line\n * past `maxLineLength` stops the stream instead of growing without bound.\n */\nasync function* lines(\n response: Response,\n maxLineLength: number,\n): AsyncGenerator<string> {\n if (!response.body) return;\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n const breaks = /\\r\\n|\\r|\\n/g;\n let pending = \"\";\n // The previous chunk ended in \"\\r\": a \"\\n\" opening this one belongs to it.\n let afterCR = false;\n try {\n while (true) {\n const { value, done } = await reader.read();\n let text = decoder.decode(value, { stream: !done });\n if (afterCR && text.startsWith(\"\\n\")) {\n text = text.slice(1);\n afterCR = false;\n }\n if (text) afterCR = text.endsWith(\"\\r\");\n let start = 0;\n breaks.lastIndex = 0;\n for (let m = breaks.exec(text); m; m = breaks.exec(text)) {\n yield pending + text.slice(start, m.index);\n pending = \"\";\n start = breaks.lastIndex;\n }\n pending += text.slice(start);\n if (pending.length > maxLineLength) {\n throw new RangeError(\n `arthron: a stream line is longer than ${maxLineLength} characters — pass a larger maxLineLength to .sse() / .ndjson() if that is expected`,\n );\n }\n if (done) break;\n }\n if (pending) yield pending;\n } finally {\n // Leaving early (break, return, a throw) must close the connection too —\n // releasing the lock alone leaves the body streaming.\n await reader.cancel().catch(() => {});\n reader.releaseLock();\n }\n}\n\n/**\n * Parse a `text/event-stream` body into events. Follows the spec: a blank\n * line dispatches, `data:` lines are joined with `\\n`, one leading space\n * after the colon is dropped, lines starting with `:` are comments, and a\n * block without `data` — or one the stream ends inside — is not dispatched.\n * Provider sentinels like\n * `[DONE]` are passed through untouched — they are not part of the spec.\n */\nexport async function* parseSse(\n response: Response,\n {\n maxLineLength = DEFAULT_LIMIT,\n maxEventSize = DEFAULT_LIMIT,\n }: SseOptions = {},\n): AsyncGenerator<SseEvent> {\n let data: string[] = [];\n let size = 0;\n let event: string | undefined;\n let id: string | undefined;\n // Stream state, not block state: neither resets when an event dispatches.\n let lastEventId = \"\";\n let retry: number | undefined;\n\n const flush = (): SseEvent | undefined => {\n const out: SseEvent | undefined =\n data.length === 0 ? undefined : { data: data.join(\"\\n\"), lastEventId };\n if (out && event !== undefined) out.event = event;\n if (out && id !== undefined) out.id = id;\n if (out && retry !== undefined) out.retry = retry;\n data = [];\n size = 0;\n event = id = undefined;\n return out;\n };\n\n for await (const line of lines(response, maxLineLength)) {\n if (line === \"\") {\n const out = flush();\n if (out) yield out;\n continue;\n }\n if (line.startsWith(\":\")) continue;\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) value = value.slice(1);\n switch (field) {\n case \"data\":\n size += value.length + 1;\n if (size > maxEventSize + 1) {\n throw new RangeError(\n `arthron: an SSE event's data is longer than ${maxEventSize} characters — pass a larger maxEventSize to .sse() if that is expected`,\n );\n }\n data.push(value);\n break;\n case \"event\":\n event = value;\n break;\n case \"id\":\n if (!value.includes(\"\\u0000\")) id = lastEventId = value;\n break;\n case \"retry\":\n if (/^\\d+$/.test(value)) retry = Number(value);\n break;\n default:\n break; // unknown fields are ignored, per spec\n }\n }\n // A block the stream ended in before its blank line is incomplete — the\n // spec discards it rather than dispatch a possibly truncated payload.\n}\n\n/**\n * Parse newline-delimited JSON. Blank lines are skipped; a malformed line\n * rejects the iteration with the `SyntaxError` from `JSON.parse`.\n */\nexport async function* parseNdjson<T = unknown>(\n response: Response,\n { maxLineLength = DEFAULT_LIMIT }: NdjsonOptions = {},\n): AsyncGenerator<T> {\n for await (const line of lines(response, maxLineLength)) {\n if (line.trim() === \"\") continue;\n yield JSON.parse(line) as T;\n }\n}\n","import type {\n ArthronPromise,\n NdjsonOptions,\n SseOptions,\n StandardSchemaV1,\n} from \"../types/response.types\";\nimport { validate } from \"./schema-validation\";\nimport { parseNdjson, parseSse } from \"./stream-parser\";\n\n/** Defer the Response until iteration starts, so the helper itself never rejects. */\nfunction iterate<T>(\n promise: Promise<Response>,\n parse: (res: Response) => AsyncGenerator<T>,\n): AsyncIterable<T> {\n // Iteration may start long after the request fails. Mark the rejection\n // handled now; the first `next()` still rethrows it.\n promise.catch(() => {});\n return {\n async *[Symbol.asyncIterator]() {\n yield* parse(await promise);\n },\n };\n}\n\n/**\n * Sugar over `Promise<Response>`: `.json()` is `(await p).json()`. Awaiting\n * without a helper still yields the untouched `Response`.\n */\nexport function toArthronPromise(promise: Promise<Response>): ArthronPromise {\n return Object.assign(promise, {\n json: ((schema?: StandardSchemaV1) =>\n promise.then(async (res) => {\n const data: unknown = await res.json();\n return schema ? validate(schema, data) : data;\n })) as ArthronPromise[\"json\"],\n text: () => promise.then((res) => res.text()),\n blob: () => promise.then((res) => res.blob()),\n arrayBuffer: () => promise.then((res) => res.arrayBuffer()),\n formData: () => promise.then((res) => res.formData()),\n sse: (options?: SseOptions) =>\n iterate(promise, (res) => parseSse(res, options)),\n ndjson: <T = unknown>(options?: NdjsonOptions) =>\n iterate(promise, (res) => parseNdjson<T>(res, options)),\n });\n}\n","import { toHeaderRecord } from \"../request/headers\";\nimport type { Plugin } from \"../types/plugin.types\";\nimport type { ArthronConfig, FetchDefaults, Resolved } from \"./client.types\";\n\n/**\n * Config keys that configure arthron itself; every other key is a fetch\n * default. Typed so that a new config key fails to compile until it is\n * listed here — otherwise it would be sent to fetch.\n */\nconst OWN_KEYS: Record<\n Exclude<keyof ArthronConfig, keyof FetchDefaults>,\n true\n> = {\n baseURL: true,\n allowAbsoluteUrls: true,\n headers: true,\n fetch: true,\n use: true,\n errorDetail: true,\n throwOn: true,\n};\n\n/** Fields that belong to one request, refused as client defaults. */\nconst PER_CALL_ONLY = [\"signal\", \"body\", \"method\"] as const;\n\n/**\n * Add plugins to a list. A named plugin takes the place of the one already\n * there with that name — same position, so a replaced `logging()` stays\n * outermost and a second `retry()` does not multiply attempts. Unnamed\n * plugins append.\n */\nexport function addPlugins(\n base: readonly Plugin[],\n added: readonly Plugin[],\n): Plugin[] {\n const out = [...base];\n for (const plugin of added) {\n const at =\n plugin.name === undefined\n ? -1\n : out.findIndex((p) => p.name === plugin.name);\n if (at === -1) out.push(plugin);\n else out[at] = plugin;\n }\n return out;\n}\n\n/** The fetch defaults in a config: every set key that is not arthron's own. */\nexport function fetchDefaults(config: Resolved): FetchDefaults {\n return Object.fromEntries(\n Object.entries(config).filter(\n ([key, value]) => value !== undefined && !(key in OWN_KEYS),\n ),\n ) as FetchDefaults;\n}\n\n/** Normalize once so `extend` can merge headers and add plugins cheaply. */\nexport function resolveConfig(config: ArthronConfig): Resolved {\n for (const key of PER_CALL_ONLY) {\n if ((config as Record<string, unknown>)[key] !== undefined) {\n throw new TypeError(\n `arthron: ${key} cannot be a client default, it belongs to one request — pass it per call (api.get(path, { signal }), api.post(path, body), api.request(path, { method }))`,\n );\n }\n }\n const { headers, use, ...rest } = config;\n return {\n ...rest,\n headers: toHeaderRecord(headers),\n use: addPlugins([], use ?? []),\n };\n}\n","/**\n * A new Response with `body` but everything else taken from `original`. The\n * constructor resets `url`, `redirected` and `type`, so those are copied over\n * as own properties — callers that resolve relative links or detect\n * redirects keep working.\n */\nexport function rebuildResponse(\n original: Response,\n body: BodyInit | null,\n): Response {\n const rebuilt = new Response(body, {\n status: original.status,\n statusText: original.statusText,\n headers: original.headers,\n });\n return withFetchedFields(rebuilt, original);\n}\n\n/** Copy the fields the constructor resets — onto `clone()`s as well. */\nfunction withFetchedFields(target: Response, from: Response): Response {\n const clone = target.clone.bind(target);\n return Object.defineProperties(target, {\n url: { value: from.url },\n redirected: { value: from.redirected },\n type: { value: from.type },\n clone: { value: () => withFetchedFields(clone(), from) },\n });\n}\n","import { redactUrl } from \"../request/url\";\nimport { rebuildResponse } from \"../response/rebuild-response\";\nimport type { RequestContext } from \"../types/request.types\";\nimport type { ErrorDetailResolver } from \"../types/response.types\";\nimport { ArthronError } from \"./arthron-error\";\n\n/**\n * Cancellation is not an HTTP failure. Matched by name so it works across\n * realms — or by the request's own `signal`, since `abort(reason)` rejects\n * with whatever reason the caller chose.\n */\nexport function isCancellation(\n error: unknown,\n signal?: AbortSignal | null,\n): boolean {\n if (signal?.aborted) return true;\n const name = (error as { name?: unknown } | null | undefined)?.name;\n return name === \"AbortError\" || name === \"TimeoutError\";\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\n/** `message` → `error` (string) → `error.message` → `detail`. */\nexport function defaultErrorDetail(data: unknown): string | undefined {\n if (!isRecord(data)) return undefined;\n if (typeof data.message === \"string\") return data.message;\n if (typeof data.error === \"string\") return data.error;\n if (isRecord(data.error) && typeof data.error.message === \"string\") {\n return data.error.message;\n }\n if (typeof data.detail === \"string\") return data.detail;\n return undefined;\n}\n\n/** How much of an error body arthron reads. Error bodies are for diagnosis; a hostile or broken server must not be able to fill memory with one. */\nconst MAX_ERROR_BODY_BYTES = 64 * 1024;\n\n/** Up to `limit` bytes of the body; the rest is cancelled unread. `undefined` when there is no body or reading it failed. */\nasync function readCapped(\n response: Response,\n limit: number,\n): Promise<{ bytes: Uint8Array<ArrayBuffer>; truncated: boolean } | undefined> {\n if (!response.body) return undefined;\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n const chunks: Uint8Array[] = [];\n let size = 0;\n try {\n // Inside the try: a body that is already locked or used counts as unreadable.\n reader = response.body.getReader();\n while (size <= limit) {\n const { value, done } = await reader.read();\n if (done) break;\n chunks.push(value);\n size += value.byteLength;\n }\n } catch {\n return undefined;\n } finally {\n await reader?.cancel().catch(() => {});\n reader?.releaseLock();\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return size > limit\n ? { bytes: bytes.subarray(0, limit), truncated: true }\n : { bytes, truncated: false };\n}\n\n/** JSON if the whole body parses, else the text (cut at the limit), else `undefined` when empty. */\nfunction parseBody(read: {\n bytes: Uint8Array<ArrayBuffer>;\n truncated: boolean;\n}): unknown {\n const text = new TextDecoder().decode(read.bytes);\n if (text === \"\") return undefined;\n if (read.truncated) return text;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\n/** The request as error messages name it: method and URL, no query or userinfo. */\nfunction describeRequest(request: RequestContext): string {\n return `${request.init.method ?? \"GET\"} ${redactUrl(request.url)}`;\n}\n\nexport async function responseError(\n response: Response,\n request: RequestContext,\n resolve: ErrorDetailResolver = defaultErrorDetail,\n): Promise<ArthronError> {\n const read = await readCapped(response, MAX_ERROR_BODY_BYTES);\n const data = read && parseBody(read);\n // The body was consumed above; hand the caller a Response over what was read.\n if (read) response = rebuildResponse(response, read.bytes);\n const status = response.statusText\n ? `${response.status} ${response.statusText}`\n : String(response.status);\n return new ArthronError({\n // arthron's own words for logs; the server's go in `detail`.\n message: `${describeRequest(request)} failed with ${status}`,\n detail: resolve(data, response) || undefined,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n data,\n request,\n response,\n });\n}\n\nexport function networkError(\n cause: unknown,\n request: RequestContext,\n): ArthronError {\n return new ArthronError({\n message: `${describeRequest(request)} failed: ${\n cause instanceof Error && cause.message ? cause.message : \"network error\"\n }`,\n status: 0,\n statusText: \"\",\n headers: new Headers(),\n data: undefined,\n request,\n cause,\n });\n}\n","import {\n isCancellation,\n networkError,\n responseError,\n} from \"../error/create-error\";\nimport { redactUrl } from \"../request/url\";\nimport type { RequestContext } from \"../types/request.types\";\nimport type { Resolved } from \"./client.types\";\n\n/**\n * The global fetch rejects a malformed URL or method with a TypeError that\n * looks just like a network failure (status 0, retried). A bodiless `Request`\n * runs the same checks first, so those become argument errors instead. Only\n * for the global fetch: an injected one owns its URL rules (SvelteKit's\n * server-side `fetch` accepts relative URLs, for one).\n */\nfunction assertSendable(url: string, method: string): void {\n if (typeof Request !== \"function\") return;\n try {\n new Request(url, { method });\n } catch (cause) {\n const shown = redactUrl(url);\n // fetch's own message repeats the full URL, query included.\n const reason = (cause instanceof Error ? cause.message : String(cause))\n .split(url)\n .join(shown);\n throw new TypeError(\n `arthron: cannot send ${method} ${shown} (${reason}) — use an absolute URL or a baseURL with a scheme (https://…), and a valid HTTP method`,\n { cause },\n );\n }\n}\n\n/**\n * Non-ok responses the caller asked for are not failures: an opaque one\n * (`mode: \"no-cors\"`) and the 3xx of `redirect: \"manual\"`.\n */\nfunction failedByDefault(res: Response, init: RequestContext[\"init\"]): boolean {\n if (res.type === \"opaque\" || res.type === \"opaqueredirect\") return false;\n return !(init.redirect === \"manual\" && res.status >= 300 && res.status < 400);\n}\n\n/** The one place a failure becomes an ArthronError. Cancellation passes through. */\nexport async function send(\n resolved: Resolved,\n ctx: RequestContext,\n throwOn: ((res: Response) => boolean) | undefined,\n): Promise<Response> {\n // Resolved per call, not per client: a global patched after the client was\n // created (msw's `server.listen()`, for one) must still be honoured.\n const fetchImpl = resolved.fetch ?? globalThis.fetch;\n // Here rather than before the pipeline, so it sees the URL the request\n // interceptors produced. A TypeError is not an ArthronError: retry and\n // error interceptors leave it alone.\n if (resolved.fetch === undefined) {\n assertSendable(ctx.url, ctx.init.method ?? \"GET\");\n }\n const { signal } = ctx.init;\n let res: Response;\n try {\n res = await fetchImpl(ctx.url, ctx.init);\n } catch (thrown) {\n if (isCancellation(thrown, signal)) throw thrown;\n throw networkError(thrown, ctx);\n }\n // Only a non-ok response can become an ArthronError; throwOn narrows which.\n if (res.ok) return res;\n if (!(throwOn ? throwOn(res) : failedByDefault(res, ctx.init))) return res;\n const error = await responseError(res, ctx, resolved.errorDetail);\n // Aborted while the error body was being read (timeout, caller): that is\n // a cancellation, not this status.\n if (signal?.aborted) throw signal.reason;\n throw error;\n}\n","import { runPipeline } from \"../pipeline/pipeline\";\nimport { isReadableStream, serializeBody } from \"../request/body\";\nimport { mergeHeaders } from \"../request/headers\";\nimport { fillPath, leavesBase, resolveUrl } from \"../request/url\";\nimport { toArthronPromise } from \"../response/arthron-promise\";\nimport type { RequestContext } from \"../types/request.types\";\nimport type { ArthronPromise } from \"../types/response.types\";\nimport type {\n Arthron,\n ArthronConfig,\n RequestInitWithBody,\n RequestOptions,\n} from \"./client.types\";\nimport { addPlugins, fetchDefaults, resolveConfig } from \"./resolve-config\";\nimport { send } from \"./send\";\n\nconst BODYLESS_METHODS = new Set([\"GET\", \"HEAD\"]);\n/** Sent uppercased whatever their case; fetch itself only normalizes six. */\nconst STANDARD_METHODS = new Set([\n \"GET\",\n \"HEAD\",\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\",\n \"OPTIONS\",\n \"QUERY\",\n]);\n\n/**\n * Build a client from config. The result is immutable — `use` and `extend`\n * return new clients and never touch the one they were called on.\n */\nexport function arthron(config: ArthronConfig = {}): Arthron {\n const resolved = resolveConfig(config);\n const initDefaults = fetchDefaults(resolved);\n\n const dispatch = (\n path: string,\n method: string,\n rawBody: unknown,\n {\n params,\n headers: callHeaders,\n meta,\n throwOn = resolved.throwOn,\n path: pathValues,\n ...init\n }: RequestOptions,\n ): ArthronPromise => {\n try {\n const upper = method.toUpperCase();\n const verb = STANDARD_METHODS.has(upper) ? upper : method;\n if (rawBody !== undefined && BODYLESS_METHODS.has(upper)) {\n // fetch rejects these with a TypeError that would otherwise be mistaken for a network failure and retried.\n throw new TypeError(\n `arthron: ${upper} requests cannot carry a body — send it as params (query) or switch to POST`,\n );\n }\n if (pathValues) path = fillPath(path, pathValues);\n const url = resolveUrl(\n resolved.baseURL,\n path,\n params,\n resolved.allowAbsoluteUrls,\n );\n // Config headers (credentials, typically) belong to baseURL's origin.\n // Another origin, reachable only with allowAbsoluteUrls, gets per-call\n // headers alone.\n const defaults = leavesBase(resolved.baseURL, path)\n ? undefined\n : resolved.headers;\n const { body, headers } = serializeBody(\n rawBody,\n mergeHeaders(defaults, callHeaders),\n );\n // Config fetch defaults sit underneath, so a per-call value wins.\n const requestInit: RequestContext[\"init\"] = {\n ...initDefaults,\n ...init,\n method: verb,\n headers,\n };\n if (body !== undefined) requestInit.body = body;\n // Without half-duplex, fetch rejects a streaming upload (Node, Chromium).\n if (isReadableStream(body))\n Object.assign(requestInit, { duplex: \"half\" });\n return toArthronPromise(\n runPipeline(\n resolved.use,\n { url, init: requestInit, meta: { ...meta } },\n (ctx) => send(resolved, ctx, throwOn),\n ),\n );\n } catch (thrown) {\n // Argument errors (no baseURL, unserializable body) reject like everything else.\n return toArthronPromise(Promise.reject(thrown));\n }\n };\n\n const derive = (next: Partial<ArthronConfig>): Arthron => {\n const merged: ArthronConfig = {\n ...resolved,\n ...next,\n headers: mergeHeaders(resolved.headers, next.headers),\n use: addPlugins(resolved.use, next.use ?? []),\n };\n return arthron(merged);\n };\n\n return {\n get: (path, init = {}) => dispatch(path, \"GET\", undefined, init),\n delete: (path, init = {}) => dispatch(path, \"DELETE\", undefined, init),\n head: (path, init = {}) => dispatch(path, \"HEAD\", undefined, init),\n post: (path, body, init = {}) => dispatch(path, \"POST\", body, init),\n put: (path, body, init = {}) => dispatch(path, \"PUT\", body, init),\n patch: (path, body, init = {}) => dispatch(path, \"PATCH\", body, init),\n query: (path, body, init = {}) => dispatch(path, \"QUERY\", body, init),\n request: (path, init: RequestInitWithBody) => {\n const { method, body, ...rest } = init;\n if (!method) {\n return toArthronPromise(\n Promise.reject(\n new TypeError(\n 'arthron: request() needs init.method — e.g. request(path, { method: \"OPTIONS\" }); use get/post/... for the common verbs',\n ),\n ),\n );\n }\n return dispatch(path, method, body, rest);\n },\n use: (...plugins) => derive({ use: plugins }),\n extend: (next) => derive(next),\n without: (...names) =>\n arthron({\n ...resolved,\n use: resolved.use.filter(\n (p) => p.name === undefined || !names.includes(p.name),\n ),\n }),\n };\n}\n","import type {\n ErrorInterceptor,\n Middleware,\n Plugin,\n RequestInterceptor,\n ResponseInterceptor,\n} from \"../types/plugin.types\";\n\n/*\n * Identity helpers. They do nothing at runtime; they exist so a plugin written\n * in its own file gets contextual typing without an explicit annotation.\n */\n\n/** Identity helper: gives a middleware written in its own file the right parameter types. */\nexport const defineMiddleware = (middleware: Middleware): Middleware =>\n middleware;\n\n/** Identity helpers for each interceptor kind — `defineInterceptor.request(fn)` etc. */\nexport const defineInterceptor = {\n request: (interceptor: RequestInterceptor): RequestInterceptor => interceptor,\n response: (interceptor: ResponseInterceptor): ResponseInterceptor =>\n interceptor,\n error: (interceptor: ErrorInterceptor): ErrorInterceptor => interceptor,\n};\n\n/** Identity helper: type-checks a plugin object literal without an annotation. */\nexport const definePlugin = (plugin: Plugin): Plugin => plugin;\n","import { isArthronError } from \"../../error/arthron-error\";\nimport { isCancellation } from \"../../error/create-error\";\nimport { redactUrl } from \"../../request/url\";\nimport type { Plugin } from \"../../types/plugin.types\";\nimport type { LogEvent, LoggingOptions } from \"./logging.types\";\n\nfunction consoleSink(logger: Pick<Console, \"log\" | \"error\">) {\n return (e: LogEvent) => {\n if (e.phase === \"start\") {\n logger.log(`[arthron] → ${e.method} ${e.path}`);\n } else if (e.phase === \"success\") {\n logger.log(`[arthron] ← ${e.method} ${e.path} ${e.status} ${e.ms}ms`);\n } else {\n logger.error(\n `[arthron] ✕ ${e.method} ${e.path} ${e.status ?? \"-\"} ${e.ms}ms`,\n );\n }\n };\n}\n\n/**\n * One event when a request starts, one when it settles, with status and\n * elapsed time. Wraps the whole call, so retries are included in the time.\n * Default output is a console line per event; pass `onEvent` to get the\n * structured event instead. Cancellations are not reported.\n */\nexport function logging(options: LoggingOptions = {}): Plugin {\n const {\n enabled = true,\n logger = console,\n onEvent,\n now = () => performance.now(),\n } = options;\n const emit = onEvent ?? consoleSink(logger);\n return {\n name: \"logging\",\n middleware: async (ctx, next) => {\n if (!enabled) return next(ctx);\n const method = ctx.init.method ?? \"GET\";\n const path = redactUrl(ctx.url);\n const started = now();\n const ms = () => Math.round(now() - started);\n\n emit({ phase: \"start\", method, path });\n let res: Response;\n try {\n res = await next(ctx);\n } catch (error) {\n if (!isCancellation(error, ctx.init.signal)) {\n const status = isArthronError(error) ? error.status : undefined;\n emit({ phase: \"error\", method, path, status, ms: ms(), error });\n }\n throw error;\n }\n // Outside the try: a sink that throws is a plugin bug, not a failed request.\n emit({ phase: \"success\", method, path, status: res.status, ms: ms() });\n return res;\n },\n };\n}\n","import { type ArthronError, isArthronError } from \"../../error/arthron-error\";\nimport { isReadableStream } from \"../../request/body\";\nimport type { Plugin } from \"../../types/plugin.types\";\nimport type { RetryOptions } from \"../../types/request.types\";\n\nconst DEFAULT_RETRY_ON = [408, 429, 500, 502, 503, 504] as const;\nconst DEFAULT_METHODS = [\n \"GET\",\n \"HEAD\",\n \"OPTIONS\",\n \"QUERY\",\n \"PUT\",\n \"DELETE\",\n] as const;\nconst DEFAULT_MAX_RETRY_AFTER = 60_000;\n/** setTimeout fires at once past this, so every wait is capped to it. */\nconst MAX_TIMER_MS = 2 ** 31 - 1;\n\nfunction defaultSleep(ms: number, signal?: AbortSignal | null): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/** `Retry-After` as ms — seconds or an HTTP-date. `undefined` when absent or unparsable. */\nfunction retryAfterMs(error: ArthronError): number | undefined {\n const value = error.headers.get(\"retry-after\")?.trim();\n if (!value) return undefined;\n const seconds = Number(value);\n if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1000);\n const at = Date.parse(value);\n if (Number.isNaN(at)) return undefined;\n return Math.max(0, at - Date.now());\n}\n\n/** The rule without `shouldRetry`: a network error or a `retryOn` status, on a method in `methods`. */\nfunction byDefault(\n thrown: unknown,\n method: string,\n settings: Settings,\n): boolean {\n if (!settings.allowed.has(method) || !isArthronError(thrown)) return false;\n return thrown.status === 0 || settings.retryOn.includes(thrown.status);\n}\n\n/**\n * Retry on network errors and the configured statuses by calling `next`\n * again — the whole attempt (request interceptors included) is re-run.\n * Only `ArthronError` is considered; cancellation and plugin bugs pass through.\n */\ntype Settings = {\n retries: number;\n retryOn: readonly number[];\n allowed: Set<string>;\n delay: (retry: number, error: unknown) => number;\n maxRetryAfter: number;\n shouldRetry: RetryOptions[\"shouldRetry\"];\n onRetry: RetryOptions[\"onRetry\"];\n};\n\n/** Defaults filled in and `retries` checked — `attempt >= NaN` is never true, so an unset env var would retry forever. */\nfunction settle(options: Omit<RetryOptions, \"sleep\">, where: string): Settings {\n const {\n retries = 2,\n retryOn = DEFAULT_RETRY_ON,\n methods = DEFAULT_METHODS,\n delay = (retry) => Math.random() * 300 * 2 ** retry,\n maxRetryAfter = DEFAULT_MAX_RETRY_AFTER,\n shouldRetry,\n onRetry,\n } = options;\n if (!Number.isInteger(retries) || retries < 0) {\n throw new TypeError(\n `arthron: ${where} retries: ${retries} needs a whole number ≥ 0 — e.g. retries: 2`,\n );\n }\n const allowed = new Set(methods.map((m) => m.toUpperCase()));\n return {\n retries,\n retryOn,\n allowed,\n delay,\n maxRetryAfter,\n shouldRetry,\n onRetry,\n };\n}\n\n/**\n * Retry on network errors and the configured statuses by calling `next`\n * again — the whole attempt (request interceptors included) is re-run.\n * Only `ArthronError` is considered; cancellation and plugin bugs pass through.\n * A call can turn it off or override its options with `meta.retry`.\n */\nexport function retry(options: RetryOptions = {}): Plugin {\n const { sleep = defaultSleep, ...rest } = options;\n const base = settle(rest, \"retry()\");\n\n return {\n name: \"retry\",\n middleware: async (ctx, next) => {\n const override = ctx.meta?.retry;\n if (override === false) return next(ctx);\n const settings = override\n ? settle({ ...rest, ...override }, \"meta.retry\")\n : base;\n const method = (ctx.init.method ?? \"GET\").toUpperCase();\n const resendable = !isReadableStream(ctx.init.body);\n\n for (let attempt = 0; ; attempt += 1) {\n try {\n return await next(ctx);\n } catch (thrown) {\n // Not even shouldRetry can lift these.\n if (!resendable || attempt >= settings.retries) throw thrown;\n if (ctx.init.signal?.aborted) throw thrown;\n const verdict = settings.shouldRetry?.(thrown, attempt, ctx);\n if (verdict === false) throw thrown;\n if (verdict === undefined && !byDefault(thrown, method, settings)) {\n throw thrown;\n }\n const retryAfter = isArthronError(thrown)\n ? retryAfterMs(thrown)\n : undefined;\n if (retryAfter !== undefined && retryAfter > settings.maxRetryAfter) {\n throw thrown;\n }\n const wait = Math.min(\n retryAfter ?? settings.delay(attempt, thrown),\n MAX_TIMER_MS,\n );\n settings.onRetry?.(thrown, attempt, wait);\n await sleep(wait, ctx.init.signal);\n }\n }\n },\n };\n}\n","import { rebuildResponse } from \"../../response/rebuild-response\";\nimport type { Plugin } from \"../../types/plugin.types\";\nimport type { TimeoutOptions } from \"./timeout.types\";\n\nconst MAX_TIMER_MS = 2 ** 31 - 1;\n\n/**\n * Wrap `body` so the deadline keeps running until it is fully read, and so an\n * abort while reading surfaces as a stream error instead of a silent stall.\n */\nfunction guardBody(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n finish: () => void,\n onChunk: () => void,\n): ReadableStream<Uint8Array> {\n const reader = body.getReader();\n return new ReadableStream<Uint8Array>({\n start(controller) {\n signal.addEventListener(\n \"abort\",\n () => {\n controller.error(signal.reason);\n reader.cancel(signal.reason).catch(() => {});\n },\n { once: true },\n );\n },\n async pull(controller) {\n const { value, done } = await reader.read();\n if (done) {\n finish();\n controller.close();\n return;\n }\n onChunk();\n controller.enqueue(value);\n },\n cancel(reason) {\n finish();\n return reader.cancel(reason);\n },\n });\n}\n\n/** setTimeout fires at once for NaN, negatives and anything past 2^31-1. */\nfunction checkDeadline(ms: number, where: string): void {\n if (ms === Number.POSITIVE_INFINITY || (ms >= 0 && ms <= MAX_TIMER_MS))\n return;\n throw new TypeError(\n `arthron: ${where} needs 0–${MAX_TIMER_MS} ms — pass Infinity for no deadline`,\n );\n}\n\n/** A timer that aborts `controller` with a TimeoutError and never keeps Node alive on its own. */\nfunction deadlineTimer(\n controller: AbortController,\n ms: number,\n message: string,\n): ReturnType<typeof setTimeout> {\n const timer = setTimeout(\n () => controller.abort(new DOMException(message, \"TimeoutError\")),\n ms,\n );\n (timer as { unref?: () => unknown }).unref?.();\n return timer;\n}\n\n/**\n * Abort the request when it takes longer than `ms` — counted from the start\n * of the attempt until the body has been fully read, so a server that sends\n * headers and then stalls still trips it. With `idle`, also abort once no\n * data has arrived for that long. Rejects with a `TimeoutError` (a\n * `DOMException`, like `AbortSignal.timeout()` would give); it is not an\n * `ArthronError`, so error interceptors and `retry` leave it alone.\n *\n * A call can change the total deadline with `meta.timeout`.\n *\n * Deadlines are timers on an AbortController — not `AbortSignal.timeout`,\n * since the idle one restarts — joined to the caller's signal with\n * `AbortSignal.any`.\n */\nexport function timeout(ms: number, options: TimeoutOptions = {}): Plugin {\n checkDeadline(ms, `timeout(${ms})`);\n const { idle } = options;\n if (idle !== undefined) checkDeadline(idle, `timeout(…, { idle: ${idle} })`);\n return {\n name: \"timeout\",\n middleware: async (ctx, next) => {\n const deadline = ctx.meta?.timeout ?? ms;\n if (deadline !== ms) checkDeadline(deadline, `meta.timeout: ${deadline}`);\n const idleMs = idle === Number.POSITIVE_INFINITY ? undefined : idle;\n if (deadline === Number.POSITIVE_INFINITY && idleMs === undefined) {\n return next(ctx);\n }\n const controller = new AbortController();\n const outer = ctx.init.signal;\n // The caller's abort and our deadlines, as one signal.\n const signal = outer\n ? AbortSignal.any([outer, controller.signal])\n : controller.signal;\n\n const total =\n deadline === Number.POSITIVE_INFINITY\n ? undefined\n : deadlineTimer(\n controller,\n deadline,\n `arthron: request timed out after ${deadline}ms`,\n );\n let quiet: ReturnType<typeof setTimeout> | undefined;\n // Restarted whenever something arrives: the headers, then every chunk.\n const stillAlive = () => {\n if (idleMs === undefined) return;\n clearTimeout(quiet);\n quiet = deadlineTimer(\n controller,\n idleMs,\n `arthron: no data for ${idleMs}ms`,\n );\n };\n const finish = () => {\n clearTimeout(total);\n clearTimeout(quiet);\n };\n stillAlive();\n\n let res: Response;\n try {\n res = await next({\n ...ctx,\n init: { ...ctx.init, signal },\n });\n } catch (thrown) {\n finish();\n throw thrown;\n }\n if (!res.body) {\n finish();\n return res;\n }\n stillAlive();\n return rebuildResponse(\n res,\n guardBody(res.body, signal, finish, stillAlive),\n );\n },\n };\n}\n"],"mappings":"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"}
|