arthron 1.2.0 → 2.1.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.
@@ -1,333 +0,0 @@
1
- //#region src/types/request.types.d.ts
2
- /**
3
- * What plugins see and return. `init.headers` is always a plain record with
4
- * lowercased names — spread it, read it, add to it — and the pipeline puts
5
- * it back into that shape after every request interceptor.
6
- */
7
- interface RequestContext {
8
- url: string;
9
- init: Omit<RequestInit, "headers"> & {
10
- headers: Record<string, string>;
11
- };
12
- /** Per-call settings for plugins (`RequestOptions.meta`); never sent. */
13
- meta: ArthronMeta;
14
- /**
15
- * The fetch this attempt is sent with — the client's `fetch`, else the
16
- * global one. Always set on contexts arthron creates; replace it to change
17
- * the transport for this attempt, wrap it to observe. Optional so a
18
- * context you build yourself stays valid.
19
- */
20
- fetch?: typeof fetch;
21
- }
22
- /**
23
- * Per-call settings for plugins, passed as `api.get(path, { meta })` and
24
- * carried next to `init` — never sent to fetch. The built-in plugins read
25
- * `bearerAuth`, `onUploadProgress`, `retry` and `timeout`; your own add keys
26
- * by augmentation:
27
- *
28
- * ```ts
29
- * declare module "arthron" {
30
- * interface ArthronMeta { skipTrace?: boolean }
31
- * }
32
- * ```
33
- */
34
- interface ArthronMeta {
35
- /**
36
- * `false` sends this call without the `bearerAuth()` token and never refreshes
37
- * on its 401 — for the login and token-refresh endpoints.
38
- */
39
- bearerAuth?: false;
40
- /**
41
- * Upload progress for this call, with `uploadProgress()` on the client.
42
- * Never called without that plugin or without a body, nor where progress
43
- * cannot be had: a client with an injected `fetch`, another plugin's
44
- * transport, Deno, Bun, Cloudflare Workers, a service worker, or a
45
- * `ReadableStream` body in a browser — those calls are sent as usual.
46
- */
47
- onUploadProgress?: (event: UploadProgressEvent) => void;
48
- /** `false` turns `retry()` off for this call; an object overrides its options. */
49
- retry?: false | Omit<RetryOptions, "sleep">;
50
- /** Deadline for this call in ms, overriding `timeout(ms)`. `Infinity` lifts it. */
51
- timeout?: number;
52
- }
53
- /** One step of an upload, as `meta.onUploadProgress` receives it. */
54
- type UploadProgressEvent = {
55
- /** Bytes sent so far. */
56
- loaded: number;
57
- /** Bytes in the whole body; `undefined` when it cannot be known (a stream without content-length). */
58
- total: number | undefined;
59
- /** `loaded / total`, from 0 to 1; `undefined` when `total` is. */
60
- progress: number | undefined;
61
- };
62
- type RetryOptions = {
63
- /** Number of retries after the first attempt. Default 2 (3 requests total). */
64
- retries?: number;
65
- /** Statuses worth retrying. Network errors (status 0) always are. */
66
- retryOn?: readonly number[];
67
- /** Methods safe to repeat (QUERY is, per RFC 10008). Compared case-insensitively. */
68
- methods?: readonly string[];
69
- /**
70
- * Backoff in ms for retry number `retry` (0-based). Default "full jitter":
71
- * a random share of 300 · 2^retry, so clients that failed together do not
72
- * retry together.
73
- */
74
- delay?: (retry: number, error: unknown) => number;
75
- /**
76
- * Your own verdict on one failure: `true` retries, `false` stops,
77
- * `undefined` leaves it to `retryOn`/`methods`. It sees every error — a
78
- * TimeoutError from a `timeout()` placed after `retry()` included — but
79
- * cannot exceed `retries`, resend a `ReadableStream` body, or retry a call
80
- * the caller aborted.
81
- */
82
- shouldRetry?: (error: unknown, attempt: number, ctx: RequestContext) => boolean | undefined;
83
- /** Called before each wait, for logs and metrics. */
84
- onRetry?: (error: unknown, attempt: number, waitMs: number) => void;
85
- /** Injectable for tests. Default `setTimeout`; rejects with the abort reason. */
86
- sleep?: (ms: number, signal?: AbortSignal | null) => Promise<void>;
87
- /**
88
- * Longest `Retry-After` (ms) worth honouring. Beyond it the request is not
89
- * retried at all. Default 60 000.
90
- */
91
- maxRetryAfter?: number;
92
- };
93
- type QueryValue = string | number | boolean | null | undefined;
94
- /**
95
- * Query parameters. `null`/`undefined` values are skipped, an array becomes
96
- * repeated keys (`ids=1&ids=2`), and a `URLSearchParams` is used as is.
97
- */
98
- type QueryParams = Record<string, QueryValue | readonly QueryValue[]> | URLSearchParams;
99
- /**
100
- * Headers as config and per-call options accept them: anything fetch's
101
- * `headers` takes, or a plain object whose `null`/`undefined` values delete
102
- * that header from the layer underneath (a client default, an inherited
103
- * header). Not spelled `HeadersInit`: that name exists only in the DOM lib,
104
- * and a Node project typed with `@types/node` alone does not have it.
105
- */
106
- type HeadersOption = NonNullable<RequestInit["headers"]> | Record<string, string | null | undefined>;
107
- //#endregion
108
- //#region src/error/arthron-error.d.ts
109
- type ArthronErrorInit = {
110
- message: string;
111
- status: number;
112
- statusText: string;
113
- headers: Headers;
114
- data: unknown;
115
- detail?: string | undefined;
116
- request: RequestContext;
117
- response?: Response;
118
- cause?: unknown;
119
- };
120
- /**
121
- * The only error arthron itself produces. Two sources: a response with
122
- * `ok === false`, or fetch rejecting outright (network failure, `status` 0).
123
- * Everything else — cancellation, interceptor bugs — is rethrown untouched.
124
- */
125
- declare class ArthronError extends Error {
126
- readonly name = "ArthronError";
127
- /** HTTP status of the failed response; `0` when fetch itself failed (network). */
128
- readonly status: number;
129
- readonly statusText: string;
130
- /** Response headers; empty for network failures. Not enumerable — kept out of logs. */
131
- readonly headers: Headers;
132
- /** Parsed body: JSON if it parses, else the text, else `undefined`. */
133
- readonly data: unknown;
134
- /**
135
- * The server's own explanation, picked out of `data` (by default
136
- * `message` → `error` → `error.message` → `detail`; see the `errorDetail`
137
- * config). `undefined` when the body had none. Untrusted server text: show
138
- * it to users as text, never as HTML. `message`, by contrast, is written by
139
- * arthron — method, URL without query, status — and is meant for logs.
140
- */
141
- readonly detail: string | undefined;
142
- /**
143
- * The context that was sent — url and init after request interceptors.
144
- * Not enumerable: it holds credentials, so `JSON.stringify`, `console.error`
145
- * and error trackers leave it out. Read it directly when you need it.
146
- */
147
- readonly request: RequestContext;
148
- /** The failed Response, still readable — its body holds what arthron read (at most 64 KiB). Absent for network failures. Not enumerable. */
149
- readonly response: Response | undefined;
150
- /** The underlying error for network failures. */
151
- readonly cause: unknown;
152
- constructor(init: ArthronErrorInit);
153
- /** `instanceof ArthronError` holds for an error from any copy of the package. */
154
- static [Symbol.hasInstance](value: unknown): boolean;
155
- /** What serializers see: no headers, no body, no query or userinfo. */
156
- toJSON(): {
157
- name: string;
158
- message: string;
159
- detail: string | undefined;
160
- status: number;
161
- statusText: string;
162
- method: string;
163
- url: string;
164
- data: unknown;
165
- };
166
- }
167
- /** `true` for errors arthron produced: a `!ok` response or a network failure. Cancellations and plugin bugs are not ArthronErrors. */
168
- declare function isArthronError(error: unknown): error is ArthronError;
169
- //#endregion
170
- //#region src/types/plugin.types.d.ts
171
- /** Runs before each attempt. Returns the context to send (may be a new object). */
172
- type RequestInterceptor = (ctx: RequestContext) => RequestContext | Promise<RequestContext>;
173
- /** Runs after a successful attempt. The body is single-use — `clone()` to peek. */
174
- type ResponseInterceptor = (res: Response, ctx: RequestContext) => Response | Promise<Response>;
175
- /** Runs after a failed attempt. Returns the error to throw; it is always thrown. */
176
- type ErrorInterceptor = (err: ArthronError, ctx: RequestContext) => ArthronError | Promise<ArthronError>;
177
- /**
178
- * Wraps the whole call. `next` runs everything below it (request interceptors →
179
- * fetch → response/error interceptors) and may be called again to retry.
180
- * `next` rejects with an `ArthronError`, or with the untouched original when the
181
- * failure was a cancellation or a bug in a plugin.
182
- */
183
- type Middleware = (ctx: RequestContext, next: (ctx: RequestContext) => Promise<Response>) => Promise<Response>;
184
- interface Plugin {
185
- /**
186
- * Identity within a client: `use`/`extend` replace the plugin of the same
187
- * name in place, `without(name)` removes it. The built-ins are named
188
- * "bearerAuth", "logging", "retry", "timeout" and "uploadProgress". Leave it out to always
189
- * append.
190
- */
191
- name?: string;
192
- middleware?: Middleware;
193
- request?: RequestInterceptor;
194
- response?: ResponseInterceptor;
195
- error?: ErrorInterceptor;
196
- }
197
- //#endregion
198
- //#region src/plugins/bearer-auth/bearer-auth.types.d.ts
199
- type BearerAuthOptions = {
200
- /**
201
- * Where the token may go: a URL, or several. Only their origins count, so
202
- * your `baseURL` works as is. A request anywhere else — a CDN, a URL taken
203
- * from a response body — is sent without the token.
204
- */
205
- origin: string | readonly string[];
206
- /**
207
- * The current access token, read on every attempt. `null`, `undefined` or
208
- * `""` sends no `authorization` header.
209
- */
210
- token: () => string | null | undefined | Promise<string | null | undefined>;
211
- /**
212
- * Get a new token after a 401; the call is then redone once. Concurrent
213
- * 401s share one refresh, and a call whose token was already replaced
214
- * retries without one. Throw when the refresh fails — every waiting call
215
- * rejects with that error. Requests the refresh makes through the same
216
- * client need `meta: { bearerAuth: false }`. Without `refresh`, or for a
217
- * `ReadableStream` body (already read, so it cannot be resent), a 401 is
218
- * thrown as is.
219
- */
220
- refresh?: () => Promise<void>;
221
- };
222
- //#endregion
223
- //#region src/plugins/bearer-auth/bearer-auth.d.ts
224
- /**
225
- * Bearer-token auth. A request interceptor sets `authorization: Bearer
226
- * <token>` on every attempt to `origin`; with `refresh`, a middleware turns a
227
- * 401 into one refresh and one more try. Concurrent 401s share the refresh
228
- * (with refresh-token rotation, parallel refreshes revoke each other), and a
229
- * call whose token was replaced meanwhile just retries. A call opts out with
230
- * `meta: { bearerAuth: false }`.
231
- */
232
- declare function bearerAuth(options: BearerAuthOptions): Plugin;
233
- //#endregion
234
- //#region src/plugins/logging/logging.types.d.ts
235
- type LogEventBase = {
236
- method: string;
237
- path: string;
238
- };
239
- type LogEvent = ({
240
- phase: "start";
241
- } & LogEventBase) | ({
242
- phase: "success";
243
- status: number;
244
- ms: number;
245
- } & LogEventBase) | ({
246
- phase: "error";
247
- /** HTTP status for an ArthronError (0 = network); undefined for anything else. */
248
- status: number | undefined;
249
- ms: number;
250
- error: unknown;
251
- } & LogEventBase);
252
- type LoggingOptions = {
253
- /** Default `true`. The library never reads `NODE_ENV` — pass `isDev` yourself. */
254
- enabled?: boolean;
255
- logger?: Pick<Console, "log" | "error">;
256
- /** Receive structured events instead of the default console lines. */
257
- onEvent?: (event: LogEvent) => void;
258
- /** Clock in ms. Injectable for tests. */
259
- now?: () => number;
260
- };
261
- //#endregion
262
- //#region src/plugins/logging/logging.d.ts
263
- /**
264
- * One event when a request starts, one when it settles, with status and
265
- * elapsed time. Wraps the whole call, so retries are included in the time.
266
- * Default output is a console line per event; pass `onEvent` to get the
267
- * structured event instead. Cancellations are not reported.
268
- */
269
- declare function logging(options?: LoggingOptions): Plugin;
270
- //#endregion
271
- //#region src/plugins/retry/retry.d.ts
272
- /**
273
- * Retry on network errors and the configured statuses by calling `next`
274
- * again — the whole attempt (request interceptors included) is re-run.
275
- * Only `ArthronError` is considered; cancellation and plugin bugs pass through.
276
- * A call can turn it off or override its options with `meta.retry`.
277
- */
278
- declare function retry(options?: RetryOptions): Plugin;
279
- //#endregion
280
- //#region src/plugins/timeout/timeout.types.d.ts
281
- type TimeoutOptions = {
282
- /**
283
- * Abort after this many ms in all, counted until the body has been fully
284
- * read — the same deadline as `timeout(ms)`. Default: none.
285
- */
286
- total?: number;
287
- /**
288
- * Abort when no data has arrived for this many ms — while waiting for the
289
- * headers and between body chunks. Unlike `total`, a stream that keeps
290
- * flowing is never cut off: `timeout({ idle: 30_000 })`.
291
- */
292
- idle?: number;
293
- };
294
- //#endregion
295
- //#region src/plugins/timeout/timeout.d.ts
296
- /**
297
- * Abort the request when it takes longer than `ms` — counted from the start
298
- * of the attempt until the body has been fully read, so a server that sends
299
- * headers and then stalls still trips it. `timeout({ idle })` instead aborts
300
- * once no data has arrived for that long, and never cuts off a stream that
301
- * keeps flowing; `timeout({ total, idle })` does both. Rejects with a
302
- * `TimeoutError` (a `DOMException`, like `AbortSignal.timeout()` would give);
303
- * it is not an `ArthronError`, so error interceptors and `retry` leave it
304
- * alone.
305
- *
306
- * A call can change the total deadline with `meta.timeout`.
307
- *
308
- * Deadlines are timers on an AbortController — not `AbortSignal.timeout`,
309
- * since the idle one restarts — joined to the caller's signal with
310
- * `AbortSignal.any`.
311
- */
312
- declare function timeout(ms: number): Plugin;
313
- declare function timeout(options: TimeoutOptions): Plugin;
314
- /** @deprecated Use `timeout({ total: ms, idle })`; this form goes in the next major. */
315
- declare function timeout(ms: number, options: Pick<TimeoutOptions, "idle">): Plugin;
316
- //#endregion
317
- //#region src/plugins/upload-progress/upload-progress.d.ts
318
- /**
319
- * Does nothing by itself — only a call that passes `meta.onUploadProgress`
320
- * reports upload progress. On such a call it changes how that one attempt
321
- * is sent: over XMLHttpRequest in a browser, with a counted body in Node.
322
- * Every other call, on this client too, goes out exactly as before.
323
- *
324
- * Progress needs the runtime's own fetch: with an injected `fetch`, another
325
- * plugin's transport, or a runtime that is neither (Deno, Bun, Cloudflare
326
- * Workers, a service worker), the call is sent as usual without progress.
327
- * Put it last in `use`: the call's signal carries a throwing callback's
328
- * error, and an interceptor after it that replaces the signal would cut it.
329
- */
330
- declare function uploadProgress(): Plugin;
331
- //#endregion
332
- export { UploadProgressEvent as S, ArthronMeta as _, logging as a, RequestContext as b, bearerAuth as c, Middleware as d, Plugin as f, isArthronError as g, ArthronError as h, retry as i, BearerAuthOptions as l, ResponseInterceptor as m, timeout as n, LogEvent as o, RequestInterceptor as p, TimeoutOptions as r, LoggingOptions as s, uploadProgress as t, ErrorInterceptor as u, HeadersOption as v, RetryOptions as x, QueryParams as y };
333
- //# sourceMappingURL=index-C3lylSNd.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["isArthronError","cancellationError","redactUrlIn","redactUrl","isReadableStream","runtimeStreamsRequestBody","isCancellation","cancellationError","networkError","responseError","fillPath","resolveUrl","leavesBase","serializeBody","isReadableStream"],"sources":["../src/request/headers.ts","../src/pipeline/pipeline.ts","../src/response/schema-validation.ts","../src/response/stream-parser.ts","../src/response/arthron-promise.ts","../src/client/resolve-config.ts","../src/client/send.ts","../src/client/client.ts","../src/pipeline/define-plugin.ts","../src/index.ts"],"sourcesContent":["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({\n url,\n init,\n meta,\n fetch,\n}: 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 const out: RequestContext = { url, init: copy, meta: { ...meta } };\n if (fetch) out.fetch = fetch;\n return out;\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 const out: RequestContext = {\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\n // meta, nor the fetch it is sent with.\n meta: ctx.meta ?? previous.meta,\n };\n const fetch = ctx.fetch ?? previous.fetch;\n if (fetch) out.fetch = fetch;\n return out;\n}\n\n/**\n * A plugin written in JS (or with a cast) that forgets to return would hand\n * `undefined` on — and an error interceptor's would be what the caller\n * catches. Name the plugin slot instead.\n */\nfunction returned<T>(\n value: T | null | undefined,\n who: string,\n what: string,\n cause?: unknown,\n verb = \"returned\",\n): T {\n if (value != null) return value;\n throw new TypeError(\n `arthron: ${who} ${verb} ${value} — return ${what}`,\n cause === undefined ? undefined : { cause },\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 for (const interceptor of request) {\n const next = returned(\n await interceptor(current),\n \"a request interceptor\",\n \"the context (ctx or a changed copy)\",\n );\n current = normalize(next, current);\n }\n let res: Response;\n try {\n res = await send(current);\n } catch (thrown) {\n // Only send's failures are this request's: an ArthronError a plugin\n // throws (its own call failed) is a plugin exception like any other.\n if (!isArthronError(thrown)) throw thrown;\n let err = thrown;\n for (const interceptor of error) {\n err = returned(\n await interceptor(err, current),\n \"an error interceptor\",\n \"the error (err or a changed one)\",\n thrown,\n );\n }\n throw err;\n }\n for (const interceptor of response) {\n res = returned(\n await interceptor(res, current),\n \"a response interceptor\",\n \"the Response (res or a new one)\",\n );\n }\n return res;\n };\n\n const dispatch = async (\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 // and fetch.\n const res = await middleware(input, (next) => {\n const ctx: RequestContext = { ...next, meta: next.meta ?? input.meta };\n const fetch = next.fetch ?? input.fetch;\n if (fetch) ctx.fetch = fetch;\n return dispatch(index + 1, ctx);\n });\n return returned(\n res,\n \"a middleware\",\n \"the Response, usually `return next(ctx)`\",\n undefined,\n \"resolved with\",\n );\n };\n return dispatch(0, ctx);\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 checked = (line: string): string => {\n if (line.length <= maxLineLength) return line;\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 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 checked(pending + text.slice(start, m.index));\n pending = \"\";\n start = breaks.lastIndex;\n }\n // Checked before the break arrives too, so a line without one cannot\n // grow without bound.\n pending = checked(pending + text.slice(start));\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 { cancellationError } from \"../error/create-error\";\nimport 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 signal: AbortSignal | null | undefined,\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 try {\n yield* parse(await promise);\n } catch (error) {\n throw cancellationError(error, signal);\n }\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(\n promise: Promise<Response>,\n signal?: AbortSignal | null,\n): ArthronPromise {\n // A body read the caller aborted rejects with their reason, whatever the\n // runtime's fetch reports.\n const read = <T>(body: (res: Response) => Promise<T>): Promise<T> =>\n promise.then(body).catch((error: unknown) => {\n throw cancellationError(error, signal);\n });\n return Object.assign(promise, {\n json: ((schema?: StandardSchemaV1) =>\n read(async (res) => {\n const data: unknown = await res.json();\n return schema ? validate(schema, data) : data;\n })) as ArthronPromise[\"json\"],\n text: () => read((res) => res.text()),\n blob: () => read((res) => res.blob()),\n arrayBuffer: () => read((res) => res.arrayBuffer()),\n formData: () => read((res) => res.formData()),\n sse: (options?: SseOptions) =>\n iterate(promise, (res) => parseSse(res, options), signal),\n ndjson: <T = unknown>(options?: NdjsonOptions) =>\n iterate(promise, (res) => parseNdjson<T>(res, options), signal),\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","import {\n cancellationError,\n isCancellation,\n networkError,\n responseError,\n} from \"../error/create-error\";\nimport { isReadableStream, runtimeStreamsRequestBody } from \"../request/body\";\nimport { redactUrl, redactUrlIn } 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 // fetch's own message repeats the full URL, query included.\n const reason = redactUrlIn(\n cause instanceof Error ? cause.message : String(cause),\n url,\n );\n throw new TypeError(\n `arthron: cannot send ${method} ${redactUrl(url)} (${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 * A ReadableStream body the browser cannot stream is rejected before it is\n * sent: Firefox would send the text \"[object ReadableStream]\", older Safari\n * fails with a bare network error. Only for the global fetch, like\n * assertSendable.\n */\nfunction assertStreamable(url: string, method: string, body: unknown): void {\n if (!isReadableStream(body) || runtimeStreamsRequestBody()) return;\n throw new TypeError(\n `arthron: cannot send ${method} ${redactUrl(url)} with a ReadableStream body — this browser cannot stream a request body and would send it garbled or not at all; pass a Blob or ArrayBuffer instead`,\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 // The attempt's own fetch, which a plugin may have replaced or wrapped.\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 = ctx.fetch ?? resolved.fetch ?? globalThis.fetch;\n // Here rather than before the pipeline, so it sees the URL the request\n // interceptors produced. Whenever the client relies on the runtime's fetch\n // — also when a plugin wrapped or swapped it for this attempt (upload\n // progress) — but not for an injected fetch, which owns its URL rules. A\n // TypeError is not an ArthronError: retry and error interceptors leave it\n // alone.\n if (resolved.fetch === undefined) {\n const method = ctx.init.method ?? \"GET\";\n assertSendable(ctx.url, method);\n assertStreamable(ctx.url, method, ctx.init.body);\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 cancellationError(thrown, signal);\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 {\n url,\n init: requestInit,\n meta: { ...meta },\n // Read per call: a global patched after the client was created\n // (msw's `server.listen()`, for one) is still honoured.\n fetch: resolved.fetch ?? globalThis.fetch,\n },\n (ctx) => send(resolved, ctx, throwOn),\n ),\n init.signal,\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 * as plugins from \"./plugins/index\";\n\nexport { arthron } from \"./client/client\";\nexport type {\n Arthron,\n ArthronConfig,\n HttpMethod,\n RequestInitWithBody,\n RequestOptions,\n} from \"./client/client.types\";\nexport { ArthronError, isArthronError } from \"./error/arthron-error\";\nexport {\n defineInterceptor,\n defineMiddleware,\n definePlugin,\n} from \"./pipeline/define-plugin\";\nexport { SchemaError } from \"./response/schema-validation\";\nexport type {\n ErrorInterceptor,\n Middleware,\n Plugin,\n RequestInterceptor,\n ResponseInterceptor,\n} from \"./types/plugin.types\";\nexport type {\n ArthronMeta,\n HeadersOption,\n QueryParams,\n RequestContext,\n RetryOptions,\n} from \"./types/request.types\";\nexport type {\n ArthronPromise,\n ErrorDetailResolver,\n InferOutput,\n NdjsonOptions,\n SchemaIssue,\n SseEvent,\n SseOptions,\n StandardSchemaV1,\n} from \"./types/response.types\";\n\n/*\n * The built-in plugins moved to \"arthron/plugins\". These keep 1.0 imports\n * working until the next major; they are the same functions.\n */\n\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport const logging: typeof plugins.logging = plugins.logging;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport const retry: typeof plugins.retry = plugins.retry;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport const timeout: typeof plugins.timeout = plugins.timeout;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport type LogEvent = plugins.LogEvent;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport type LoggingOptions = plugins.LoggingOptions;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport type TimeoutOptions = plugins.TimeoutOptions;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":["plugins.logging","plugins.retry","plugins.timeout"],"sources":["../src/request/headers.ts","../src/pipeline/pipeline.ts","../src/response/schema-validation.ts","../src/response/stream-parser.ts","../src/response/arthron-promise.ts","../src/client/resolve-config.ts","../src/client/send.ts","../src/client/client.ts","../src/pipeline/define-plugin.ts","../src/index.ts"],"sourcesContent":["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({\n url,\n init,\n meta,\n fetch,\n}: 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 const out: RequestContext = { url, init: copy, meta: { ...meta } };\n if (fetch) out.fetch = fetch;\n return out;\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 const out: RequestContext = {\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\n // meta, nor the fetch it is sent with.\n meta: ctx.meta ?? previous.meta,\n };\n const fetch = ctx.fetch ?? previous.fetch;\n if (fetch) out.fetch = fetch;\n return out;\n}\n\n/**\n * A plugin written in JS (or with a cast) that forgets to return would hand\n * `undefined` on — and an error interceptor's would be what the caller\n * catches. Name the plugin slot instead.\n */\nfunction returned<T>(\n value: T | null | undefined,\n who: string,\n what: string,\n cause?: unknown,\n verb = \"returned\",\n): T {\n if (value != null) return value;\n throw new TypeError(\n `arthron: ${who} ${verb} ${value} — return ${what}`,\n cause === undefined ? undefined : { cause },\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 for (const interceptor of request) {\n const next = returned(\n await interceptor(current),\n \"a request interceptor\",\n \"the context (ctx or a changed copy)\",\n );\n current = normalize(next, current);\n }\n let res: Response;\n try {\n res = await send(current);\n } catch (thrown) {\n // Only send's failures are this request's: an ArthronError a plugin\n // throws (its own call failed) is a plugin exception like any other.\n if (!isArthronError(thrown)) throw thrown;\n let err = thrown;\n for (const interceptor of error) {\n err = returned(\n await interceptor(err, current),\n \"an error interceptor\",\n \"the error (err or a changed one)\",\n thrown,\n );\n }\n throw err;\n }\n for (const interceptor of response) {\n res = returned(\n await interceptor(res, current),\n \"a response interceptor\",\n \"the Response (res or a new one)\",\n );\n }\n return res;\n };\n\n const dispatch = async (\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 // and fetch.\n const res = await middleware(input, (next) => {\n const ctx: RequestContext = { ...next, meta: next.meta ?? input.meta };\n const fetch = next.fetch ?? input.fetch;\n if (fetch) ctx.fetch = fetch;\n return dispatch(index + 1, ctx);\n });\n return returned(\n res,\n \"a middleware\",\n \"the Response, usually `return next(ctx)`\",\n undefined,\n \"resolved with\",\n );\n };\n return dispatch(0, ctx);\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 checked = (line: string): string => {\n if (line.length <= maxLineLength) return line;\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 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 checked(pending + text.slice(start, m.index));\n pending = \"\";\n start = breaks.lastIndex;\n }\n // Checked before the break arrives too, so a line without one cannot\n // grow without bound.\n pending = checked(pending + text.slice(start));\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 { cancellationError } from \"../error/create-error\";\nimport 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 signal: AbortSignal | null | undefined,\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 try {\n yield* parse(await promise);\n } catch (error) {\n throw cancellationError(error, signal);\n }\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(\n promise: Promise<Response>,\n signal?: AbortSignal | null,\n): ArthronPromise {\n // A body read the caller aborted rejects with their reason, whatever the\n // runtime's fetch reports.\n const read = <T>(body: (res: Response) => Promise<T>): Promise<T> =>\n promise.then(body).catch((error: unknown) => {\n throw cancellationError(error, signal);\n });\n return Object.assign(promise, {\n json: ((schema?: StandardSchemaV1) =>\n read(async (res) => {\n const data: unknown = await res.json();\n return schema ? validate(schema, data) : data;\n })) as ArthronPromise[\"json\"],\n text: () => read((res) => res.text()),\n blob: () => read((res) => res.blob()),\n arrayBuffer: () => read((res) => res.arrayBuffer()),\n formData: () => read((res) => res.formData()),\n sse: (options?: SseOptions) =>\n iterate(promise, (res) => parseSse(res, options), signal),\n ndjson: <T = unknown>(options?: NdjsonOptions) =>\n iterate(promise, (res) => parseNdjson<T>(res, options), signal),\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","import {\n cancellationError,\n isCancellation,\n networkError,\n responseError,\n} from \"../error/create-error\";\nimport { isReadableStream, runtimeStreamsRequestBody } from \"../request/body\";\nimport { redactUrl, redactUrlIn } 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 // fetch's own message repeats the full URL, query included.\n const reason = redactUrlIn(\n cause instanceof Error ? cause.message : String(cause),\n url,\n );\n throw new TypeError(\n `arthron: cannot send ${method} ${redactUrl(url)} (${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 * A ReadableStream body the browser cannot stream is rejected before it is\n * sent: Firefox would send the text \"[object ReadableStream]\", older Safari\n * fails with a bare network error. Only for the global fetch, like\n * assertSendable.\n */\nfunction assertStreamable(url: string, method: string, body: unknown): void {\n if (!isReadableStream(body) || runtimeStreamsRequestBody()) return;\n throw new TypeError(\n `arthron: cannot send ${method} ${redactUrl(url)} with a ReadableStream body — this browser cannot stream a request body and would send it garbled or not at all; pass a Blob or ArrayBuffer instead`,\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 // The attempt's own fetch, which a plugin may have replaced or wrapped.\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 = ctx.fetch ?? resolved.fetch ?? globalThis.fetch;\n // Here rather than before the pipeline, so it sees the URL the request\n // interceptors produced. Whenever the client relies on the runtime's fetch\n // — also when a plugin wrapped or swapped it for this attempt (upload\n // progress) — but not for an injected fetch, which owns its URL rules. A\n // TypeError is not an ArthronError: retry and error interceptors leave it\n // alone.\n if (resolved.fetch === undefined) {\n const method = ctx.init.method ?? \"GET\";\n assertSendable(ctx.url, method);\n assertStreamable(ctx.url, method, ctx.init.body);\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 cancellationError(thrown, signal);\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 {\n url,\n init: requestInit,\n meta: { ...meta },\n // Read per call: a global patched after the client was created\n // (msw's `server.listen()`, for one) is still honoured.\n fetch: resolved.fetch ?? globalThis.fetch,\n },\n (ctx) => send(resolved, ctx, throwOn),\n ),\n init.signal,\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 * as plugins from \"./plugins/index\";\n\nexport { arthron } from \"./client/client\";\nexport type {\n Arthron,\n ArthronConfig,\n HttpMethod,\n RequestInitWithBody,\n RequestOptions,\n} from \"./client/client.types\";\nexport { ArthronError, isArthronError } from \"./error/arthron-error\";\nexport {\n defineInterceptor,\n defineMiddleware,\n definePlugin,\n} from \"./pipeline/define-plugin\";\nexport { SchemaError } from \"./response/schema-validation\";\nexport type {\n ErrorInterceptor,\n Middleware,\n Plugin,\n RequestInterceptor,\n ResponseInterceptor,\n} from \"./types/plugin.types\";\nexport type {\n ArthronMeta,\n HeadersOption,\n QueryParams,\n RequestContext,\n RetryOptions,\n} from \"./types/request.types\";\nexport type {\n ArthronPromise,\n ErrorDetailResolver,\n InferOutput,\n NdjsonOptions,\n SchemaIssue,\n SseEvent,\n SseOptions,\n StandardSchemaV1,\n} from \"./types/response.types\";\n\n/*\n * The built-in plugins moved to \"arthron/plugins\". These keep 1.0 imports\n * working until the next major; they are the same functions.\n */\n\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport const logging: typeof plugins.logging = plugins.logging;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport const retry: typeof plugins.retry = plugins.retry;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport const timeout: typeof plugins.timeout = plugins.timeout;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport type LogEvent = plugins.LogEvent;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport type LoggingOptions = plugins.LoggingOptions;\n/** @deprecated Import from \"arthron/plugins\"; this export goes in the next major. */\nexport type TimeoutOptions = plugins.TimeoutOptions;\n"],"mappings":"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"}