@vielzeug/courier 1.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.
- package/README.md +70 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +2 -0
- package/dist/_dev.js.map +1 -0
- package/dist/api.cjs +2 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.ts +43 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -0
- package/dist/batcher.cjs +2 -0
- package/dist/batcher.cjs.map +1 -0
- package/dist/batcher.d.ts +66 -0
- package/dist/batcher.d.ts.map +1 -0
- package/dist/batcher.js +2 -0
- package/dist/batcher.js.map +1 -0
- package/dist/courier.cjs +7 -0
- package/dist/courier.cjs.map +1 -0
- package/dist/courier.d.ts +154 -0
- package/dist/courier.d.ts.map +1 -0
- package/dist/courier.iife.js +7 -0
- package/dist/courier.iife.js.map +1 -0
- package/dist/courier.js +7 -0
- package/dist/courier.js.map +1 -0
- package/dist/devtools.cjs +2 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.ts +31 -0
- package/dist/devtools.d.ts.map +1 -0
- package/dist/devtools.js +2 -0
- package/dist/devtools.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +105 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -0
- package/dist/focus.cjs +2 -0
- package/dist/focus.cjs.map +1 -0
- package/dist/focus.d.ts +25 -0
- package/dist/focus.d.ts.map +1 -0
- package/dist/focus.js +2 -0
- package/dist/focus.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/interceptors.cjs +2 -0
- package/dist/interceptors.cjs.map +1 -0
- package/dist/interceptors.d.ts +50 -0
- package/dist/interceptors.d.ts.map +1 -0
- package/dist/interceptors.js +2 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/mutation.cjs +2 -0
- package/dist/mutation.cjs.map +1 -0
- package/dist/mutation.d.ts +81 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +2 -0
- package/dist/mutation.js.map +1 -0
- package/dist/persist.cjs +2 -0
- package/dist/persist.cjs.map +1 -0
- package/dist/persist.d.ts +86 -0
- package/dist/persist.d.ts.map +1 -0
- package/dist/persist.js +2 -0
- package/dist/persist.js.map +1 -0
- package/dist/query-cache.cjs +2 -0
- package/dist/query-cache.cjs.map +1 -0
- package/dist/query-cache.d.ts +88 -0
- package/dist/query-cache.d.ts.map +1 -0
- package/dist/query-cache.js +2 -0
- package/dist/query-cache.js.map +1 -0
- package/dist/query-observe.cjs +2 -0
- package/dist/query-observe.cjs.map +1 -0
- package/dist/query-observe.d.ts +17 -0
- package/dist/query-observe.d.ts.map +1 -0
- package/dist/query-observe.js +2 -0
- package/dist/query-observe.js.map +1 -0
- package/dist/query.cjs +2 -0
- package/dist/query.cjs.map +1 -0
- package/dist/query.d.ts +110 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +2 -0
- package/dist/query.js.map +1 -0
- package/dist/response.cjs +2 -0
- package/dist/response.cjs.map +1 -0
- package/dist/response.d.ts +4 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +2 -0
- package/dist/response.js.map +1 -0
- package/dist/retry.cjs +2 -0
- package/dist/retry.cjs.map +1 -0
- package/dist/retry.d.ts +34 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +2 -0
- package/dist/retry.js.map +1 -0
- package/dist/serialize.cjs +2 -0
- package/dist/serialize.cjs.map +1 -0
- package/dist/serialize.d.ts +10 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +2 -0
- package/dist/serialize.js.map +1 -0
- package/dist/stream.cjs +7 -0
- package/dist/stream.cjs.map +1 -0
- package/dist/stream.d.ts +113 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +7 -0
- package/dist/stream.js.map +1 -0
- package/dist/sync-store.cjs +2 -0
- package/dist/sync-store.cjs.map +1 -0
- package/dist/sync-store.d.ts +20 -0
- package/dist/sync-store.d.ts.map +1 -0
- package/dist/sync-store.js +2 -0
- package/dist/sync-store.js.map +1 -0
- package/dist/transport.cjs +2 -0
- package/dist/transport.cjs.map +1 -0
- package/dist/transport.d.ts +59 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +2 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/url.cjs +2 -0
- package/dist/url.cjs.map +1 -0
- package/dist/url.d.ts +49 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +2 -0
- package/dist/url.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"courier.cjs","names":[],"sources":["../src/errors.ts","../src/response.ts","../src/serialize.ts","../src/transport.ts","../src/url.ts","../src/api.ts","../src/batcher.ts","../src/retry.ts","../src/mutation.ts","../src/query-cache.ts","../src/query-observe.ts","../src/query.ts","../src/stream.ts","../src/courier.ts","../src/_dev.ts","../src/focus.ts","../src/interceptors.ts","../src/persist.ts","../src/sync-store.ts"],"sourcesContent":["/**\n * Base class for all courier errors.\n * Use `instanceof CourierError` to catch any courier-originated error in one branch.\n * Use `HttpError.is(e, status?)` to check for a specific HTTP status code.\n */\nexport class CourierError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is CourierError {\n return err instanceof CourierError;\n }\n}\n\n/**\n * Thrown when the server responds with a non-2xx HTTP status code.\n * Use `HttpError.is(e, status?)` to narrow to a specific status.\n */\nexport class CourierHttpError extends CourierError {\n readonly url: string;\n readonly method: string;\n readonly status: number;\n readonly data: unknown;\n readonly headers: Headers;\n\n constructor(opts: { data: unknown; headers: Headers; message: string; method: string; status: number; url: string }) {\n super(opts.message);\n this.url = opts.url;\n this.method = opts.method;\n this.status = opts.status;\n this.data = opts.data;\n this.headers = opts.headers;\n }\n\n static fromResponse(res: Response, data: unknown, method: string, url: string): CourierHttpError {\n return new CourierHttpError({\n data,\n headers: res.headers,\n message: res.statusText || `HTTP ${res.status}`,\n method,\n status: res.status,\n url,\n });\n }\n\n static is(err: unknown, status?: number): err is CourierHttpError {\n return err instanceof CourierHttpError && (status === undefined || err.status === status);\n }\n}\n\n/**\n * Thrown when a fetch fails due to a network-level error (DNS, TCP, CORS, etc.)\n * with no HTTP response. Distinct from `HttpError` so callers never need to check\n * for a missing `status` field.\n */\nexport class CourierNetworkError extends CourierError {\n readonly url: string;\n readonly method: string;\n\n constructor(opts: { cause?: unknown; message: string; method: string; url: string }) {\n super(opts.message, { cause: opts.cause });\n this.url = opts.url;\n this.method = opts.method;\n }\n}\n\n/**\n * Thrown when a request is aborted via `AbortSignal.timeout()` or a caller-supplied\n * timeout option. Distinct from `AbortError` so callers can show retry UI on timeouts\n * without checking any `kind` discriminant.\n */\nexport class CourierTimeoutError extends CourierError {\n readonly url: string;\n readonly method: string;\n\n constructor(opts: { cause?: unknown; message: string; method: string; url: string }) {\n super(opts.message, { cause: opts.cause });\n this.url = opts.url;\n this.method = opts.method;\n }\n}\n\n/**\n * Thrown when a request is cancelled via a caller-supplied `AbortSignal` or\n * `cancelAll()` / `dispose()`. Safe to ignore in most UI handlers.\n */\nexport class CourierAbortError extends CourierError {\n readonly url: string;\n readonly method: string;\n\n constructor(opts: { cause?: unknown; message: string; method: string; url: string }) {\n super(opts.message, { cause: opts.cause });\n this.url = opts.url;\n this.method = opts.method;\n }\n}\n\n/**\n * Thrown when a response body fails schema validation (via the `schema` option).\n * Distinct from the HTTP error classes so callers can separately handle network failures\n * vs. data contract violations without inspecting the error shape.\n */\nexport class CourierSchemaValidationError extends CourierError {\n /** The raw (pre-validation) response body that failed parsing. */\n readonly data: unknown;\n\n constructor(cause: unknown, data: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n this.data = data;\n }\n}\n\n/** Thrown when the batcher's resolve function returns an unexpected number of results. */\nexport class CourierBatcherError extends CourierError {}\n\n/** Thrown when a method is called on a disposed client instance. */\nexport class CourierDisposedError extends CourierError {\n constructor(clientName: string) {\n super(`[courier] ${clientName} disposed`);\n }\n}\n\n/** Thrown when a response body cannot be read or parsed. */\nexport class CourierParseError extends CourierError {}\n\n/**\n * Classify an error thrown by `fetch` or an abort signal into the appropriate\n * courier error class. Signal reason is checked first so a timed-out signal\n * always produces `TimeoutError` even when `fetch` throws a generic Error.\n *\n * We check `.name` rather than `instanceof DOMException` because `AbortSignal.timeout()`\n * sets reason to the *native* Node.js DOMException which may differ from the environment's\n * global DOMException (e.g. jsdom), causing `instanceof` checks to fail cross-realm.\n */\nexport function classifyRequestError(\n cause: unknown,\n method: string,\n url: string,\n signal?: AbortSignal,\n): CourierNetworkError | CourierTimeoutError | CourierAbortError {\n const message = cause instanceof Error ? cause.message : String(cause);\n\n // Signal reason is authoritative — a timed-out signal carries a TimeoutError reason\n // regardless of what error `fetch` actually threw.\n const reason = signal?.reason;\n\n if (reason instanceof Error && reason.name === 'TimeoutError') {\n return new CourierTimeoutError({ cause, message, method, url });\n }\n\n if (cause instanceof DOMException) {\n if (cause.name === 'TimeoutError') return new CourierTimeoutError({ cause, message, method, url });\n\n return new CourierAbortError({ cause, message, method, url });\n }\n\n if ((cause instanceof Error && cause.name === 'AbortError') || signal?.aborted) {\n return new CourierAbortError({ cause, message, method, url });\n }\n\n return new CourierNetworkError({ cause, message, method, url });\n}\n","/** Response parsing strategy. 'raw' returns the Response object directly. */\nexport type ResponseType = 'auto' | 'json' | 'text' | 'blob' | 'arrayBuffer' | 'raw';\n\nexport async function parseResponse(res: Response, responseType: ResponseType = 'auto'): Promise<unknown> {\n if (responseType === 'raw') return res;\n\n if (res.status === 204 || res.status === 205 || res.status === 304) return;\n\n if (responseType === 'json') return res.json();\n\n if (responseType === 'text') return res.text();\n\n if (responseType === 'blob') return res.blob();\n\n if (responseType === 'arrayBuffer') return res.arrayBuffer();\n\n const contentType = res.headers.get('content-type') ?? '';\n\n if (contentType.includes('application/json') || contentType.includes('+json')) return res.json();\n\n if (contentType.startsWith('text/')) return res.text();\n\n if (contentType.startsWith('image/') || contentType.startsWith('audio/') || contentType.startsWith('video/')) {\n return res.blob();\n }\n\n // Unknown content-type — fall back to text, which is always safe to read and debug.\n return res.text();\n}\n","import { hash } from '@vielzeug/arsenal';\n\nexport { hash };\n\n/**\n * Build a `RequestInit` object from the request components, handling body serialisation.\n * Plain objects/arrays are JSON-serialised and `content-type: application/json` is added.\n * BodyInit values (FormData, Blob, etc.) are forwarded as-is.\n */\nexport function buildRequestInit(\n method: string,\n headers: Record<string, string>,\n body: unknown,\n signal: AbortSignal | undefined,\n rest: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>,\n): RequestInit {\n if (body !== undefined && !isBodyInit(body)) {\n return {\n ...rest,\n body: JSON.stringify(body),\n headers: { 'content-type': 'application/json', ...headers },\n method: method.toUpperCase(),\n signal,\n };\n }\n\n return {\n ...rest,\n ...(body !== undefined && { body: body as BodyInit }),\n headers,\n method: method.toUpperCase(),\n signal,\n };\n}\n\nexport function isBodyInit(value: unknown): value is BodyInit {\n return (\n value instanceof FormData ||\n value instanceof Blob ||\n value instanceof URLSearchParams ||\n typeof value === 'string' ||\n value instanceof ArrayBuffer ||\n ArrayBuffer.isView(value) ||\n (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream)\n );\n}\n","import { CourierError } from './errors';\n\n/**\n * Immutable request context passed through the interceptor pipeline.\n *\n * **Never mutate `init` or `headers` directly.** Use `ctx.withHeaders(updates)` to\n * produce a new context with merged headers — this is the safe, idiomatic pattern\n * for interceptors that need to add or override headers.\n *\n * @example\n * ```ts\n * // Correct — returns a new context\n * return next(ctx.withHeaders({ authorization: `Bearer ${token}` }));\n *\n * // Wrong — mutates shared state, risks stomping other interceptors\n * ctx.init.headers = { ...ctx.init.headers, authorization: `Bearer ${token}` };\n * ```\n */\nexport type FetchContext = {\n readonly headers: Readonly<Record<string, string>>;\n readonly init: Readonly<Omit<RequestInit, 'headers'>>;\n readonly url: string;\n /** Returns a new `FetchContext` with the given header overrides merged in (lowercase keys). */\n withHeaders(updates: Record<string, string>): FetchContext;\n};\n\nfunction makeFetchContext(\n url: string,\n headers: Record<string, string>,\n init: Omit<RequestInit, 'headers'>,\n): FetchContext {\n const ctx: FetchContext = {\n headers,\n init,\n url,\n withHeaders(updates: Record<string, string>): FetchContext {\n const merged = { ...headers };\n\n for (const [k, v] of Object.entries(updates)) merged[k.toLowerCase()] = v;\n\n return makeFetchContext(url, merged, init);\n },\n };\n\n return ctx;\n}\n\nexport function anySignal(...signals: ReadonlyArray<AbortSignal | null | undefined>): AbortSignal | undefined {\n const active = signals.filter((s): s is AbortSignal => s != null);\n\n if (active.length === 0) return undefined;\n\n if (active.length === 1) return active[0];\n\n return AbortSignal.any(active);\n}\nexport type Interceptor = (ctx: FetchContext, next: (ctx: FetchContext) => Promise<Response>) => Promise<Response>;\n\nexport type TransportOptions = {\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n headers?: Record<string, string>;\n timeout?: number;\n};\n\nexport const DEFAULT_TIMEOUT = 30_000;\n\nexport function validateTimeout(timeoutMs: number): void {\n if ((timeoutMs <= 0 || !Number.isFinite(timeoutMs)) && timeoutMs !== Number.POSITIVE_INFINITY) {\n throw new CourierError('[courier] timeout must be a positive number or Infinity');\n }\n}\n\nexport function buildTimeoutSignal(timeoutMs: number, external?: AbortSignal | null): AbortSignal | undefined {\n if (timeoutMs === Number.POSITIVE_INFINITY) {\n return external ?? undefined;\n }\n\n return anySignal(AbortSignal.timeout(timeoutMs), external);\n}\n\n/**\n * Shared transport core: interceptor pipeline, header management, AbortController lifecycle.\n * Both `createApi` and `createStream` build on this to avoid duplicating infrastructure.\n */\nexport function createTransportCore(opts: TransportOptions = {}) {\n const {\n baseUrl = '',\n fetch: fetchFn = globalThis.fetch,\n headers: initialHeaders = {},\n timeout = DEFAULT_TIMEOUT,\n } = opts;\n\n validateTimeout(timeout);\n\n const globalHeaders: Record<string, string> = Object.fromEntries(\n Object.entries(initialHeaders).map(([k, v]) => [k.toLowerCase(), v]),\n );\n const activeControllers = new Set<AbortController>();\n const disposeController = new AbortController();\n const interceptors: Interceptor[] = [];\n let cachedPipeline: ((ctx: FetchContext) => Promise<Response>) | null = null;\n let disposed = false;\n\n function getPipeline(): (ctx: FetchContext) => Promise<Response> {\n if (cachedPipeline) return cachedPipeline;\n\n const base: (ctx: FetchContext) => Promise<Response> = (ctx) =>\n fetchFn(ctx.url, { ...ctx.init, headers: ctx.headers });\n\n cachedPipeline =\n interceptors.length === 0\n ? base\n : interceptors.reduceRight<(ctx: FetchContext) => Promise<Response>>(\n (next, interceptor) => (ctx) => interceptor(ctx, next),\n base,\n );\n\n return cachedPipeline;\n }\n\n function use(interceptor: Interceptor): () => void {\n interceptors.push(interceptor);\n cachedPipeline = null;\n\n return () => {\n const i = interceptors.indexOf(interceptor);\n\n if (i !== -1) {\n interceptors.splice(i, 1);\n cachedPipeline = null;\n }\n };\n }\n\n function headers(updates: Record<string, string | undefined>): void {\n for (const [key, value] of Object.entries(updates)) {\n const k = key.toLowerCase();\n\n if (value === undefined) delete globalHeaders[k];\n else globalHeaders[k] = value;\n }\n }\n\n /** Returns a read-only snapshot of the current global headers. */\n function getHeaders(): Readonly<Record<string, string>> {\n return { ...globalHeaders };\n }\n\n /**\n * Merge global headers with optional per-request and extra headers.\n * Per-request keys are normalised to lowercase.\n */\n function mergeHeaders(perRequest?: Record<string, string>, extra?: Record<string, string>): Record<string, string> {\n const normalized = perRequest\n ? Object.fromEntries(Object.entries(perRequest).map(([k, v]) => [k.toLowerCase(), v]))\n : undefined;\n\n return { ...globalHeaders, ...normalized, ...extra };\n }\n\n /** Register an AbortController for lifecycle tracking (cancelAll / dispose). Returns an untrack fn. */\n function track(ac: AbortController): () => void {\n activeControllers.add(ac);\n\n return () => activeControllers.delete(ac);\n }\n\n /**\n * Dispatch a request through the interceptor pipeline.\n * Accepts a plain `{ url, headers, init }` object and promotes it to a\n * full `FetchContext` with `withHeaders()` before entering the pipeline.\n */\n function dispatch(raw: {\n headers: Record<string, string>;\n init: Omit<RequestInit, 'headers'>;\n url: string;\n }): Promise<Response> {\n return getPipeline()(makeFetchContext(raw.url, raw.headers, raw.init));\n }\n\n function cancelAll(): void {\n for (const ac of [...activeControllers]) ac.abort();\n activeControllers.clear();\n }\n\n function dispose(): void {\n if (disposed) return;\n\n disposed = true;\n disposeController.abort();\n\n for (const ac of activeControllers) ac.abort();\n\n activeControllers.clear();\n interceptors.length = 0;\n cachedPipeline = null;\n }\n\n return {\n baseUrl,\n cancelAll,\n dispatch,\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getHeaders,\n /** Returns the configured request timeout in ms. */\n getTimeout(): number {\n return timeout;\n },\n headers,\n mergeHeaders,\n track,\n use,\n };\n}\n\nexport type TransportCore = ReturnType<typeof createTransportCore>;\n","import type { ResponseType } from './response';\n\nimport { CourierParseError } from './errors';\n\ntype QueryScalar = string | number | boolean | null;\n\nexport type ParamValue = QueryScalar | readonly QueryScalar[] | undefined;\nexport type Params = Record<string, ParamValue>;\n\n// Type-safe path params: extracts {param} placeholders from a path string\ntype ExtractPathParams<P extends string> = P extends `${string}{${infer K}}${infer R}`\n ? K | ExtractPathParams<R>\n : never;\n\nexport type PathConfig<P extends string> = [ExtractPathParams<P>] extends [never]\n ? { params?: never }\n : { params: Record<ExtractPathParams<P>, string | number | boolean> };\n\nexport type CourierRequestConfig<P extends string = string, T = unknown> = PathConfig<P> & {\n /** Request body. Plain objects → JSON. BodyInit values passed as-is. */\n body?: unknown;\n /**\n * Set to `false` to bypass in-flight deduplication for this request.\n * Safe + idempotent methods (GET, HEAD, OPTIONS) are deduplicated by default.\n * DELETE is idempotent but has side-effects, so it does not auto-dedupe;\n * pass an explicit `dedupeKey` to opt in.\n */\n dedupe?: boolean;\n /** Explicit deduplication key for non-idempotent requests. */\n dedupeKey?: unknown;\n /** Query string parameters. */\n query?: Params;\n /** Response parsing strategy. */\n responseType?: ResponseType;\n /**\n * Optional schema for response validation. Any object with a `parse(data)` method\n * works — e.g. a `@vielzeug/spell` schema or a plain validator function wrapper.\n * Called after the response body is parsed; throws if validation fails.\n * The schema's return type must be assignable to `T`.\n */\n schema?: { parse(data: unknown): T };\n /** Request timeout in ms. Overrides client default. */\n timeout?: number;\n};\n\nexport type HttpRequestConfig<P extends string = string, T = unknown> = CourierRequestConfig<P, T> & {\n /** Raw fetch options for advanced use (credentials, cache, mode, referrer, etc.). */\n fetchInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>;\n /** Per-request headers merged with (and overriding) global client headers. */\n headers?: Record<string, string>;\n /** External abort signal merged with internal cancellation. */\n signal?: AbortSignal;\n};\n\nexport function buildUrl(base: string, path: string, params?: Params, query?: Params): string {\n const baseClean = base.replace(/\\/+$/, '');\n let pathClean = path.replace(/^\\/+/, '');\n\n pathClean = pathClean.replace(/\\{([^}]+)\\}/g, (_, key: string) => {\n const val = params?.[key];\n\n if (val === undefined || val === null) throw new CourierParseError(`unresolved path param {${key}} in '${path}'`);\n\n return encodeURIComponent(String(val));\n });\n\n const url = baseClean && pathClean ? `${baseClean}/${pathClean}` : baseClean || pathClean;\n\n if (!query) return url;\n\n const qs = new URLSearchParams();\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) {\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (entry !== undefined) {\n qs.append(key, entry === null ? '' : String(entry));\n }\n }\n\n continue;\n }\n\n qs.append(key, value === null ? '' : String(value));\n }\n\n const queryString = qs.toString();\n\n return queryString ? `${url}${url.includes('?') ? '&' : '?'}${queryString}` : url;\n}\n","import type { HttpRequestConfig, Params } from './url';\n\nimport { classifyRequestError, CourierDisposedError, CourierHttpError, CourierSchemaValidationError } from './errors';\nimport { parseResponse } from './response';\nimport { buildRequestInit, hash } from './serialize';\nimport {\n anySignal,\n buildTimeoutSignal,\n createTransportCore,\n type FetchContext,\n type Interceptor,\n type TransportCore,\n type TransportOptions,\n validateTimeout,\n} from './transport';\nimport { buildUrl } from './url';\n\nexport type { FetchContext, Interceptor };\n\n// Only safe + idempotent methods are auto-deduplicated. DELETE is idempotent but\n// not safe (it produces a side-effect), so it must opt-in via explicit dedupeKey\n// to avoid silently coalescing concurrent destructive requests.\nconst IDEMPOTENT_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\n\nfunction getDedupeKey(\n method: string,\n url: string,\n responseType: string,\n dedupeKey: HttpRequestConfig['dedupeKey'],\n): string | undefined {\n if (IDEMPOTENT_METHODS.has(method)) {\n // Key on method + URL + responseType only. Headers are uniform within a\n // single client instance and should not prevent deduplication when a token\n // refresh updates globalHeaders mid-flight.\n return `${method}:${url}:${responseType}`;\n }\n\n if (dedupeKey === undefined) {\n return undefined;\n }\n\n return `${method}:${url}:${hash(dedupeKey)}`;\n}\n\n/**\n * Creates a typed REST client — `get`/`post`/`put`/`patch`/`delete`/`request`, all backed by a\n * shared interceptor pipeline, header management, and `AbortController` lifecycle.\n *\n * Safe + idempotent requests (`GET`/`HEAD`/`OPTIONS`) are deduplicated by default — concurrent\n * calls with the same method, URL, and response type share a single in-flight request.\n *\n * @example\n * ```ts\n * const api = createApi({ baseUrl: 'https://api.example.com', timeout: 10_000 });\n *\n * const user = await api.get<User>('/users/{id}', { params: { id: '1' } });\n * const created = await api.post<User>('/users', { body: { name: 'Ada' } });\n *\n * api.use(async (ctx, next) => next(ctx.withHeaders({ authorization: `Bearer ${token}` })));\n *\n * // later:\n * api.dispose();\n * ```\n */\nexport function createApi(opts?: TransportOptions & { transport?: TransportCore }) {\n const { transport: sharedTransport, ...transportOpts } = opts ?? {};\n const transport = sharedTransport ?? createTransportCore(transportOpts);\n const ownTransport = !sharedTransport;\n const inFlight = new Map<string, Promise<unknown>>();\n\n async function execute<T>(\n headers: Record<string, string>,\n init: Omit<RequestInit, 'headers'>,\n full: string,\n m: string,\n responseType: HttpRequestConfig['responseType'],\n schema?: { parse(data: unknown): T },\n ): Promise<T> {\n const signal = init.signal as AbortSignal | undefined;\n let res: Response;\n\n try {\n res = await transport.dispatch({ headers, init, url: full });\n } catch (err) {\n throw classifyRequestError(err, m, full, signal);\n }\n\n if (!res.ok) {\n // For error responses: parse body using normal content-type detection,\n // fall back to text for unknown content-types (better than blob for debugging).\n let body: unknown;\n\n try {\n body = await parseResponse(res, responseType ?? 'auto');\n } catch {\n body = await res.text().catch(() => '');\n }\n\n throw CourierHttpError.fromResponse(res, body, m, full);\n }\n\n let raw: unknown;\n\n try {\n raw = await parseResponse(res, responseType ?? 'auto');\n } catch (err) {\n throw classifyRequestError(err, m, full, signal);\n }\n\n if (schema) {\n try {\n return schema.parse(raw);\n } catch (err) {\n throw new CourierSchemaValidationError(err, raw);\n }\n }\n\n return raw as T;\n }\n\n async function request<T, P extends string = string>(\n method: string,\n url: P,\n config: HttpRequestConfig<P> = {} as HttpRequestConfig<P>,\n ) {\n if (transport.disposed) throw new CourierDisposedError('ApiClient');\n\n const m = method.toUpperCase();\n\n let full: string;\n\n try {\n full = buildUrl(transport.baseUrl, url, config.params as Params | undefined, config.query);\n } catch (err) {\n throw classifyRequestError(err, m, url);\n }\n\n const {\n body,\n dedupe = true,\n dedupeKey,\n fetchInit,\n headers,\n responseType,\n schema,\n signal: extSignal,\n timeout: cfgTimeout,\n } = config as HttpRequestConfig;\n\n if (cfgTimeout !== undefined) validateTimeout(cfgTimeout);\n\n const mergedHeaders = transport.mergeHeaders(headers);\n const requestDedupeKey = dedupe ? getDedupeKey(m, full, responseType ?? 'auto', dedupeKey) : undefined;\n\n if (requestDedupeKey) {\n const existing = inFlight.get(requestDedupeKey);\n\n if (existing) return existing as Promise<T>;\n }\n\n const requestAc = new AbortController();\n const untrack = transport.track(requestAc);\n const combinedExt = anySignal(extSignal, requestAc.signal) ?? requestAc.signal;\n const signal = buildTimeoutSignal(cfgTimeout ?? transport.getTimeout(), combinedExt);\n\n const { headers: initHeaders, ...restInit } = buildRequestInit(m, mergedHeaders, body, signal, fetchInit ?? {});\n const p = execute<T>(\n initHeaders as Record<string, string>,\n restInit,\n full,\n m,\n responseType,\n schema as { parse(data: unknown): T } | undefined,\n );\n\n if (requestDedupeKey) inFlight.set(requestDedupeKey, p);\n\n try {\n return (await p) as T;\n } finally {\n if (requestDedupeKey) inFlight.delete(requestDedupeKey);\n\n untrack();\n }\n }\n\n return {\n cancelAll(): void {\n // Note: narrow race — a request that starts after the abort signals fire but before\n // their in-flight promise settles may see an empty inFlight map and error a redundant\n // request. This is an accepted trade-off for the simplicity of a synchronous clear.\n transport.cancelAll();\n inFlight.clear();\n },\n delete: <T, P extends string = string>(url: P, cfg?: HttpRequestConfig<P>) => request<T, P>('DELETE', url, cfg),\n get disposalSignal() {\n return transport.disposalSignal;\n },\n dispose(): void {\n inFlight.clear();\n\n if (ownTransport) transport.dispose();\n },\n get disposed() {\n return transport.disposed;\n },\n get: <T, P extends string = string>(url: P, cfg?: HttpRequestConfig<P>) => request<T, P>('GET', url, cfg),\n getHeaders: transport.getHeaders,\n headers: transport.headers,\n patch: <T, P extends string = string>(url: P, cfg?: HttpRequestConfig<P>) => request<T, P>('PATCH', url, cfg),\n post: <T, P extends string = string>(url: P, cfg?: HttpRequestConfig<P>) => request<T, P>('POST', url, cfg),\n put: <T, P extends string = string>(url: P, cfg?: HttpRequestConfig<P>) => request<T, P>('PUT', url, cfg),\n request,\n [Symbol.dispose](): void {\n this.dispose();\n },\n use: transport.use,\n };\n}\n\nexport type ApiClient = ReturnType<typeof createApi>;\n","import { CourierBatcherError, CourierDisposedError } from './errors';\n\ntype BatcherBase = {\n /** Maximum batch size before a flush is forced. Defaults to `25`. */\n maxSize?: number;\n /**\n * Scheduling window in ms. Defaults to `0` (next microtask), which coalesces\n * all `load()` calls within the same synchronous block into one batch.\n * Set a positive value (e.g. `16`) to coalesce across async boundaries.\n */\n window?: number;\n};\n\n/**\n * Batcher options. Exactly one of `resolve` or `resolveSettled` must be provided — they are mutually exclusive.\n *\n * - **`resolve`**: execute a batch and return results in the same order. All succeed or all fail.\n * - **`resolveSettled`**: per-key error isolation — each `load()` fulfills or rejects independently.\n */\nexport type BatcherOptions<K, V> =\n | (BatcherBase & {\n /**\n * Execute a batch of keys and return results in the same order.\n * The returned array must have the same length as `keys`.\n */\n resolve: (keys: K[]) => Promise<V[]>;\n resolveSettled?: never;\n })\n | (BatcherBase & {\n resolve?: never;\n /**\n * Per-key error isolation. Receives the same key array but must return a\n * `PromiseSettledResult<V>[]` of equal length. Each `load()` promise fulfills\n * or rejects independently based on its corresponding settled result.\n */\n resolveSettled: (keys: K[]) => Promise<PromiseSettledResult<V>[]>;\n });\n\ntype PendingItem<K, V> = {\n key: K;\n reject: (reason: unknown) => void;\n resolve: (value: V) => void;\n};\n\n/**\n * DataLoader-style request batcher. Coalesces individual `load()` calls made\n * within the same scheduling window into a single `resolve()` call.\n *\n * Typical use: N+1 query elimination, request fan-out coalescing.\n *\n * @example\n * ```ts\n * const userLoader = createBatcher({\n * resolve: async (ids) => api.post<User[]>('/users/batch', { body: { ids } }),\n * });\n *\n * // These 3 calls collapse into 1 POST /users/batch { ids: [1, 2, 3] }\n * const [alice, bob, carol] = await Promise.all([\n * userLoader.load(1),\n * userLoader.load(2),\n * userLoader.load(3),\n * ]);\n * ```\n */\nexport function createBatcher<K, V>(opts: BatcherOptions<K, V>) {\n const { maxSize = 25, resolve, resolveSettled, window: windowMs = 0 } = opts;\n\n const queue: PendingItem<K, V>[] = [];\n const controller = new AbortController();\n let scheduled = false;\n let pendingTimer: ReturnType<typeof setTimeout> | null = null;\n let disposed = false;\n\n function flush(): void {\n if (queue.length === 0) return;\n\n const batch = queue.splice(0, maxSize);\n\n // If more items remain after taking maxSize, schedule another flush immediately.\n if (queue.length > 0) schedule();\n\n const keys = batch.map((item) => item.key);\n\n // resolve()/resolveSettled() are called directly (not just chained with .then/.catch) so a\n // consumer function that throws synchronously — rather than returning a rejected promise —\n // still rejects every pending load() instead of leaving them hanging forever.\n try {\n if (resolveSettled) {\n void resolveSettled(keys)\n .then((results) => {\n if (results.length !== batch.length) {\n const err = new CourierBatcherError(\n `Batcher: resolveSettled() returned ${results.length} results for ${batch.length} keys`,\n );\n\n for (const item of batch) item.reject(err);\n\n return;\n }\n\n batch.forEach((item, i) => {\n const r = results[i];\n\n if (r.status === 'fulfilled') {\n item.resolve(r.value);\n } else {\n item.reject(r.reason);\n }\n });\n })\n .catch((err: unknown) => {\n for (const item of batch) item.reject(err);\n });\n } else {\n void resolve(keys)\n .then((results) => {\n if (results.length !== batch.length) {\n const err = new CourierBatcherError(\n `Batcher: resolve() returned ${results.length} results for ${batch.length} keys`,\n );\n\n for (const item of batch) item.reject(err);\n\n return;\n }\n\n batch.forEach((item, i) => item.resolve(results[i]));\n })\n .catch((err: unknown) => {\n for (const item of batch) item.reject(err);\n });\n }\n } catch (err) {\n for (const item of batch) item.reject(err);\n }\n }\n\n function schedule(): void {\n if (scheduled) return;\n\n scheduled = true;\n\n if (windowMs === 0) {\n queueMicrotask(() => {\n scheduled = false;\n flush();\n });\n } else {\n pendingTimer = setTimeout(() => {\n pendingTimer = null;\n scheduled = false;\n flush();\n }, windowMs);\n }\n }\n\n return {\n get disposalSignal(): AbortSignal {\n return controller.signal;\n },\n\n /**\n * Cancels all pending `load()` promises with a disposal error and stops\n * any scheduled flushes. Safe to call multiple times.\n */\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n\n if (pendingTimer !== null) {\n clearTimeout(pendingTimer);\n pendingTimer = null;\n }\n\n const err = new CourierDisposedError('Batcher');\n\n for (const item of queue.splice(0)) item.reject(err);\n\n scheduled = false;\n controller.abort();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n load(key: K): Promise<V> {\n if (disposed) return Promise.reject(new CourierDisposedError('Batcher'));\n\n return new Promise<V>((res, rej) => {\n queue.push({ key, reject: rej, resolve: res });\n\n if (queue.length >= maxSize) {\n // Force-flush immediately when the batch is full.\n // Cancel any pending timer first so it cannot fire a second flush.\n if (pendingTimer !== null) {\n clearTimeout(pendingTimer);\n pendingTimer = null;\n }\n\n scheduled = false;\n flush();\n } else {\n schedule();\n }\n });\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport type Batcher<K, V> = ReturnType<typeof createBatcher<K, V>>;\n","import { backoff } from '@vielzeug/arsenal';\n\n/** Internal default: one attempt, no retries. */\nexport const DEFAULT_TIMES = 1;\n\nexport type RetryOptions = {\n /**\n * Delay between retry attempts in ms, or a function receiving the zero-based\n * attempt index (`attempt = 0` means the wait before the 2nd try, after the\n * 1st failure). Defaults to full-jitter exponential backoff: a random delay\n * in `[0, min(1 s × 2ⁿ, 30 s)]` where `n` is the zero-based attempt index.\n *\n * @example\n * ```ts\n * // Linear backoff: 500 ms, 1 000 ms, 1 500 ms, …\n * delay: (attempt) => (attempt + 1) * 500\n * ```\n */\n delay?: number | ((attempt: number) => number);\n /**\n * Return `false` to skip retrying for a specific error (e.g. 4xx HTTP errors).\n * `attempt` is zero-based: `0` means \"deciding whether to retry after the 1st\n * failure\", `1` means \"after the 2nd failure\", and so on.\n */\n shouldRetry?: (error: unknown, attempt: number) => boolean;\n /** Total number of attempts including the first. `1` means a single try with no retries. Defaults to `1`. */\n times?: number;\n};\n\n/**\n * Full-jitter exponential backoff: a random delay in `[0, min(1s × 2ⁿ, 30s)]` where `n` is the\n * zero-based attempt index. Shared default delay for both retries (`retry()`/mutations/queries)\n * and stream reconnects (`sse()`/`readable()`).\n */\nexport function fullJitterDelay(attempt: number): number {\n return Math.random() * backoff(attempt);\n}\n\n/** Compute the inter-attempt delay from a courier RetryOptions configuration. */\nexport function resolveRetryDelay(attempt: number, userDelay?: number | ((attempt: number) => number)): number {\n if (typeof userDelay === 'function') {\n const ms = userDelay(attempt);\n\n return Number.isFinite(ms) ? Math.max(0, ms) : 0;\n }\n\n if (typeof userDelay === 'number') {\n return Number.isFinite(userDelay) ? Math.max(0, userDelay) : 0;\n }\n\n return fullJitterDelay(attempt);\n}\n","import { isAbortError, retry } from '@vielzeug/arsenal';\n\nimport type { RetryOptions } from './retry';\nimport type { MutationState, SyncStore, Unsubscribe } from './types';\n\nimport { CourierDisposedError } from './errors';\nimport { resolveRetryDelay } from './retry';\nimport { anySignal } from './transport';\n\nconst IDLE_STATE: MutationState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: false,\n status: 'loading',\n updatedAt: undefined,\n});\n\n/**\n * Discriminated union result passed to `onSettled`.\n * Switch on `result.status` to handle each outcome exhaustively.\n */\nexport type SettledResult<TData, TVariables> =\n | { readonly data: TData; readonly status: 'success'; readonly variables: TVariables }\n | { readonly error: Error; readonly status: 'error'; readonly variables: TVariables }\n | { readonly status: 'aborted'; readonly variables: TVariables };\n\nexport type MutationOptions<TData = unknown, TVariables = void> = RetryOptions & {\n /**\n * Called when a lifecycle callback (`onSuccess`, `onError`, `onSettled`, or `onFinally`) throws.\n * Does not affect the `mutate()` result or re-throw. Optional — for development/debugging.\n */\n onCallbackError?: (error: Error) => void;\n /**\n * Called after a failed run, before `mutate()` rejects.\n * Not called when the mutation was aborted (use `onSettled` if you need abort awareness).\n */\n onError?: (error: Error, variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Use for cleanup patterns that do not need to inspect the result.\n * Runs after `onSuccess` / `onError` and before `onSettled`.\n */\n onFinally?: (variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Switch on `result.status` to handle `'success'`, `'error'`, or `'aborted'` exhaustively.\n */\n onSettled?: (result: SettledResult<TData, TVariables>) => void | Promise<void>;\n /** Called after a successful run, before `mutate()` resolves. */\n onSuccess?: (data: TData, variables: TVariables) => void | Promise<void>;\n};\n\nexport type MutationFn<TData, TVariables = void> = (input: TVariables, signal: AbortSignal) => Promise<TData>;\n\n/**\n * Wraps an async function (typically a write operation — create/update/delete) with\n * loading/success/error state tracking, retries, cancellation, and lifecycle callbacks.\n *\n * @example\n * ```ts\n * const createUser = createMutation(\n * (input: NewUser, signal) => api.post<User>('/users', { body: input, signal }),\n * { onSuccess: (user) => console.log('created', user.id) },\n * );\n *\n * const unsub = createUser.subscribe(() => console.log(createUser.peek()));\n * const user = await createUser.mutate({ name: 'Ada' });\n *\n * // later:\n * createUser.dispose();\n * ```\n */\nexport function createMutation<TData, TVariables = void>(\n mutationFn: MutationFn<TData, TVariables>,\n mutOpts?: MutationOptions<TData, TVariables>,\n): Mutation<TData, TVariables> {\n let snap: MutationState<TData> = IDLE_STATE as MutationState<TData>;\n let currentRun = 0;\n let activeRun: { controller: AbortController; promise: Promise<unknown> } | null = null;\n const observers = new Set<() => void>();\n let disposed = false;\n let cachedStore: SyncStore<MutationState<TData>> | null = null;\n\n function notifyObservers(): void {\n observers.forEach((l) => l());\n }\n\n async function safeCall(fn: (() => void | Promise<void>) | undefined): Promise<void> {\n try {\n await fn?.();\n } catch (err) {\n if (mutOpts?.onCallbackError) {\n try {\n mutOpts.onCallbackError(err instanceof Error ? err : new Error(String(err)));\n } catch {\n // Silently ignore errors in error handler itself.\n }\n }\n }\n }\n\n return {\n async cancel(): Promise<void> {\n const run = activeRun;\n\n if (!run) return;\n\n run.controller.abort();\n await run.promise.catch(() => {});\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n activeRun?.controller.abort();\n activeRun = null;\n observers.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n /**\n * Execute the mutation with the given variables.\n *\n * Concurrent calls are allowed. State updates (`isFetching`, `data`, `error`) always\n * reflect the **latest** `mutate()` call. Lifecycle callbacks (`onSuccess`, `onError`,\n * `onSettled`) fire for **every** call independently — not just the last one.\n * Cancel earlier calls via `mutation.cancel()` if you need only-last-wins callback semantics.\n *\n * @throws {CourierDisposedError} If called after `dispose()`.\n */\n async mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData> {\n if (disposed) throw new CourierDisposedError('Mutation');\n\n const localController = new AbortController();\n\n const signal = callOpts?.signal ? anySignal(callOpts.signal, localController.signal)! : localController.signal;\n const run = ++currentRun;\n\n snap = {\n data: undefined,\n error: null,\n isFetching: true,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n };\n notifyObservers();\n\n const pendingRun = { controller: localController, promise: null as unknown as Promise<TData> };\n\n activeRun = pendingRun;\n\n const operation = (async () => {\n try {\n const data = await retry(() => mutationFn(variables, signal), {\n delay: (attempt) => resolveRetryDelay(attempt, mutOpts?.delay),\n shouldRetry: mutOpts?.shouldRetry,\n signal,\n times: mutOpts?.times ?? 1,\n });\n\n if (run === currentRun) {\n snap = { data, error: null, isFetching: false, isLoading: false, status: 'success', updatedAt: Date.now() };\n notifyObservers();\n }\n\n await safeCall(() => mutOpts?.onSuccess?.(data, variables));\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() => mutOpts?.onSettled?.({ data, status: 'success', variables }));\n\n return data;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isAborted = signal.aborted || isAbortError(error);\n\n if (run === currentRun) {\n snap = isAborted\n ? (IDLE_STATE as MutationState<TData>)\n : { data: undefined, error, isFetching: false, isLoading: false, status: 'error', updatedAt: Date.now() };\n notifyObservers();\n }\n\n if (!isAborted) {\n await safeCall(() => mutOpts?.onError?.(error, variables));\n }\n\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() =>\n mutOpts?.onSettled?.(isAborted ? { status: 'aborted', variables } : { error, status: 'error', variables }),\n );\n\n throw error;\n } finally {\n if (activeRun?.controller === localController) {\n activeRun = null;\n }\n }\n })();\n\n pendingRun.promise = operation;\n\n return operation;\n },\n\n /**\n * Read the current mutation state snapshot.\n * For framework integrations prefer `peek()` + `subscribe()` directly.\n */\n peek(): MutationState<TData> {\n return snap;\n },\n\n reset(): void {\n snap = IDLE_STATE as MutationState<TData>;\n notifyObservers();\n },\n\n /**\n * A `SyncStore` view of the mutation state — identical to `{ peek, subscribe }` on this object.\n * Provided for framework integrations that accept a `SyncStore` directly:\n * - React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n * - Svelte: `readable(mutation.peek(), mutation.subscribe)`\n */\n get store(): SyncStore<MutationState<TData>> {\n return (cachedStore ??= {\n peek: () => snap,\n subscribe: (cb) => {\n observers.add(cb);\n\n return () => observers.delete(cb);\n },\n });\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n observers.add(onStoreChange);\n\n return () => observers.delete(onStoreChange);\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport interface Mutation<TData, TVariables = void> {\n [Symbol.dispose](): void;\n cancel(): Promise<void>;\n dispose(): void;\n get disposed(): boolean;\n mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData>;\n peek(): MutationState<TData>;\n reset(): void;\n /**\n * `SyncStore` adapter — equivalent to `{ peek, subscribe }` on this object.\n * For React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n */\n get store(): SyncStore<MutationState<TData>>;\n subscribe(onStoreChange: () => void): Unsubscribe;\n}\n","import { isAbortError, retry } from '@vielzeug/arsenal';\n\nimport type { RetryOptions } from './retry';\nimport type { QueryKey } from './types';\n\nimport { DEFAULT_TIMES, resolveRetryDelay } from './retry';\nimport { hash } from './serialize';\n\nexport const DEFAULT_GC = 5 * 60_000;\n\nexport type QueryFn<T> = (ctx: QueryFnContext) => Promise<T>;\n\nexport type QueryFnContext = {\n key: QueryKey;\n signal: AbortSignal;\n};\n\nexport type FetchConfig<T = unknown> = {\n delay: RetryOptions['delay'];\n fn: QueryFn<T>;\n gcTime: number;\n shouldRetry: RetryOptions['shouldRetry'];\n staleTime: number;\n times: number;\n};\n\nexport type EntryStatus = 'loading' | 'success' | 'error';\n\nexport type CacheEntry<T = unknown> = {\n data: T | undefined;\n error: Error | null;\n hash: string;\n inflight: { controller: AbortController; promise: Promise<T> } | null;\n isFetching: boolean;\n key: QueryKey;\n lastConfig: FetchConfig<T> | undefined;\n observers: Set<import('./query-observe').QueryObserver<unknown, unknown>>;\n segmentHashes: readonly string[];\n status: EntryStatus;\n updatedAt: number | undefined;\n};\n\nexport type EntrySnapshot<T> = {\n data: T | undefined;\n error: Error | null;\n status: EntryStatus;\n updatedAt: number | undefined;\n};\n\nexport type CacheContext = {\n delayDefault: RetryOptions['delay'];\n disposed: boolean;\n entries: Map<string, CacheEntry>;\n gcTimeDefault: number;\n gcTimers: Map<string, ReturnType<typeof setTimeout>>;\n notify: (entry: CacheEntry) => void;\n shouldRetryDefault: RetryOptions['shouldRetry'];\n staleTimeDefault: number;\n timesDefault: number;\n};\n\nexport function makeLoadingState(): {\n data: undefined;\n error: null;\n isFetching: true;\n isLoading: true;\n status: 'loading';\n updatedAt: undefined;\n} {\n return {\n data: undefined,\n error: null,\n isFetching: true,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n };\n}\n\nexport function resolveValue<T>(v: T | (() => T | undefined) | undefined): T | undefined {\n return typeof v === 'function' ? (v as () => T | undefined)() : v;\n}\n\nexport function hashKey(key: QueryKey): string {\n return hash(key);\n}\n\nexport function hashAtom(atom: QueryKey[number]): string {\n return hash(atom);\n}\n\nexport function ensureEntry<T>(ctx: CacheContext, key: QueryKey): CacheEntry<T> {\n const entryHash = hash(key);\n let entry = ctx.entries.get(entryHash) as CacheEntry<T> | undefined;\n\n if (!entry) {\n entry = {\n data: undefined,\n error: null,\n hash: entryHash,\n inflight: null,\n isFetching: false,\n key,\n lastConfig: undefined,\n observers: new Set(),\n segmentHashes: key.map((k) => hash(k)),\n status: 'loading',\n updatedAt: undefined,\n };\n ctx.entries.set(entryHash, entry as CacheEntry<unknown>);\n }\n\n return entry;\n}\n\nexport function cancelGc(ctx: CacheContext, entryHash: string): void {\n const timer = ctx.gcTimers.get(entryHash);\n\n if (!timer) return;\n\n clearTimeout(timer);\n ctx.gcTimers.delete(entryHash);\n}\n\nexport function scheduleGc<T>(ctx: CacheContext, entry: CacheEntry<T>, gcTime: number): void {\n if (ctx.disposed) return;\n\n cancelGc(ctx, entry.hash);\n\n if (entry.observers.size > 0) return;\n\n if (gcTime === 0) {\n ctx.entries.delete(entry.hash);\n\n return;\n }\n\n const timer = setTimeout(() => {\n const current = ctx.entries.get(entry.hash);\n\n if (!current || current.observers.size > 0 || current.isFetching) return;\n\n ctx.entries.delete(entry.hash);\n ctx.gcTimers.delete(entry.hash);\n }, gcTime);\n\n ctx.gcTimers.set(entry.hash, timer);\n}\n\nexport function deleteEntry<T>(ctx: CacheContext, entry: CacheEntry<T>): void {\n entry.inflight?.controller.abort();\n cancelGc(ctx, entry.hash);\n ctx.entries.delete(entry.hash);\n}\n\nexport function isKeyOrPrefix(entry: CacheEntry, prefixHash: readonly string[]): boolean {\n if (prefixHash.length > entry.segmentHashes.length) return false;\n\n return prefixHash.every((seg, i) => seg === entry.segmentHashes[i]);\n}\n\nexport function markFetching<T>(ctx: CacheContext, entry: CacheEntry<T>): void {\n entry.isFetching = true;\n entry.status = 'loading';\n entry.error = null;\n ctx.notify(entry);\n}\n\nexport function commitSuccess<T>(ctx: CacheContext, entry: CacheEntry<T>, data: T, gcTime: number): void {\n entry.data = data;\n entry.error = null;\n entry.status = 'success';\n entry.updatedAt = Date.now();\n entry.isFetching = false;\n entry.inflight = null;\n scheduleGc(ctx, entry, gcTime);\n ctx.notify(entry);\n}\n\nexport function commitError<T>(ctx: CacheContext, entry: CacheEntry<T>, error: Error, gcTime: number): void {\n entry.error = error;\n entry.status = 'error';\n entry.updatedAt = Date.now();\n entry.isFetching = false;\n entry.inflight = null;\n scheduleGc(ctx, entry, gcTime);\n ctx.notify(entry);\n}\n\nexport function rollback<T>(ctx: CacheContext, entry: CacheEntry<T>, previous: EntrySnapshot<T>, gcTime: number): void {\n entry.data = previous.data;\n entry.error = previous.error;\n entry.status = previous.status;\n entry.updatedAt = previous.updatedAt;\n entry.isFetching = false;\n entry.inflight = null;\n\n if (entry.observers.size === 0 && entry.status === 'loading' && entry.data === undefined) {\n deleteEntry(ctx, entry);\n\n return;\n }\n\n scheduleGc(ctx, entry, gcTime);\n ctx.notify(entry);\n}\n\nexport function evictEntry<T>(ctx: CacheContext, entry: CacheEntry<T>): void {\n entry.inflight?.controller.abort();\n\n if (entry.observers.size > 0) {\n entry.inflight = null;\n entry.isFetching = false;\n entry.status = 'loading';\n entry.data = undefined;\n entry.error = null;\n entry.updatedAt = undefined;\n ctx.notify(entry);\n\n return;\n }\n\n deleteEntry(ctx, entry);\n}\n\nexport function startFetch<T>(ctx: CacheContext, entry: CacheEntry<T>, config: FetchConfig<T>): Promise<T> {\n if (entry.inflight) return entry.inflight.promise;\n\n const { delay, fn, gcTime, shouldRetry, times } = config;\n const controller = new AbortController();\n const prev: EntrySnapshot<T> = {\n data: entry.data,\n error: entry.error,\n status: entry.status,\n updatedAt: entry.updatedAt,\n };\n\n const promise = (async () => {\n try {\n const data = await retry(() => fn({ key: entry.key, signal: controller.signal }), {\n delay: (attempt) => resolveRetryDelay(attempt, delay),\n shouldRetry,\n signal: controller.signal,\n times,\n });\n\n commitSuccess(ctx, entry, data, gcTime);\n\n return data;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isAborted = controller.signal.aborted || isAbortError(error);\n\n if (isAborted) {\n rollback(ctx, entry, prev, gcTime);\n } else {\n commitError(ctx, entry, error, gcTime);\n }\n\n throw error;\n }\n })();\n\n entry.inflight = { controller, promise };\n markFetching(ctx, entry);\n\n return promise;\n}\n\nexport function makeFetchConfig<T>(\n ctx: CacheContext,\n options: {\n delay?: RetryOptions['delay'];\n fn: QueryFn<T>;\n gcTime?: number;\n shouldRetry?: RetryOptions['shouldRetry'];\n staleTime?: number;\n times?: number;\n },\n): FetchConfig<T> {\n return {\n delay: options.delay ?? ctx.delayDefault,\n fn: options.fn,\n gcTime: options.gcTime ?? ctx.gcTimeDefault,\n shouldRetry: options.shouldRetry ?? ctx.shouldRetryDefault,\n staleTime: options.staleTime ?? ctx.staleTimeDefault,\n times: options.times ?? ctx.timesDefault,\n };\n}\n\nexport function buildCacheContext(\n opts: {\n delay?: RetryOptions['delay'];\n gcTime?: number;\n shouldRetry?: RetryOptions['shouldRetry'];\n staleTime?: number;\n times?: number;\n },\n entries: Map<string, CacheEntry>,\n gcTimers: Map<string, ReturnType<typeof setTimeout>>,\n notify: (entry: CacheEntry) => void,\n): CacheContext {\n return {\n delayDefault: opts.delay,\n disposed: false,\n entries,\n gcTimeDefault: opts.gcTime ?? DEFAULT_GC,\n gcTimers,\n notify,\n shouldRetryDefault: opts.shouldRetry,\n staleTimeDefault: opts.staleTime ?? 0,\n timesDefault: opts.times ?? DEFAULT_TIMES,\n };\n}\n","import type { CacheContext, CacheEntry } from './query-cache';\nimport type { AsyncState, QueryState, SyncStore, Unsubscribe } from './types';\n\nimport { cancelGc, ensureEntry, hashKey, resolveValue, scheduleGc } from './query-cache';\n\nexport type QueryObserver<T, S> = {\n listener: () => void;\n placeholderData?: S | (() => S | undefined);\n previous?: QueryState<S>;\n select?: (data: T | undefined) => S | undefined;\n};\n\nconst LOADING_STATE: AsyncState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\nexport function toBaseState<T>(entry: CacheEntry<T>): QueryState<T> {\n if (entry.status === 'loading') {\n return {\n data: undefined,\n error: null,\n isFetching: entry.isFetching,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n } as QueryState<T>;\n }\n\n if (entry.status === 'success') {\n return {\n data: entry.data as T,\n error: null,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'success',\n updatedAt: entry.updatedAt as number,\n };\n }\n\n return {\n data: entry.data,\n error: entry.error as Error,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'error',\n updatedAt: entry.updatedAt as number,\n };\n}\n\nexport function toObserverState<T, S>(entry: CacheEntry<T>, observer: QueryObserver<T, S>): QueryState<S> {\n const base = toBaseState(entry);\n\n if (base.status === 'loading') {\n const placeholder = resolveValue(observer.placeholderData as S | (() => S | undefined) | undefined);\n\n return { ...base, data: placeholder } as QueryState<S>;\n }\n\n const selected = observer.select ? observer.select(base.data as T | undefined) : (base.data as S | undefined);\n\n return { ...base, data: selected } as QueryState<S>;\n}\n\nexport function notify<T>(entry: CacheEntry<T>): void {\n for (const observer of entry.observers) {\n const typed = observer as QueryObserver<T, unknown>;\n const next = toObserverState(entry, typed);\n const prev = typed.previous;\n\n const dataUnchanged = Object.is(prev?.data, next.data);\n const metaUnchanged =\n !!prev && prev.status === next.status && prev.isFetching === next.isFetching && Object.is(prev.error, next.error);\n\n const shouldSkip = typed.select\n ? metaUnchanged && dataUnchanged\n : metaUnchanged && prev?.updatedAt === next.updatedAt && dataUnchanged;\n\n if (shouldSkip) continue;\n\n typed.previous = next;\n typed.listener();\n }\n}\n\nexport function watchInternal<T = unknown, S = T>(\n ctx: CacheContext,\n key: Parameters<typeof ensureEntry>[1],\n opts?: { placeholderData?: S | (() => S | undefined); select?: (data: T | undefined) => S | undefined },\n): SyncStore<QueryState<S>> {\n const peekObserver: QueryObserver<T, S> = { listener: () => {}, ...opts };\n\n return {\n peek(): QueryState<S> {\n const entry = ctx.entries.get(hashKey(key)) as CacheEntry<T> | undefined;\n\n if (!entry) return LOADING_STATE as QueryState<S>;\n\n return toObserverState(entry, peekObserver);\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n const entry = ensureEntry<T>(ctx, key);\n\n cancelGc(ctx, entry.hash);\n\n const observer: QueryObserver<T, S> = {\n ...opts,\n listener: onStoreChange,\n previous: toObserverState(entry, peekObserver),\n };\n\n entry.observers.add(observer as QueryObserver<unknown, unknown>);\n\n return () => {\n entry.observers.delete(observer as QueryObserver<unknown, unknown>);\n\n if (entry.observers.size === 0) {\n scheduleGc(ctx, entry, entry.lastConfig?.gcTime ?? ctx.gcTimeDefault);\n }\n };\n },\n };\n}\n","import type { RetryOptions } from './retry';\nimport type { QueryKey, QueryState, SyncStore, Unsubscribe } from './types';\n\nimport { CourierDisposedError } from './errors';\nimport {\n buildCacheContext,\n ensureEntry,\n evictEntry,\n hashAtom,\n hashKey,\n isKeyOrPrefix,\n makeFetchConfig,\n resolveValue,\n scheduleGc,\n startFetch,\n type CacheContext,\n type CacheEntry,\n type FetchConfig,\n type QueryFn,\n type QueryFnContext,\n} from './query-cache';\nimport { notify, toBaseState, watchInternal } from './query-observe';\n\nexport type { QueryFn, QueryFnContext };\n\n/**\n * Options for `qc.fetch()`. Always throws on error and returns `T`.\n * Use `observe()` for reactive subscriptions with select/placeholder support.\n */\nexport type QueryOptions<T> = {\n /**\n * When `false` the fetch is skipped and the current cached value is returned.\n * If no cached data exists yet, the return value is `undefined` — use `getState()`\n * to inspect entry status in that case.\n * Defaults to `true`.\n */\n enabled?: boolean;\n fn: QueryFn<T>;\n gcTime?: number;\n /** Pre-seed the cache as a successful entry when no data exists. Subject to normal staleTime checks. */\n initialData?: T | (() => T | undefined);\n key: QueryKey;\n staleTime?: number;\n} & RetryOptions;\n\n/**\n * Shared reactive fields for `observe()`.\n */\ntype ObserveExtras<T, S> = {\n /**\n * Temporary value shown while a fetch is in-flight and no cached data exists.\n * Does not affect cache state — only the value returned by `store.peek()`.\n */\n placeholderData?: S | (() => S | undefined);\n /** Transform the cached data before it is delivered to store subscribers. */\n select?: (data: T | undefined) => S | undefined;\n};\n\n/**\n * Options for `qc.observe()`. Two forms:\n *\n * - `fetch?: true` (default) — triggers a background fetch; `fn` is required.\n * - `fetch: false` — read-only store; `fn` is not required or called.\n *\n * Errors surface via `store.peek().status === 'error'`, not via Promise rejection.\n */\nexport type ObserveOptions<T, S = T> =\n | ({ fetch?: true } & QueryOptions<T> & ObserveExtras<T, S>)\n | ({ fetch: false; key: QueryKey } & Partial<QueryOptions<T>> & ObserveExtras<T, S>);\n\nexport type QueryClientOptions = {\n /**\n * Optional fetch implementation injected by `createCourier` so that\n * query fetches flow through the shared interceptor pipeline (auth, logging, etc.).\n * When omitted `globalThis.fetch` is used directly.\n */\n fetch?: typeof globalThis.fetch;\n gcTime?: number;\n staleTime?: number;\n} & RetryOptions;\n\n/**\n * Creates a key-based query cache with request deduplication, retries, stale-time/gc-time\n * eviction, and `observe()`-based reactive subscriptions (`SyncStore`-compatible).\n *\n * @example\n * ```ts\n * const qc = createQuery({ staleTime: 30_000 });\n *\n * // One-shot fetch, always resolves or throws\n * const user = await qc.fetch({ key: ['users', 1], fn: ({ signal }) => fetchUser(1, signal) });\n *\n * // Reactive subscription — errors surface via store.peek().status, not rejection\n * const store = qc.observe({ key: ['users', 1], fn: ({ signal }) => fetchUser(1, signal) });\n * const unsub = store.subscribe(() => console.log(store.peek()));\n *\n * // later:\n * qc.dispose();\n * ```\n */\nexport function createQuery(opts?: QueryClientOptions) {\n let disposed = false;\n const disposeController = new AbortController();\n const entries = new Map<string, CacheEntry>();\n const gcTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n const ctx: CacheContext = buildCacheContext(\n {\n delay: opts?.delay,\n gcTime: opts?.gcTime,\n shouldRetry: opts?.shouldRetry,\n staleTime: opts?.staleTime,\n times: opts?.times,\n },\n entries,\n gcTimers,\n notify,\n );\n\n async function fetchQuery<T>(options: QueryOptions<T>): Promise<T> {\n if (disposed) throw new CourierDisposedError('QueryClient');\n\n const { enabled = true, fn, gcTime, initialData, key, staleTime, ...retryOpts } = options;\n\n // When disabled and no existing entry, return undefined without creating a cache entry.\n if (!enabled) {\n const h = hashKey(key);\n const existing = entries.get(h);\n\n return (existing?.data as T | undefined) ?? (undefined as unknown as T);\n }\n\n const entry = ensureEntry<T>(ctx, key);\n const config = makeFetchConfig<T>(ctx, { fn, gcTime, staleTime, ...retryOpts });\n\n if (initialData !== undefined && entry.status === 'loading' && entry.data === undefined) {\n const initVal = resolveValue(initialData);\n\n if (initVal !== undefined) {\n entry.data = initVal;\n entry.error = null;\n entry.status = 'success';\n entry.updatedAt = Date.now();\n }\n }\n\n if (\n entry.status === 'success' &&\n entry.updatedAt !== undefined &&\n Date.now() - entry.updatedAt < config.staleTime &&\n !entry.isFetching\n ) {\n entry.lastConfig = config;\n\n return entry.data as T;\n }\n\n entry.lastConfig = config;\n\n if (entry.inflight) return entry.inflight.promise;\n\n return startFetch(ctx, entry, config);\n }\n\n function revalidateObservedEntry<T>(entry: CacheEntry<T>): void {\n if (!entry.lastConfig) {\n evictEntry(ctx, entry);\n\n return;\n }\n\n if (entry.isFetching) return;\n\n startFetch(ctx, entry, entry.lastConfig as FetchConfig<T>).catch(() => {});\n }\n\n function invalidate(key: QueryKey): void {\n const prefixHash = key.map((k) => hashAtom(k));\n\n for (const entry of [...entries.values()]) {\n if (isKeyOrPrefix(entry, prefixHash)) {\n if (entry.observers.size > 0) {\n revalidateObservedEntry(entry);\n continue;\n }\n\n evictEntry(ctx, entry);\n }\n }\n }\n\n function set<T>(key: QueryKey, data: T, opts?: { gcTime?: number; updatedAt?: number }): void;\n function set<T>(\n key: QueryKey,\n updater: (old: T | undefined) => T,\n opts?: { gcTime?: number; updatedAt?: number },\n ): void;\n function set<T>(\n key: QueryKey,\n dataOrUpdater: T | ((old: T | undefined) => T),\n opts?: { gcTime?: number; updatedAt?: number },\n ): void {\n const entry = ensureEntry<T>(ctx, key);\n const gcTime = opts?.gcTime ?? entry.lastConfig?.gcTime ?? ctx.gcTimeDefault;\n\n entry.data =\n typeof dataOrUpdater === 'function' ? (dataOrUpdater as (old: T | undefined) => T)(entry.data) : dataOrUpdater;\n entry.error = null;\n entry.status = 'success';\n entry.updatedAt = opts?.updatedAt ?? Date.now();\n entry.isFetching = false;\n entry.inflight = null;\n notify(entry);\n scheduleGc(ctx, entry, gcTime);\n }\n\n function isStaleAndRevalidatable(entry: CacheEntry): boolean {\n if (entry.observers.size === 0 || !entry.lastConfig || entry.isFetching) return false;\n\n if (entry.status === 'success' && entry.updatedAt !== undefined) {\n return Date.now() - entry.updatedAt >= entry.lastConfig.staleTime;\n }\n\n if (entry.status === 'error' && entry.data !== undefined && entry.updatedAt !== undefined) {\n return Date.now() - entry.updatedAt >= entry.lastConfig.staleTime;\n }\n\n return false;\n }\n\n /**\n * Returns a `SyncStore` for `key` and optionally triggers a background fetch.\n *\n * **With fetch (default):** pass `fn` and the store triggers a background fetch on creation.\n * Errors surface via `store.peek().status === 'error'`, not via Promise rejection.\n *\n * **Without fetch:** pass `fetch: false` — `fn` is not required. The store reflects\n * whatever is in the cache. Useful when another path is responsible for populating the entry.\n *\n * @example\n * ```ts\n * // Fetch form\n * const store = qc.observe({ key: ['users', 1], fn: ({ signal }) => fetchUser(1, signal) });\n *\n * // Read-only form — no fn required\n * const store = qc.observe({ key: ['users', 1], fetch: false });\n * ```\n */\n function observe<T = unknown, S = T>(options: ObserveOptions<T, S>): SyncStore<QueryState<S>> {\n const {\n fetch: shouldFetch = true,\n key,\n placeholderData,\n select,\n } = options as {\n fetch?: boolean;\n key: QueryKey;\n placeholderData?: S | (() => S | undefined);\n select?: (data: T | undefined) => S | undefined;\n };\n\n const store = watchInternal<T, S>(ctx, key, { placeholderData, select });\n\n if (shouldFetch && (options as { fn?: QueryFn<T> }).fn) {\n fetchQuery({ ...(options as QueryOptions<T>) }).catch(() => {});\n }\n\n return store;\n }\n\n return {\n cancel(key: QueryKey): void {\n const entry = entries.get(hashKey(key));\n\n if (!entry?.inflight) return;\n\n entry.inflight.controller.abort();\n },\n\n cancelAll(): void {\n for (const entry of entries.values()) {\n entry.inflight?.controller.abort();\n }\n },\n\n clear(): void {\n for (const entry of [...entries.values()]) {\n evictEntry(ctx, entry);\n }\n },\n\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n ctx.disposed = true;\n disposeController.abort();\n\n for (const [, entry] of entries) {\n entry.observers.clear();\n entry.inflight?.controller.abort();\n }\n\n for (const [, timer] of gcTimers) {\n clearTimeout(timer);\n }\n\n gcTimers.clear();\n entries.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n fetch: fetchQuery,\n\n fetchMany<T = unknown>(queries: QueryOptions<T>[]): Promise<T[]> {\n return Promise.all(queries.map((q) => fetchQuery(q)));\n },\n\n get<T>(key: QueryKey): T | undefined {\n const entry = entries.get(hashKey(key));\n\n return entry ? (entry.data as T | undefined) : undefined;\n },\n\n getState<T>(key: QueryKey): QueryState<T> | null {\n const entry = entries.get(hashKey(key)) as CacheEntry<T> | undefined;\n\n if (!entry) return null;\n\n return toBaseState(entry);\n },\n\n invalidate,\n\n keys(): QueryKey[] {\n return [...entries.values()].map((e) => e.key);\n },\n\n observe,\n\n observeMany<T = unknown>(keys: QueryKey[]): SyncStore<QueryState<T>[]> {\n const stores = keys.map((k) => watchInternal<T>(ctx, k));\n\n return {\n peek(): QueryState<T>[] {\n return stores.map((s) => s.peek());\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n const unsubs = stores.map((s) => s.subscribe(onStoreChange));\n\n return () => {\n for (const u of unsubs) u();\n };\n },\n };\n },\n\n refetchStale(): void {\n for (const entry of [...entries.values()]) {\n if (isStaleAndRevalidatable(entry)) {\n startFetch(ctx, entry, entry.lastConfig as FetchConfig<unknown>).catch(() => {});\n }\n }\n },\n\n remove(key: QueryKey): void {\n const entry = entries.get(hashKey(key));\n\n if (entry) evictEntry(ctx, entry);\n },\n\n set,\n\n get size(): number {\n return entries.size;\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport type QueryClient = ReturnType<typeof createQuery>;\n","import { sleep } from '@vielzeug/arsenal';\n\nimport type { Params } from './url';\n\nimport { classifyRequestError, CourierDisposedError, CourierHttpError, CourierParseError } from './errors';\nimport { fullJitterDelay } from './retry';\nimport { buildRequestInit } from './serialize';\nimport {\n anySignal,\n buildTimeoutSignal,\n createTransportCore,\n type TransportCore,\n type TransportOptions,\n validateTimeout,\n} from './transport';\nimport { buildUrl } from './url';\n\nexport type StreamRequestConfig<P extends string = string> = {\n body?: unknown;\n /** Raw fetch options for advanced use (credentials, cache, mode, referrer, etc.). */\n fetchInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>;\n headers?: Record<string, string>;\n method?: string;\n params?: P extends string ? Record<string, string | number | boolean> : never;\n query?: Params;\n /** External abort signal. Merged with internal cancellation. */\n signal?: AbortSignal;\n /** Request timeout in ms. Overrides client default (which is `Infinity` for streaming). */\n timeout?: number;\n};\n\nexport type ReconnectOptions = {\n /**\n * Delay between reconnect attempts in ms, or a zero-based function where\n * `attempt` is the number of failures so far (0 = waiting before the 2nd try).\n * Defaults to full-jitter exponential backoff: `[0, min(1s × 2ⁿ, 30s)]`.\n */\n delay?: number | ((attempt: number) => number);\n /** Total reconnect attempts after the first failure. Defaults to `5`. */\n times?: number;\n};\n\nexport type ReadableConfig<P extends string = string> = StreamRequestConfig<P> & {\n /**\n * Called when the reconnect budget is exhausted or a non-retriable error\n * occurs. Not called when the generator is aborted via signal or dispose.\n */\n onError?: (error: Error) => void;\n /**\n * Response body parsing mode.\n * - `'text'` (default) — yields raw decoded string chunks as they arrive.\n * - `'ndjson'` — splits by newline and JSON-parses each complete line; use `T` to type the values.\n */\n parse?: 'ndjson' | 'text';\n /**\n * Auto-reconnect on connection loss. Uses the same backoff semantics as\n * `sse()` reconnect. `true` uses defaults (5 attempts). Defaults to `false`.\n */\n reconnect?: boolean | ReconnectOptions;\n};\n\nexport type SseOptions<P extends string = string> = StreamRequestConfig<P> & {\n /**\n * Called when the connection is permanently lost (reconnect budget exhausted due to error).\n * Not called on `dispose()`.\n */\n onError?: (error: Error) => void;\n /**\n * Auto-reconnect on connection loss with exponential backoff.\n * `true` uses defaults (5 attempts). Defaults to `false`.\n */\n reconnect?: boolean | ReconnectOptions;\n};\n\n/** Connection lifecycle status for an SSE source. */\nexport type SseStatus = 'connecting' | 'open' | 'reconnecting' | 'closed';\n\n/**\n * Typed SSE event source. `TEvents` maps event name → data type.\n * Non-string data values are automatically JSON-parsed from the raw `data:` field.\n * If parsing fails the raw string is delivered instead.\n */\nexport type SseSource<TEvents extends Record<string, unknown> = Record<string, string>> = {\n [Symbol.dispose](): void;\n /** `true` after `dispose()` is called or the reconnect budget is exhausted. */\n readonly closed: boolean;\n /** Permanently closes the SSE connection. No further events will be dispatched. */\n dispose(): void;\n /**\n * Registers a handler for a named SSE event. Returns an unsubscribe function.\n * The special name `'message'` matches events without an explicit `event:` field.\n * Calling `on()` after `dispose()` returns a no-op unsubscribe.\n */\n on<K extends keyof TEvents & string>(event: K, handler: (data: TEvents[K]) => void): () => void;\n /** Current connection lifecycle status. Useful for displaying a live-connection indicator. */\n readonly status: SseStatus;\n};\n\n/** Parse a raw SSE data string: try JSON, fall back to raw string. */\nfunction parseEventData(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/**\n * Shared stream setup: build URL, combine signals, merge headers, dispatch through\n * transport. Returns the Response so both sse() and readable() can focus on parsing.\n * The caller owns the AbortController lifecycle (track + untrack).\n */\nasync function openStreamWith(\n transport: TransportCore,\n url: string,\n ac: AbortController,\n config: {\n body?: unknown;\n extSignal?: AbortSignal;\n fetchInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>;\n headers?: Record<string, string>;\n method: string;\n params?: Params;\n query?: Params;\n timeout?: number;\n },\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n // Normalize once — error paths and RequestInit both receive the canonical form.\n const method = config.method.toUpperCase();\n const full = buildUrl(transport.baseUrl, url, config.params, config.query);\n const combined = anySignal(config.extSignal, ac.signal) ?? ac.signal;\n // Streaming connections are long-lived — default to Infinity so the transport's\n // REST default (30s) does not cut off streams prematurely.\n const signal = buildTimeoutSignal(config.timeout ?? Number.POSITIVE_INFINITY, combined);\n const requestHeaders = transport.mergeHeaders(config.headers, extraHeaders);\n const { headers: initHeaders, ...restInit } = buildRequestInit(\n method,\n requestHeaders,\n config.body,\n signal,\n config.fetchInit ?? {},\n );\n\n let res: Response;\n\n try {\n res = await transport.dispatch({ headers: initHeaders as Record<string, string>, init: restInit, url: full });\n } catch (err) {\n throw classifyRequestError(err, method, full, signal ?? combined);\n }\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n\n throw CourierHttpError.fromResponse(res, text, method, full);\n }\n\n if (!res.body) throw new CourierParseError('Response has no body');\n\n return res;\n}\n\n/**\n * Creates a streaming client exposing `sse()` (Server-Sent Events) and `readable()`\n * (`ReadableStream`/NDJSON). Both share the same interceptor pipeline, header management,\n * and `AbortController` lifecycle as `createApi`.\n *\n * @example\n * ```ts\n * const stream = createStream({ baseUrl: 'https://api.example.com' });\n *\n * const src = stream.sse<{ message: { text: string } }>('/events', { reconnect: true });\n * src.on('message', (data) => console.log(data.text));\n *\n * for await (const chunk of stream.readable('/completions', { body: { prompt } })) {\n * process.stdout.write(chunk);\n * }\n *\n * // later:\n * stream.dispose();\n * ```\n */\nexport function createStream(opts?: TransportOptions & { transport?: TransportCore }) {\n const { transport: sharedTransport, ...transportOpts } = opts ?? {};\n const ownTransport = !sharedTransport;\n const transport = sharedTransport ?? createTransportCore(transportOpts);\n\n /**\n * Opens a Server-Sent Events connection and returns a typed source.\n *\n * - Intercepts request through the same pipeline as `createApi` (auth, logging, etc.)\n * - Auto-reconnects with exponential backoff when `reconnect` is set\n * - Sends `Last-Event-ID` header on reconnect to resume from last received event\n * - Non-string event data is automatically JSON-parsed\n *\n * @example\n * ```ts\n * const src = stream.sse<{ message: { text: string }; ping: null }>('/events', {\n * reconnect: true,\n * onError: (err) => console.error(err),\n * });\n *\n * src.on('message', (data) => console.log(data.text));\n * src.on('ping', () => {});\n * // later:\n * src.dispose();\n * ```\n */\n function sse<TEvents extends Record<string, unknown> = Record<string, string>, P extends string = string>(\n url: P,\n config: SseOptions<P> = {} as SseOptions<P>,\n ): SseSource<TEvents> {\n if (transport.disposed) throw new CourierDisposedError('StreamClient');\n\n const {\n body,\n fetchInit,\n headers: perRequestHeaders,\n method = body !== undefined ? 'POST' : 'GET',\n onError,\n params,\n query,\n reconnect = false,\n signal: extSignal,\n timeout: cfgTimeout,\n } = config as SseOptions;\n\n if (cfgTimeout !== undefined) validateTimeout(cfgTimeout);\n\n const listeners = new Map<string, Set<(data: unknown) => void>>();\n const ac = new AbortController();\n // Track `ac` once for the entire SSE lifetime — covers active connections AND\n // reconnect sleep windows, so cancelAll()/dispose() always reach it.\n const untrack = transport.track(ac);\n let closed = false;\n let sseStatus: SseStatus = 'connecting';\n let lastEventId = '';\n\n const reconnectOpts: ReconnectOptions = reconnect === true ? {} : reconnect === false ? { times: 0 } : reconnect;\n const maxReconnects = reconnectOpts.times ?? (reconnect ? 5 : 0);\n // `activeReconnectDelay` is mutable so the server's `retry:` field can update\n // the reconnection interval without the caller needing to handle it manually.\n let activeReconnectDelay: number | ((attempt: number) => number) = reconnectOpts.delay ?? fullJitterDelay;\n\n function dispatchEvent(event: string, rawData: string): void {\n const handlers = listeners.get(event);\n\n if (!handlers?.size) return;\n\n const data = parseEventData(rawData);\n\n for (const handler of handlers) handler(data);\n }\n\n async function connect(): Promise<void> {\n const res = await openStreamWith(\n transport,\n url,\n ac,\n {\n body,\n extSignal,\n fetchInit,\n headers: perRequestHeaders as Record<string, string> | undefined,\n method,\n params: params as Params | undefined,\n query,\n timeout: cfgTimeout,\n },\n {\n accept: 'text/event-stream',\n 'cache-control': 'no-cache',\n ...(lastEventId ? { 'last-event-id': lastEventId } : {}),\n },\n );\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEvent = 'message';\n let currentData = '';\n let currentId = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n // Normalise \\r\\n and \\r to \\n before processing\n buffer += decoder.decode(value, { stream: true }).replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n\n let nlIdx: number;\n\n while ((nlIdx = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, nlIdx);\n\n buffer = buffer.slice(nlIdx + 1);\n\n if (line === '') {\n // Empty line → dispatch event\n if (currentData !== '') {\n if (currentId) lastEventId = currentId;\n\n dispatchEvent(currentEvent, currentData.replace(/\\n$/, ''));\n }\n\n currentEvent = 'message';\n currentData = '';\n currentId = '';\n } else if (line.startsWith(':')) {\n // Comment — ignore\n } else {\n const colonIdx = line.indexOf(':');\n const field = colonIdx === -1 ? line : line.slice(0, colonIdx);\n const value = colonIdx === -1 ? '' : line.slice(colonIdx + 1).replace(/^ /, '');\n\n if (field === 'event') currentEvent = value;\n else if (field === 'data') currentData += (currentData ? '\\n' : '') + value;\n else if (field === 'id' && !value.includes('\\0')) currentId = value;\n else if (field === 'retry') {\n // Honor the server's advised reconnect interval (SSE spec §9.2.6).\n const ms = parseInt(value, 10);\n\n if (!Number.isNaN(ms)) activeReconnectDelay = ms;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n async function run(): Promise<void> {\n let attempt = 0;\n\n try {\n while (!closed && !transport.disposed && !ac.signal.aborted) {\n let connectError: Error | undefined;\n\n sseStatus = 'connecting';\n\n try {\n sseStatus = 'open';\n await connect();\n // Clean server-side close — falls through to reconnect logic below.\n // The attempt counter is intentionally NOT reset here: `times`\n // bounds total reconnects regardless of whether the close was clean or an\n // error, preventing infinite reconnection against servers that always close\n // after a response window (e.g. SSE keepalive patterns).\n } catch (err) {\n if (closed || transport.disposed || ac.signal.aborted) break;\n\n connectError = err instanceof Error ? err : new Error(String(err));\n }\n\n if (closed || transport.disposed || ac.signal.aborted) break;\n\n // No reconnect budget → fire onError for errors, stop either way\n if (maxReconnects === 0) {\n if (connectError) onError?.(connectError);\n\n break;\n }\n\n // Budget exhausted → always signal via onError so the caller knows\n // the reconnect cycle has ended (whether the close was clean or not).\n if (attempt >= maxReconnects) {\n onError?.(connectError ?? new Error('[courier] SSE reconnect budget exhausted'));\n\n break;\n }\n\n // Budget available → sleep and retry\n sseStatus = 'reconnecting';\n\n const delay =\n typeof activeReconnectDelay === 'function' ? activeReconnectDelay(attempt) : activeReconnectDelay;\n\n attempt++;\n await sleep(delay, ac.signal).catch(() => {});\n }\n } finally {\n sseStatus = 'closed';\n untrack();\n }\n }\n\n // Surface unexpected programming errors (not network failures) via onError\n run().catch((err) => {\n if (!closed && !transport.disposed) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n return {\n get closed(): boolean {\n return closed;\n },\n\n dispose(): void {\n closed = true;\n ac.abort();\n listeners.clear();\n },\n\n on<K extends keyof TEvents & string>(event: K, handler: (data: TEvents[K]) => void): () => void {\n // After dispose(), return a no-op to avoid silent dead-listener bugs\n if (closed) return () => {};\n\n let set = listeners.get(event);\n\n if (!set) {\n set = new Set<(data: unknown) => void>();\n listeners.set(event, set);\n }\n\n set.add(handler as (data: unknown) => void);\n\n return () => set.delete(handler as (data: unknown) => void);\n },\n\n get status(): SseStatus {\n return sseStatus;\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n }\n\n /**\n * Opens an HTTP streaming connection and returns an async generator yielding\n * response body chunks as they arrive.\n *\n * - `parse: 'text'` (default) — yields raw decoded string chunks\n * - `parse: 'ndjson'` — splits by newline and JSON-parses each line; use `T` to\n * type the parsed values\n *\n * @example\n * ```ts\n * // Raw text stream\n * for await (const chunk of stream.readable('/completions', { body: { prompt } })) {\n * process.stdout.write(chunk);\n * }\n *\n * // NDJSON (e.g. AI token stream, log stream)\n * for await (const msg of stream.readable<ChatMessage>('/chat', {\n * body: { prompt },\n * parse: 'ndjson',\n * })) {\n * console.log(msg.content);\n * }\n * ```\n */\n async function* readable<T = string, P extends string = string>(\n url: P,\n config: ReadableConfig<P> = {} as ReadableConfig<P>,\n ): AsyncGenerator<T> {\n if (transport.disposed) throw new CourierDisposedError('StreamClient');\n\n const {\n body,\n fetchInit,\n headers: perRequestHeaders,\n method = body !== undefined ? 'POST' : 'GET',\n onError,\n params,\n parse = 'text',\n query,\n reconnect = false,\n signal: extSignal,\n timeout: cfgTimeout,\n } = config as ReadableConfig;\n\n if (cfgTimeout !== undefined) validateTimeout(cfgTimeout);\n\n const reconnectOpts: ReconnectOptions = reconnect === true ? {} : reconnect === false ? { times: 0 } : reconnect;\n const maxReconnects = reconnectOpts.times ?? (reconnect ? 5 : 0);\n const reconnectDelay: number | ((attempt: number) => number) = reconnectOpts.delay ?? fullJitterDelay;\n\n const ac = new AbortController();\n const untrack = transport.track(ac);\n let attempt = 0;\n let overallNaturalEnd = false;\n\n try {\n while (!transport.disposed && !ac.signal.aborted) {\n let connectError: Error | undefined;\n let connectionNaturalEnd = false;\n\n try {\n const res = await openStreamWith(transport, url, ac, {\n body,\n extSignal,\n fetchInit,\n headers: perRequestHeaders as Record<string, string> | undefined,\n method,\n params: params as Params | undefined,\n query,\n timeout: cfgTimeout,\n });\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n\n try {\n if (parse === 'ndjson') {\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n const remaining = buffer.trim();\n\n if (remaining) {\n try {\n yield JSON.parse(remaining) as T;\n } catch {\n throw new CourierParseError(`NDJSON: failed to parse line: ${remaining.slice(0, 200)}`);\n }\n }\n\n connectionNaturalEnd = true;\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n let nlIdx: number;\n\n while ((nlIdx = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, nlIdx).trim();\n\n buffer = buffer.slice(nlIdx + 1);\n\n if (line) {\n try {\n yield JSON.parse(line) as T;\n } catch {\n throw new CourierParseError(`NDJSON: failed to parse line: ${line.slice(0, 200)}`);\n }\n }\n }\n }\n } else {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n connectionNaturalEnd = true;\n break;\n }\n\n yield decoder.decode(value, { stream: true }) as unknown as T;\n }\n }\n } finally {\n reader.releaseLock();\n }\n } catch (err) {\n if (transport.disposed || ac.signal.aborted) break;\n\n connectError = err instanceof Error ? err : new Error(String(err));\n }\n\n if (transport.disposed || ac.signal.aborted) break;\n\n // No reconnect budget — throw or call onError on errors, stop either way\n if (maxReconnects === 0) {\n if (connectError) {\n if (onError) {\n onError(connectError);\n } else {\n throw connectError;\n }\n } else {\n overallNaturalEnd = connectionNaturalEnd;\n }\n\n break;\n }\n\n // Budget exhausted\n if (attempt >= maxReconnects) {\n const budgetError = connectError ?? new Error('[courier] readable() reconnect budget exhausted');\n\n if (onError) {\n onError(budgetError);\n } else if (connectError) {\n throw connectError;\n }\n\n break;\n }\n\n // Clean server close with no reconnect error — done\n if (connectionNaturalEnd && !connectError) {\n overallNaturalEnd = true;\n break;\n }\n\n // Sleep before reconnecting\n const delay = typeof reconnectDelay === 'function' ? reconnectDelay(attempt) : reconnectDelay;\n\n attempt++;\n await sleep(delay, ac.signal).catch(() => {});\n }\n } finally {\n if (!overallNaturalEnd) ac.abort();\n\n untrack();\n }\n }\n\n return {\n cancelAll(): void {\n transport.cancelAll();\n },\n get disposalSignal() {\n return transport.disposalSignal;\n },\n dispose(): void {\n if (ownTransport) transport.dispose();\n },\n get disposed() {\n return transport.disposed;\n },\n getHeaders: transport.getHeaders,\n headers: transport.headers,\n readable,\n sse,\n [Symbol.dispose](): void {\n this.dispose();\n },\n use: transport.use,\n };\n}\n\nexport type StreamClient = ReturnType<typeof createStream>;\n","import type { QueryKey } from './types';\n\nimport { createApi } from './api';\nimport { createMutation, type Mutation, type MutationFn, type MutationOptions } from './mutation';\nimport { createQuery, type QueryClientOptions } from './query';\nimport { createStream } from './stream';\nimport { createTransportCore, type TransportOptions } from './transport';\n\n/**\n * Extended mutation options for `client.mutation()` on a `Courier` instance.\n * Includes all `MutationOptions` plus `invalidates` and `sets` cache shorthands.\n */\nexport type CourierMutationOptions<TData = unknown, TVariables = void> = MutationOptions<TData, TVariables> & {\n /** Query keys to invalidate in the shared cache on success. Runs before `onSuccess`. */\n invalidates?: QueryKey[];\n /**\n * Imperatively seed the cache on success. Return an array of `[key, data]` pairs.\n * Runs before `onSuccess`.\n *\n * @example\n * ```ts\n * sets: (user) => [[ ['users', user.id], user ], [ ['users'], allUsers ]]\n * ```\n */\n sets?: (data: TData, variables: TVariables) => Array<[QueryKey, unknown]>;\n};\n\nexport type CourierOptions = TransportOptions & {\n /**\n * Default options merged into every `mutation()` call.\n * Only retry/callback-error options are meaningful here — lifecycle callbacks\n * (`onSuccess`, `onError`, `onSettled`) should be provided per-mutation since\n * they receive typed variables that differ per mutation.\n */\n mutationDefaults?: Pick<MutationOptions, 'delay' | 'onCallbackError' | 'shouldRetry' | 'times'>;\n /** Options specific to the query cache (staleTime, gcTime, refetch policies, etc.). */\n query?: QueryClientOptions;\n};\n\n/**\n * Create a unified Courier instance backed by a single shared transport.\n *\n * `baseUrl`, `headers`, `timeout`, and `fetch` are shared between the `api` and\n * `stream` sub-clients. Interceptors registered via `courier.use()` apply to all\n * HTTP requests — REST calls and SSE connections alike.\n *\n * @example\n * ```ts\n * const client = createCourier({\n * baseUrl: 'https://api.example.com',\n * headers: { authorization: `Bearer ${token}` },\n * });\n *\n * // Interceptors apply to both api and stream\n * client.use(async (ctx, next) => {\n * return next(ctx.withHeaders({ 'x-request-id': crypto.randomUUID() }));\n * });\n *\n * const user = await client.api.get<User>('/users/{id}', { params: { id: '1' } });\n * const src = client.stream.sse('/events', { reconnect: true });\n * ```\n */\nexport function createCourier(opts?: CourierOptions) {\n const { mutationDefaults, query: queryOpts, ...transportOpts } = opts ?? {};\n\n // Single shared transport — interceptors, headers, and cancellation are\n // unified across the api and stream sub-clients.\n // REST requests use DEFAULT_TIMEOUT (30s); SSE/readable streams default to\n // Infinity individually inside createStream, so the two concerns stay separate.\n const transport = createTransportCore(transportOpts);\n\n const api = createApi({ transport });\n const stream = createStream({ transport });\n\n // Wire transport.dispatch into the query client so query fetches flow through\n // the same interceptor pipeline as api/stream requests (auth, logging, etc.).\n // The adapter converts the query fetch (url + AbortSignal) to a full dispatch call,\n // merging global headers so interceptors that add per-request headers work correctly.\n const transportFetch: typeof globalThis.fetch = (input, init) => {\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;\n const { signal, ...restInit } = init ?? {};\n const headers = Object.fromEntries(new Headers({ ...transport.getHeaders(), ...(init?.headers ?? {}) }).entries());\n\n return transport.dispatch({ headers, init: { ...restInit, signal }, url });\n };\n\n const queryClient = createQuery({ ...queryOpts, fetch: transportFetch });\n\n return {\n api,\n\n /** Abort all in-flight requests, SSE connections, and query cache fetches. Does not dispose the client. */\n cancelAll(): void {\n transport.cancelAll();\n queryClient.cancelAll();\n },\n\n /** `AbortSignal` aborted when the client is disposed. Use to tie other lifecycles to this client. */\n get disposalSignal() {\n return transport.disposalSignal;\n },\n\n /**\n * Permanently dispose the client. All in-flight requests, SSE connections,\n * and query cache fetches are aborted. Idempotent.\n */\n dispose(): void {\n transport.dispose();\n queryClient.dispose();\n },\n\n /** `true` after `dispose()` is called. */\n get disposed(): boolean {\n return transport.disposed;\n },\n\n /** Update or delete global headers. Applies to both API requests and SSE streams. */\n headers: transport.headers,\n\n /**\n * Create a mutation instance with optional lifecycle callbacks.\n *\n * The `invalidates` and `sets` shorthands automatically update the shared query\n * cache on success, eliminating boilerplate in the `onSuccess` callback.\n *\n * @example\n * ```ts\n * const createUser = client.mutation(\n * (input: NewUser, signal) => client.api.post<User>('/users', { body: input, signal }),\n * {\n * invalidates: [['users']],\n * sets: (user) => [[ ['users', user.id], user ]],\n * },\n * );\n * ```\n */\n mutation<TData, TVariables = void>(\n fn: MutationFn<TData, TVariables>,\n mutOpts?: CourierMutationOptions<TData, TVariables>,\n ): Mutation<TData, TVariables> {\n const { invalidates, sets, ...rest } = mutOpts ?? {};\n\n const wrappedOnSuccess = async (data: TData, variables: TVariables): Promise<void> => {\n if (sets) {\n const pairs = sets(data, variables);\n\n for (const [key, val] of pairs) queryClient.set(key, val);\n }\n\n if (invalidates) {\n for (const key of invalidates) queryClient.invalidate(key);\n }\n\n await rest.onSuccess?.(data, variables);\n };\n\n return createMutation(fn, { ...mutationDefaults, ...rest, onSuccess: wrappedOnSuccess });\n },\n\n /** Query / cache client. */\n query: queryClient,\n\n /** SSE and ReadableStream client. */\n stream,\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n\n /** Register a shared interceptor that applies to both API requests and SSE connections. */\n use: transport.use,\n };\n}\n\nexport type Courier = ReturnType<typeof createCourier>;\n","const isDev = !(globalThis as { __COURIER_PROD__?: boolean }).__COURIER_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/courier] ${msg}`);\n}\n","import { warn } from './_dev';\n\n/**\n * Binds a query client's refetchStale() method to browser lifecycle events\n * (document visibility and network reconnect), returning a disposer.\n *\n * This is the explicit opt-in replacement for the removed `refetchOnFocus` and\n * `refetchOnReconnect` QueryClientOptions, giving full control over when and\n * where listeners are attached without hidden global side-effects.\n *\n * In a non-browser environment (no `document`/`window`, e.g. SSR) this is a no-op — a dev\n * warning is logged and the returned disposer does nothing when called.\n *\n * @example\n * ```ts\n * const qc = createQuery({ staleTime: 30_000 });\n * const unbind = bindRefetch(qc);\n * // later — e.g. in a component teardown or route leave:\n * unbind();\n * ```\n */\nexport function bindRefetch(qc: { refetchStale(): void }, opts?: { signal?: AbortSignal }): () => void {\n const disposers: Array<() => void> = [];\n const hasDocument = typeof document !== 'undefined';\n const hasWindow = typeof window !== 'undefined';\n\n if (!hasDocument && !hasWindow) {\n warn('bindRefetch() called with no document/window in scope — no listeners attached');\n }\n\n if (hasDocument) {\n const handler = () => {\n if (document.visibilityState === 'visible') qc.refetchStale();\n };\n\n document.addEventListener('visibilitychange', handler);\n disposers.push(() => document.removeEventListener('visibilitychange', handler));\n }\n\n if (hasWindow) {\n const handler = () => qc.refetchStale();\n\n window.addEventListener('online', handler);\n disposers.push(() => window.removeEventListener('online', handler));\n }\n\n const unbind = () => {\n for (const dispose of disposers) dispose();\n disposers.length = 0;\n };\n\n opts?.signal?.addEventListener('abort', unbind, { once: true });\n\n return unbind;\n}\n","import { uuid } from '@vielzeug/arsenal';\n\nimport type { Interceptor } from './transport';\n\n/**\n * Attaches a Bearer token `Authorization` header to every request.\n * The token can be a static string or an async function (useful for refresh flows).\n *\n * @example\n * ```ts\n * client.use(withBearerAuth(() => tokenStore.getAccessToken()));\n * ```\n */\nexport function withBearerAuth(token: string | (() => string | Promise<string>)): Interceptor {\n return async (ctx, next) => {\n const t = typeof token === 'function' ? await token() : token;\n\n return next(ctx.withHeaders({ authorization: `Bearer ${t}` }));\n };\n}\n\n/**\n * Adds a unique request ID to every request as a header.\n *\n * Defaults to `x-request-id` populated with `crypto.randomUUID()`.\n *\n * @example\n * ```ts\n * client.use(withRequestId());\n * client.use(withRequestId({ header: 'x-trace-id' }));\n * ```\n */\nexport function withRequestId(opts?: { generate?: () => string; header?: string }): Interceptor {\n const header = opts?.header ?? 'x-request-id';\n const generate = opts?.generate ?? uuid;\n\n return (ctx, next) => next(ctx.withHeaders({ [header]: generate() }));\n}\n\n/**\n * Logs each request's method, URL, status code, and duration.\n *\n * Defaults to `console.debug`. Supply a custom `logger` for structured logging.\n *\n * **Security note:** The full URL is logged, including any query parameters.\n * If your URLs may contain sensitive data (tokens, PII), provide a custom\n * `logger` that sanitizes the URL before writing to persistent logs.\n *\n * @example\n * ```ts\n * client.use(withLogging());\n * client.use(withLogging({ logger: (msg, meta) => logger.info(meta) }));\n * ```\n */\nexport function withLogging(opts?: {\n logger?: (msg: string, meta: { duration: number; method: string; status: number; url: string }) => void;\n}): Interceptor {\n const log =\n opts?.logger ??\n ((msg, meta) => {\n console.debug(msg, meta);\n });\n\n return async (ctx, next) => {\n const start = performance.now();\n const method = ((ctx.init as RequestInit).method ?? 'GET').toUpperCase();\n\n try {\n const res = await next(ctx);\n const duration = Math.round(performance.now() - start);\n\n log(`${method} ${ctx.url} ${res.status} (${duration}ms)`, {\n duration,\n method,\n status: res.status,\n url: ctx.url,\n });\n\n return res;\n } catch (err) {\n const duration = Math.round(performance.now() - start);\n\n log(`${method} ${ctx.url} ERR (${duration}ms)`, {\n duration,\n method,\n status: 0,\n url: ctx.url,\n });\n\n throw err;\n }\n };\n}\n","import type { QueryKey, QueryState } from './types';\n\nimport { hash } from './serialize';\n\n/**\n * A sync-or-async key-value storage backend. Compatible with `localStorage`,\n * `sessionStorage`, and any async adapter (IndexedDB, filesystem, etc.).\n */\nexport interface PersistStorage {\n getItem(key: string): Promise<string | null> | string | null;\n setItem(key: string, value: string): Promise<void> | void;\n}\n\nexport interface PersistOptions {\n /**\n * The query keys to persist or hydrate. Accepts either:\n * - `QueryKey[]` — an explicit list of keys to observe/restore.\n * - `(key: QueryKey) => boolean` — a predicate applied to all currently cached keys.\n *\n * Both `persistQueryCache` and `hydrateQueryCache` evaluate this consistently.\n */\n keys: QueryKey[] | ((key: QueryKey) => boolean);\n /**\n * Maximum age in ms for a persisted entry to be eligible for hydration.\n * Entries whose `updatedAt` timestamp is older than `Date.now() - maxAge` are\n * skipped during hydration and left for a fresh network fetch.\n * When omitted, all entries are hydrated regardless of age.\n */\n maxAge?: number;\n /**\n * Called when a storage operation (read or write) throws.\n * If omitted, storage errors are silently swallowed.\n */\n onError?: (err: unknown, key: QueryKey) => void;\n /**\n * Storage key prefix to namespace entries and avoid collisions.\n * Defaults to `'courier:'`.\n */\n prefix?: string;\n /** Storage backend. */\n storage: PersistStorage;\n}\n\ntype SerializedEntry = {\n data: unknown;\n updatedAt: number;\n};\n\n/**\n * Subscribes a query client to state changes and writes successful entries to\n * a storage backend on every update. Returns a disposer that stops persistence.\n *\n * Pair with `hydrateQueryCache` to restore entries on page load.\n *\n * @example\n * ```ts\n * const qc = createQuery({ staleTime: 60_000 });\n * const stop = persistQueryCache(qc, {\n * keys: [['users', 1], ['settings']],\n * storage: localStorage,\n * });\n *\n * // On next page load:\n * await hydrateQueryCache(qc, { keys: [['users', 1], ['settings']], storage: localStorage });\n * ```\n */\nexport function persistQueryCache(\n qc: {\n getState(key: QueryKey): QueryState | null;\n keys(): QueryKey[];\n observe(opts: { fetch: false; key: QueryKey }): { peek(): QueryState; subscribe(listener: () => void): () => void };\n },\n opts: PersistOptions,\n): () => void {\n const { keys: keysOpt, onError, prefix = 'courier:', storage } = opts;\n const allKeys = qc.keys();\n const keys = typeof keysOpt === 'function' ? allKeys.filter(keysOpt) : keysOpt;\n const unsubs: Array<() => void> = [];\n\n function storageKey(key: QueryKey): string {\n return `${prefix}${hash(key)}`;\n }\n\n function persistState(key: QueryKey, state: QueryState): void {\n if (state.status !== 'success') return;\n\n const entry: SerializedEntry = { data: state.data, updatedAt: state.updatedAt };\n\n try {\n const result = storage.setItem(storageKey(key), JSON.stringify(entry));\n\n if (result instanceof Promise) {\n result.catch((err: unknown) => onError?.(err, key));\n }\n } catch (err) {\n onError?.(err, key);\n }\n }\n\n for (const key of keys) {\n const current = qc.getState(key);\n\n if (current) persistState(key, current);\n\n const store = qc.observe({ fetch: false, key });\n const unsub = store.subscribe(() => persistState(key, store.peek()));\n\n unsubs.push(unsub);\n }\n\n return () => {\n for (const unsub of unsubs) unsub();\n unsubs.length = 0;\n };\n}\n\n/**\n * Hydrates a query client from persisted storage before any fetches are made.\n * Entries are written via `qc.set()` so observers are notified immediately.\n *\n * @example\n * ```ts\n * await hydrateQueryCache(qc, {\n * keys: [['users', 1], ['settings']],\n * storage: localStorage,\n * });\n * ```\n */\nexport async function hydrateQueryCache(\n qc: { keys(): QueryKey[]; set(key: QueryKey, data: unknown, opts?: { updatedAt?: number }): void },\n opts: PersistOptions,\n): Promise<void> {\n const { keys: keysOpt, maxAge, onError, prefix = 'courier:', storage } = opts;\n const allKeys = qc.keys();\n const keys = typeof keysOpt === 'function' ? allKeys.filter(keysOpt) : keysOpt;\n\n await Promise.all(\n keys.map(async (key) => {\n try {\n const raw = await storage.getItem(`${prefix}${hash(key)}`);\n\n if (!raw) return;\n\n // Use the caller's key — not any key embedded in stored JSON — so the correct\n // cache entry is populated regardless of JSON serialisation edge cases.\n const parsed: unknown = JSON.parse(raw);\n\n // Validate structure before use to guard against schema migrations,\n // corrupt storage, or entries written by older versions of the app.\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('data' in parsed) ||\n typeof (parsed as { updatedAt?: unknown }).updatedAt !== 'number'\n ) {\n onError?.(new Error('[courier] Malformed persisted entry'), key);\n\n return;\n }\n\n const entry = parsed as SerializedEntry;\n\n // Skip entries that exceed the caller's maximum age threshold.\n if (maxAge !== undefined && Date.now() - entry.updatedAt > maxAge) return;\n\n // Restore the original updatedAt so staleTime checks after hydration are\n // accurate — data hydrated from a 55-second-old entry should be considered\n // almost stale, not brand-new.\n qc.set(key, entry.data, { updatedAt: entry.updatedAt });\n } catch (err) {\n onError?.(err, key);\n }\n }),\n );\n}\n","import type { SyncStore, Unsubscribe } from './types';\n\n/**\n * Converts any object with `peek()` and `subscribe()` methods into a plain\n * `SyncStore<T>` suitable for framework integration adapters.\n *\n * @example\n * ```ts\n * // React\n * const store = toSyncStore(mutation);\n * const state = useSyncExternalStore(store.subscribe, store.peek);\n *\n * // Svelte\n * const readable = toSyncStore(mutation);\n * ```\n */\nexport function toSyncStore<T>(source: { peek(): T; subscribe(cb: () => void): Unsubscribe }): SyncStore<T> {\n return {\n peek: () => source.peek(),\n subscribe: (cb) => source.subscribe(cb),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { QueryKey } from './types';
|
|
2
|
+
import { type Mutation, type MutationFn, type MutationOptions } from './mutation';
|
|
3
|
+
import { type QueryClientOptions } from './query';
|
|
4
|
+
import { type TransportOptions } from './transport';
|
|
5
|
+
/**
|
|
6
|
+
* Extended mutation options for `client.mutation()` on a `Courier` instance.
|
|
7
|
+
* Includes all `MutationOptions` plus `invalidates` and `sets` cache shorthands.
|
|
8
|
+
*/
|
|
9
|
+
export type CourierMutationOptions<TData = unknown, TVariables = void> = MutationOptions<TData, TVariables> & {
|
|
10
|
+
/** Query keys to invalidate in the shared cache on success. Runs before `onSuccess`. */
|
|
11
|
+
invalidates?: QueryKey[];
|
|
12
|
+
/**
|
|
13
|
+
* Imperatively seed the cache on success. Return an array of `[key, data]` pairs.
|
|
14
|
+
* Runs before `onSuccess`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* sets: (user) => [[ ['users', user.id], user ], [ ['users'], allUsers ]]
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
sets?: (data: TData, variables: TVariables) => Array<[QueryKey, unknown]>;
|
|
22
|
+
};
|
|
23
|
+
export type CourierOptions = TransportOptions & {
|
|
24
|
+
/**
|
|
25
|
+
* Default options merged into every `mutation()` call.
|
|
26
|
+
* Only retry/callback-error options are meaningful here — lifecycle callbacks
|
|
27
|
+
* (`onSuccess`, `onError`, `onSettled`) should be provided per-mutation since
|
|
28
|
+
* they receive typed variables that differ per mutation.
|
|
29
|
+
*/
|
|
30
|
+
mutationDefaults?: Pick<MutationOptions, 'delay' | 'onCallbackError' | 'shouldRetry' | 'times'>;
|
|
31
|
+
/** Options specific to the query cache (staleTime, gcTime, refetch policies, etc.). */
|
|
32
|
+
query?: QueryClientOptions;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Create a unified Courier instance backed by a single shared transport.
|
|
36
|
+
*
|
|
37
|
+
* `baseUrl`, `headers`, `timeout`, and `fetch` are shared between the `api` and
|
|
38
|
+
* `stream` sub-clients. Interceptors registered via `courier.use()` apply to all
|
|
39
|
+
* HTTP requests — REST calls and SSE connections alike.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const client = createCourier({
|
|
44
|
+
* baseUrl: 'https://api.example.com',
|
|
45
|
+
* headers: { authorization: `Bearer ${token}` },
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* // Interceptors apply to both api and stream
|
|
49
|
+
* client.use(async (ctx, next) => {
|
|
50
|
+
* return next(ctx.withHeaders({ 'x-request-id': crypto.randomUUID() }));
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* const user = await client.api.get<User>('/users/{id}', { params: { id: '1' } });
|
|
54
|
+
* const src = client.stream.sse('/events', { reconnect: true });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function createCourier(opts?: CourierOptions): {
|
|
58
|
+
api: {
|
|
59
|
+
cancelAll(): void;
|
|
60
|
+
delete: <T, P extends string = string>(url: P, cfg?: import("./url").HttpRequestConfig<P>) => Promise<T>;
|
|
61
|
+
readonly disposalSignal: AbortSignal;
|
|
62
|
+
dispose(): void;
|
|
63
|
+
readonly disposed: boolean;
|
|
64
|
+
get: <T, P extends string = string>(url: P, cfg?: import("./url").HttpRequestConfig<P>) => Promise<T>;
|
|
65
|
+
getHeaders: () => Readonly<Record<string, string>>;
|
|
66
|
+
headers: (updates: Record<string, string | undefined>) => void;
|
|
67
|
+
patch: <T, P extends string = string>(url: P, cfg?: import("./url").HttpRequestConfig<P>) => Promise<T>;
|
|
68
|
+
post: <T, P extends string = string>(url: P, cfg?: import("./url").HttpRequestConfig<P>) => Promise<T>;
|
|
69
|
+
put: <T, P extends string = string>(url: P, cfg?: import("./url").HttpRequestConfig<P>) => Promise<T>;
|
|
70
|
+
request: <T, P extends string = string>(method: string, url: P, config?: import("./url").HttpRequestConfig<P>) => Promise<T>;
|
|
71
|
+
[Symbol.dispose](): void;
|
|
72
|
+
use: (interceptor: import("./transport").Interceptor) => () => void;
|
|
73
|
+
};
|
|
74
|
+
/** Abort all in-flight requests, SSE connections, and query cache fetches. Does not dispose the client. */
|
|
75
|
+
cancelAll(): void;
|
|
76
|
+
/** `AbortSignal` aborted when the client is disposed. Use to tie other lifecycles to this client. */
|
|
77
|
+
readonly disposalSignal: AbortSignal;
|
|
78
|
+
/**
|
|
79
|
+
* Permanently dispose the client. All in-flight requests, SSE connections,
|
|
80
|
+
* and query cache fetches are aborted. Idempotent.
|
|
81
|
+
*/
|
|
82
|
+
dispose(): void;
|
|
83
|
+
/** `true` after `dispose()` is called. */
|
|
84
|
+
readonly disposed: boolean;
|
|
85
|
+
/** Update or delete global headers. Applies to both API requests and SSE streams. */
|
|
86
|
+
headers: (updates: Record<string, string | undefined>) => void;
|
|
87
|
+
/**
|
|
88
|
+
* Create a mutation instance with optional lifecycle callbacks.
|
|
89
|
+
*
|
|
90
|
+
* The `invalidates` and `sets` shorthands automatically update the shared query
|
|
91
|
+
* cache on success, eliminating boilerplate in the `onSuccess` callback.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const createUser = client.mutation(
|
|
96
|
+
* (input: NewUser, signal) => client.api.post<User>('/users', { body: input, signal }),
|
|
97
|
+
* {
|
|
98
|
+
* invalidates: [['users']],
|
|
99
|
+
* sets: (user) => [[ ['users', user.id], user ]],
|
|
100
|
+
* },
|
|
101
|
+
* );
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
mutation<TData, TVariables = void>(fn: MutationFn<TData, TVariables>, mutOpts?: CourierMutationOptions<TData, TVariables>): Mutation<TData, TVariables>;
|
|
105
|
+
/** Query / cache client. */
|
|
106
|
+
query: {
|
|
107
|
+
cancel(key: QueryKey): void;
|
|
108
|
+
cancelAll(): void;
|
|
109
|
+
clear(): void;
|
|
110
|
+
readonly disposalSignal: AbortSignal;
|
|
111
|
+
dispose(): void;
|
|
112
|
+
readonly disposed: boolean;
|
|
113
|
+
fetch: <T>(options: import("./query").QueryOptions<T>) => Promise<T>;
|
|
114
|
+
fetchMany<T = unknown>(queries: import("./query").QueryOptions<T>[]): Promise<T[]>;
|
|
115
|
+
get<T>(key: QueryKey): T | undefined;
|
|
116
|
+
getState<T>(key: QueryKey): import("./types").QueryState<T> | null;
|
|
117
|
+
invalidate: (key: QueryKey) => void;
|
|
118
|
+
keys(): QueryKey[];
|
|
119
|
+
observe: <T = unknown, S = T>(options: import("./query").ObserveOptions<T, S>) => import("./types").SyncStore<import("./types").QueryState<S>>;
|
|
120
|
+
observeMany<T = unknown>(keys: QueryKey[]): import("./types").SyncStore<import("./types").QueryState<T>[]>;
|
|
121
|
+
refetchStale(): void;
|
|
122
|
+
remove(key: QueryKey): void;
|
|
123
|
+
set: {
|
|
124
|
+
<T>(key: QueryKey, data: T, opts?: {
|
|
125
|
+
gcTime?: number;
|
|
126
|
+
updatedAt?: number;
|
|
127
|
+
}): void;
|
|
128
|
+
<T>(key: QueryKey, updater: (old: T | undefined) => T, opts?: {
|
|
129
|
+
gcTime?: number;
|
|
130
|
+
updatedAt?: number;
|
|
131
|
+
}): void;
|
|
132
|
+
};
|
|
133
|
+
readonly size: number;
|
|
134
|
+
[Symbol.dispose](): void;
|
|
135
|
+
};
|
|
136
|
+
/** SSE and ReadableStream client. */
|
|
137
|
+
stream: {
|
|
138
|
+
cancelAll(): void;
|
|
139
|
+
readonly disposalSignal: AbortSignal;
|
|
140
|
+
dispose(): void;
|
|
141
|
+
readonly disposed: boolean;
|
|
142
|
+
getHeaders: () => Readonly<Record<string, string>>;
|
|
143
|
+
headers: (updates: Record<string, string | undefined>) => void;
|
|
144
|
+
readable: <T = string, P extends string = string>(url: P, config?: import("./stream").ReadableConfig<P>) => AsyncGenerator<T>;
|
|
145
|
+
sse: <TEvents extends Record<string, unknown> = Record<string, string>, P extends string = string>(url: P, config?: import("./stream").SseOptions<P>) => import("./stream").SseSource<TEvents>;
|
|
146
|
+
[Symbol.dispose](): void;
|
|
147
|
+
use: (interceptor: import("./transport").Interceptor) => () => void;
|
|
148
|
+
};
|
|
149
|
+
[Symbol.dispose](): void;
|
|
150
|
+
/** Register a shared interceptor that applies to both API requests and SSE connections. */
|
|
151
|
+
use: (interceptor: import("./transport").Interceptor) => () => void;
|
|
152
|
+
};
|
|
153
|
+
export type Courier = ReturnType<typeof createCourier>;
|
|
154
|
+
//# sourceMappingURL=courier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"courier.d.ts","sourceRoot":"","sources":["../src/courier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAClG,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEzE;;;GAGG;AACH,MAAM,MAAM,sBAAsB,CAAC,KAAK,GAAG,OAAO,EAAE,UAAU,GAAG,IAAI,IAAI,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG;IAC5G,wFAAwF;IACxF,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;IACzB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,KAAK,KAAK,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;CAC3E,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG;IAC9C;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,iBAAiB,GAAG,aAAa,GAAG,OAAO,CAAC,CAAC;IAChG,uFAAuF;IACvF,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;IA6B/C,2GAA2G;iBAC9F,IAAI;IAKjB,qGAAqG;;IAKrG;;;OAGG;eACQ,IAAI;IAKf,0CAA0C;uBAC1B,OAAO;IAIvB,qFAAqF;;IAGrF;;;;;;;;;;;;;;;;OAgBG;aACM,KAAK,EAAE,UAAU,aACpB,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,YACvB,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC,GAClD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAoB9B,4BAA4B;;;;;;;;;;;;;;;;;;;;sBAb2B,CAAC;yBAGpD,CAAR;;;sBAIQ,CAAC;yBAAmB,CAAC;;;;;;IASzB,qCAAqC;;;;;;;;;;;;;wBAGjB,IAAI;IAIxB,2FAA2F;;EAG9F;AAED,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
var Courier=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},r=class e extends n{url;method;status;data;headers;constructor(e){super(e.message),this.url=e.url,this.method=e.method,this.status=e.status,this.data=e.data,this.headers=e.headers}static fromResponse(t,n,r,i){return new e({data:n,headers:t.headers,message:t.statusText||`HTTP ${t.status}`,method:r,status:t.status,url:i})}static is(t,n){return t instanceof e&&(n===void 0||t.status===n)}},i=class extends n{url;method;constructor(e){super(e.message,{cause:e.cause}),this.url=e.url,this.method=e.method}},a=class extends n{url;method;constructor(e){super(e.message,{cause:e.cause}),this.url=e.url,this.method=e.method}},o=class extends n{url;method;constructor(e){super(e.message,{cause:e.cause}),this.url=e.url,this.method=e.method}},s=class extends n{data;constructor(e,t){super(e instanceof Error?e.message:String(e),{cause:e}),this.data=t}},c=class extends n{},l=class extends n{constructor(e){super(`[courier] ${e} disposed`)}},u=class extends n{};function d(e,t,n,r){let s=e instanceof Error?e.message:String(e),c=r?.reason;return c instanceof Error&&c.name===`TimeoutError`?new a({cause:e,message:s,method:t,url:n}):e instanceof DOMException?e.name===`TimeoutError`?new a({cause:e,message:s,method:t,url:n}):new o({cause:e,message:s,method:t,url:n}):e instanceof Error&&e.name===`AbortError`||r?.aborted?new o({cause:e,message:s,method:t,url:n}):new i({cause:e,message:s,method:t,url:n})}async function f(e,t=`auto`){if(t===`raw`)return e;if(e.status===204||e.status===205||e.status===304)return;if(t===`json`)return e.json();if(t===`text`)return e.text();if(t===`blob`)return e.blob();if(t===`arrayBuffer`)return e.arrayBuffer();let n=e.headers.get(`content-type`)??``;return n.includes(`application/json`)||n.includes(`+json`)?e.json():n.startsWith(`text/`)?e.text():n.startsWith(`image/`)||n.startsWith(`audio/`)||n.startsWith(`video/`)?e.blob():e.text()}function p(e,t,n,r,i){return n!==void 0&&!m(n)?{...i,body:JSON.stringify(n),headers:{"content-type":`application/json`,...t},method:e.toUpperCase(),signal:r}:{...i,...n!==void 0&&{body:n},headers:t,method:e.toUpperCase(),signal:r}}function m(e){return e instanceof FormData||e instanceof Blob||e instanceof URLSearchParams||typeof e==`string`||e instanceof ArrayBuffer||ArrayBuffer.isView(e)||typeof ReadableStream<`u`&&e instanceof ReadableStream}function h(e,t,n){return{headers:t,init:n,url:e,withHeaders(r){let i={...t};for(let[e,t]of Object.entries(r))i[e.toLowerCase()]=t;return h(e,i,n)}}}function g(...e){let t=e.filter(e=>e!=null);if(t.length!==0)return t.length===1?t[0]:AbortSignal.any(t)}var _=3e4;function v(e){if((e<=0||!Number.isFinite(e))&&e!==1/0)throw new n(`[courier] timeout must be a positive number or Infinity`)}function y(e,t){return e===1/0?t??void 0:g(AbortSignal.timeout(e),t)}function b(e={}){let{baseUrl:t=``,fetch:n=globalThis.fetch,headers:r={},timeout:i=_}=e;v(i);let a=Object.fromEntries(Object.entries(r).map(([e,t])=>[e.toLowerCase(),t])),o=new Set,s=new AbortController,c=[],l=null,u=!1;function d(){if(l)return l;let e=e=>n(e.url,{...e.init,headers:e.headers});return l=c.length===0?e:c.reduceRight((e,t)=>n=>t(n,e),e),l}function f(e){return c.push(e),l=null,()=>{let t=c.indexOf(e);t!==-1&&(c.splice(t,1),l=null)}}function p(e){for(let[t,n]of Object.entries(e)){let e=t.toLowerCase();n===void 0?delete a[e]:a[e]=n}}function m(){return{...a}}function g(e,t){let n=e?Object.fromEntries(Object.entries(e).map(([e,t])=>[e.toLowerCase(),t])):void 0;return{...a,...n,...t}}function y(e){return o.add(e),()=>o.delete(e)}function b(e){return d()(h(e.url,e.headers,e.init))}function x(){for(let e of[...o])e.abort();o.clear()}function S(){if(!u){u=!0,s.abort();for(let e of o)e.abort();o.clear(),c.length=0,l=null}}return{baseUrl:t,cancelAll:x,dispatch:b,get disposalSignal(){return s.signal},dispose:S,get disposed(){return u},getHeaders:m,getTimeout(){return i},headers:p,mergeHeaders:g,track:y,use:f}}function x(e,t,n,r){let i=e.replace(/\/+$/,``),a=t.replace(/^\/+/,``);a=a.replace(/\{([^}]+)\}/g,(e,r)=>{let i=n?.[r];if(i==null)throw new u(`unresolved path param {${r}} in '${t}'`);return encodeURIComponent(String(i))});let o=i&&a?`${i}/${a}`:i||a;if(!r)return o;let s=new URLSearchParams;for(let[e,t]of Object.entries(r))if(t!==void 0){if(Array.isArray(t)){for(let n of t)n!==void 0&&s.append(e,n===null?``:String(n));continue}s.append(e,t===null?``:String(t))}let c=s.toString();return c?`${o}${o.includes(`?`)?`&`:`?`}${c}`:o}var S=new Set([`GET`,`HEAD`,`OPTIONS`]);function C(e,n,r,i){if(S.has(e))return`${e}:${n}:${r}`;if(i!==void 0)return`${e}:${n}:${(0,t.hash)(i)}`}function w(e){let{transport:t,...n}=e??{},i=t??b(n),a=!t,o=new Map;async function c(e,t,n,a,o,c){let l=t.signal,u;try{u=await i.dispatch({headers:e,init:t,url:n})}catch(e){throw d(e,a,n,l)}if(!u.ok){let e;try{e=await f(u,o??`auto`)}catch{e=await u.text().catch(()=>``)}throw r.fromResponse(u,e,a,n)}let p;try{p=await f(u,o??`auto`)}catch(e){throw d(e,a,n,l)}if(c)try{return c.parse(p)}catch(e){throw new s(e,p)}return p}async function u(e,t,n={}){if(i.disposed)throw new l(`ApiClient`);let r=e.toUpperCase(),a;try{a=x(i.baseUrl,t,n.params,n.query)}catch(e){throw d(e,r,t)}let{body:s,dedupe:u=!0,dedupeKey:f,fetchInit:m,headers:h,responseType:_,schema:b,signal:S,timeout:w}=n;w!==void 0&&v(w);let T=i.mergeHeaders(h),E=u?C(r,a,_??`auto`,f):void 0;if(E){let e=o.get(E);if(e)return e}let D=new AbortController,O=i.track(D),k=g(S,D.signal)??D.signal,{headers:A,...j}=p(r,T,s,y(w??i.getTimeout(),k),m??{}),M=c(A,j,a,r,_,b);E&&o.set(E,M);try{return await M}finally{E&&o.delete(E),O()}}return{cancelAll(){i.cancelAll(),o.clear()},delete:(e,t)=>u(`DELETE`,e,t),get disposalSignal(){return i.disposalSignal},dispose(){o.clear(),a&&i.dispose()},get disposed(){return i.disposed},get:(e,t)=>u(`GET`,e,t),getHeaders:i.getHeaders,headers:i.headers,patch:(e,t)=>u(`PATCH`,e,t),post:(e,t)=>u(`POST`,e,t),put:(e,t)=>u(`PUT`,e,t),request:u,[Symbol.dispose](){this.dispose()},use:i.use}}function T(e){let{maxSize:t=25,resolve:n,resolveSettled:r,window:i=0}=e,a=[],o=new AbortController,s=!1,u=null,d=!1;function f(){if(a.length===0)return;let e=a.splice(0,t);a.length>0&&p();let i=e.map(e=>e.key);try{r?r(i).then(t=>{if(t.length!==e.length){let n=new c(`Batcher: resolveSettled() returned ${t.length} results for ${e.length} keys`);for(let t of e)t.reject(n);return}e.forEach((e,n)=>{let r=t[n];r.status===`fulfilled`?e.resolve(r.value):e.reject(r.reason)})}).catch(t=>{for(let n of e)n.reject(t)}):n(i).then(t=>{if(t.length!==e.length){let n=new c(`Batcher: resolve() returned ${t.length} results for ${e.length} keys`);for(let t of e)t.reject(n);return}e.forEach((e,n)=>e.resolve(t[n]))}).catch(t=>{for(let n of e)n.reject(t)})}catch(t){for(let n of e)n.reject(t)}}function p(){s||(s=!0,i===0?queueMicrotask(()=>{s=!1,f()}):u=setTimeout(()=>{u=null,s=!1,f()},i))}return{get disposalSignal(){return o.signal},dispose(){if(d)return;d=!0,u!==null&&(clearTimeout(u),u=null);let e=new l(`Batcher`);for(let t of a.splice(0))t.reject(e);s=!1,o.abort()},get disposed(){return d},load(e){return d?Promise.reject(new l(`Batcher`)):new Promise((n,r)=>{a.push({key:e,reject:r,resolve:n}),a.length>=t?(u!==null&&(clearTimeout(u),u=null),s=!1,f()):p()})},[Symbol.dispose](){this.dispose()}}}function E(e){return Math.random()*(0,t.backoff)(e)}function D(e,t){if(typeof t==`function`){let n=t(e);return Number.isFinite(n)?Math.max(0,n):0}return typeof t==`number`?Number.isFinite(t)?Math.max(0,t):0:E(e)}var O=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!1,status:`loading`,updatedAt:void 0});function k(e,n){let r=O,i=0,a=null,o=new Set,s=!1,c=null;function u(){o.forEach(e=>e())}async function d(e){try{await e?.()}catch(e){if(n?.onCallbackError)try{n.onCallbackError(e instanceof Error?e:Error(String(e)))}catch{}}}return{async cancel(){let e=a;e&&(e.controller.abort(),await e.promise.catch(()=>{}))},dispose(){s||(s=!0,a?.controller.abort(),a=null,o.clear())},get disposed(){return s},async mutate(o,c){if(s)throw new l(`Mutation`);let f=new AbortController,p=c?.signal?g(c.signal,f.signal):f.signal,m=++i;r={data:void 0,error:null,isFetching:!0,isLoading:!0,status:`loading`,updatedAt:void 0},u();let h={controller:f,promise:null};a=h;let _=(async()=>{try{let a=await(0,t.retry)(()=>e(o,p),{delay:e=>D(e,n?.delay),shouldRetry:n?.shouldRetry,signal:p,times:n?.times??1});return m===i&&(r={data:a,error:null,isFetching:!1,isLoading:!1,status:`success`,updatedAt:Date.now()},u()),await d(()=>n?.onSuccess?.(a,o)),await d(()=>n?.onFinally?.(o)),await d(()=>n?.onSettled?.({data:a,status:`success`,variables:o})),a}catch(e){let a=e instanceof Error?e:Error(String(e)),s=p.aborted||(0,t.isAbortError)(a);throw m===i&&(r=s?O:{data:void 0,error:a,isFetching:!1,isLoading:!1,status:`error`,updatedAt:Date.now()},u()),s||await d(()=>n?.onError?.(a,o)),await d(()=>n?.onFinally?.(o)),await d(()=>n?.onSettled?.(s?{status:`aborted`,variables:o}:{error:a,status:`error`,variables:o})),a}finally{a?.controller===f&&(a=null)}})();return h.promise=_,_},peek(){return r},reset(){r=O,u()},get store(){return c??={peek:()=>r,subscribe:e=>(o.add(e),()=>o.delete(e))}},subscribe(e){return o.add(e),()=>o.delete(e)},[Symbol.dispose](){this.dispose()}}}function A(e){return typeof e==`function`?e():e}function j(e){return(0,t.hash)(e)}function M(e){return(0,t.hash)(e)}function N(e,n){let r=(0,t.hash)(n),i=e.entries.get(r);return i||(i={data:void 0,error:null,hash:r,inflight:null,isFetching:!1,key:n,lastConfig:void 0,observers:new Set,segmentHashes:n.map(e=>(0,t.hash)(e)),status:`loading`,updatedAt:void 0},e.entries.set(r,i)),i}function P(e,t){let n=e.gcTimers.get(t);n&&(clearTimeout(n),e.gcTimers.delete(t))}function F(e,t,n){if(e.disposed||(P(e,t.hash),t.observers.size>0))return;if(n===0){e.entries.delete(t.hash);return}let r=setTimeout(()=>{let n=e.entries.get(t.hash);!n||n.observers.size>0||n.isFetching||(e.entries.delete(t.hash),e.gcTimers.delete(t.hash))},n);e.gcTimers.set(t.hash,r)}function I(e,t){t.inflight?.controller.abort(),P(e,t.hash),e.entries.delete(t.hash)}function L(e,t){return t.length>e.segmentHashes.length?!1:t.every((t,n)=>t===e.segmentHashes[n])}function R(e,t){t.isFetching=!0,t.status=`loading`,t.error=null,e.notify(t)}function z(e,t,n,r){t.data=n,t.error=null,t.status=`success`,t.updatedAt=Date.now(),t.isFetching=!1,t.inflight=null,F(e,t,r),e.notify(t)}function B(e,t,n,r){t.error=n,t.status=`error`,t.updatedAt=Date.now(),t.isFetching=!1,t.inflight=null,F(e,t,r),e.notify(t)}function V(e,t,n,r){if(t.data=n.data,t.error=n.error,t.status=n.status,t.updatedAt=n.updatedAt,t.isFetching=!1,t.inflight=null,t.observers.size===0&&t.status===`loading`&&t.data===void 0){I(e,t);return}F(e,t,r),e.notify(t)}function H(e,t){if(t.inflight?.controller.abort(),t.observers.size>0){t.inflight=null,t.isFetching=!1,t.status=`loading`,t.data=void 0,t.error=null,t.updatedAt=void 0,e.notify(t);return}I(e,t)}function U(e,n,r){if(n.inflight)return n.inflight.promise;let{delay:i,fn:a,gcTime:o,shouldRetry:s,times:c}=r,l=new AbortController,u={data:n.data,error:n.error,status:n.status,updatedAt:n.updatedAt},d=(async()=>{try{let r=await(0,t.retry)(()=>a({key:n.key,signal:l.signal}),{delay:e=>D(e,i),shouldRetry:s,signal:l.signal,times:c});return z(e,n,r,o),r}catch(r){let i=r instanceof Error?r:Error(String(r));throw l.signal.aborted||(0,t.isAbortError)(i)?V(e,n,u,o):B(e,n,i,o),i}})();return n.inflight={controller:l,promise:d},R(e,n),d}function W(e,t){return{delay:t.delay??e.delayDefault,fn:t.fn,gcTime:t.gcTime??e.gcTimeDefault,shouldRetry:t.shouldRetry??e.shouldRetryDefault,staleTime:t.staleTime??e.staleTimeDefault,times:t.times??e.timesDefault}}function G(e,t,n,r){return{delayDefault:e.delay,disposed:!1,entries:t,gcTimeDefault:e.gcTime??3e5,gcTimers:n,notify:r,shouldRetryDefault:e.shouldRetry,staleTimeDefault:e.staleTime??0,timesDefault:e.times??1}}var K=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function q(e){return e.status===`loading`?{data:void 0,error:null,isFetching:e.isFetching,isLoading:!0,status:`loading`,updatedAt:void 0}:e.status===`success`?{data:e.data,error:null,isFetching:e.isFetching,isLoading:!1,status:`success`,updatedAt:e.updatedAt}:{data:e.data,error:e.error,isFetching:e.isFetching,isLoading:!1,status:`error`,updatedAt:e.updatedAt}}function J(e,t){let n=q(e);if(n.status===`loading`){let e=A(t.placeholderData);return{...n,data:e}}let r=t.select?t.select(n.data):n.data;return{...n,data:r}}function Y(e){for(let t of e.observers){let n=t,r=J(e,n),i=n.previous,a=Object.is(i?.data,r.data),o=!!i&&i.status===r.status&&i.isFetching===r.isFetching&&Object.is(i.error,r.error);(n.select?o&&a:o&&i?.updatedAt===r.updatedAt&&a)||(n.previous=r,n.listener())}}function X(e,t,n){let r={listener:()=>{},...n};return{peek(){let n=e.entries.get(j(t));return n?J(n,r):K},subscribe(i){let a=N(e,t);P(e,a.hash);let o={...n,listener:i,previous:J(a,r)};return a.observers.add(o),()=>{a.observers.delete(o),a.observers.size===0&&F(e,a,a.lastConfig?.gcTime??e.gcTimeDefault)}}}}function Z(e){let t=!1,n=new AbortController,r=new Map,i=new Map,a=G({delay:e?.delay,gcTime:e?.gcTime,shouldRetry:e?.shouldRetry,staleTime:e?.staleTime,times:e?.times},r,i,Y);async function o(e){if(t)throw new l(`QueryClient`);let{enabled:n=!0,fn:i,gcTime:o,initialData:s,key:c,staleTime:u,...d}=e;if(!n){let e=j(c);return r.get(e)?.data??void 0}let f=N(a,c),p=W(a,{fn:i,gcTime:o,staleTime:u,...d});if(s!==void 0&&f.status===`loading`&&f.data===void 0){let e=A(s);e!==void 0&&(f.data=e,f.error=null,f.status=`success`,f.updatedAt=Date.now())}return f.status===`success`&&f.updatedAt!==void 0&&Date.now()-f.updatedAt<p.staleTime&&!f.isFetching?(f.lastConfig=p,f.data):(f.lastConfig=p,f.inflight?f.inflight.promise:U(a,f,p))}function s(e){if(!e.lastConfig){H(a,e);return}e.isFetching||U(a,e,e.lastConfig).catch(()=>{})}function c(e){let t=e.map(e=>M(e));for(let e of[...r.values()])if(L(e,t)){if(e.observers.size>0){s(e);continue}H(a,e)}}function u(e,t,n){let r=N(a,e),i=n?.gcTime??r.lastConfig?.gcTime??a.gcTimeDefault;r.data=typeof t==`function`?t(r.data):t,r.error=null,r.status=`success`,r.updatedAt=n?.updatedAt??Date.now(),r.isFetching=!1,r.inflight=null,Y(r),F(a,r,i)}function d(e){return e.observers.size===0||!e.lastConfig||e.isFetching?!1:e.status===`success`&&e.updatedAt!==void 0||e.status===`error`&&e.data!==void 0&&e.updatedAt!==void 0?Date.now()-e.updatedAt>=e.lastConfig.staleTime:!1}function f(e){let{fetch:t=!0,key:n,placeholderData:r,select:i}=e,s=X(a,n,{placeholderData:r,select:i});return t&&e.fn&&o({...e}).catch(()=>{}),s}return{cancel(e){let t=r.get(j(e));t?.inflight&&t.inflight.controller.abort()},cancelAll(){for(let e of r.values())e.inflight?.controller.abort()},clear(){for(let e of[...r.values()])H(a,e)},get disposalSignal(){return n.signal},dispose(){if(!t){t=!0,a.disposed=!0,n.abort();for(let[,e]of r)e.observers.clear(),e.inflight?.controller.abort();for(let[,e]of i)clearTimeout(e);i.clear(),r.clear()}},get disposed(){return t},fetch:o,fetchMany(e){return Promise.all(e.map(e=>o(e)))},get(e){let t=r.get(j(e));return t?t.data:void 0},getState(e){let t=r.get(j(e));return t?q(t):null},invalidate:c,keys(){return[...r.values()].map(e=>e.key)},observe:f,observeMany(e){let t=e.map(e=>X(a,e));return{peek(){return t.map(e=>e.peek())},subscribe(e){let n=t.map(t=>t.subscribe(e));return()=>{for(let e of n)e()}}}},refetchStale(){for(let e of[...r.values()])d(e)&&U(a,e,e.lastConfig).catch(()=>{})},remove(e){let t=r.get(j(e));t&&H(a,t)},set:u,get size(){return r.size},[Symbol.dispose](){this.dispose()}}}function ee(e){try{return JSON.parse(e)}catch{return e}}async function Q(e,t,n,i,a){let o=i.method.toUpperCase(),s=x(e.baseUrl,t,i.params,i.query),c=g(i.extSignal,n.signal)??n.signal,l=y(i.timeout??1/0,c),{headers:f,...m}=p(o,e.mergeHeaders(i.headers,a),i.body,l,i.fetchInit??{}),h;try{h=await e.dispatch({headers:f,init:m,url:s})}catch(e){throw d(e,o,s,l??c)}if(!h.ok){let e=await h.text().catch(()=>``);throw r.fromResponse(h,e,o,s)}if(!h.body)throw new u(`Response has no body`);return h}function $(e){let{transport:n,...r}=e??{},i=!n,a=n??b(r);function o(e,n={}){if(a.disposed)throw new l(`StreamClient`);let{body:r,fetchInit:i,headers:o,method:s=r===void 0?`GET`:`POST`,onError:c,params:u,query:d,reconnect:f=!1,signal:p,timeout:m}=n;m!==void 0&&v(m);let h=new Map,g=new AbortController,_=a.track(g),y=!1,b=`connecting`,x=``,S=f===!0?{}:f===!1?{times:0}:f,C=S.times??(f?5:0),w=S.delay??E;function T(e,t){let n=h.get(e);if(!n?.size)return;let r=ee(t);for(let e of n)e(r)}async function D(){let t=(await Q(a,e,g,{body:r,extSignal:p,fetchInit:i,headers:o,method:s,params:u,query:d,timeout:m},{accept:`text/event-stream`,"cache-control":`no-cache`,...x?{"last-event-id":x}:{}})).body.getReader(),n=new TextDecoder,c=``,l=`message`,f=``,h=``;try{for(;;){let{done:e,value:r}=await t.read();if(e)break;c+=n.decode(r,{stream:!0}).replace(/\r\n/g,`
|
|
2
|
+
`).replace(/\r/g,`
|
|
3
|
+
`);let i;for(;(i=c.indexOf(`
|
|
4
|
+
`))!==-1;){let e=c.slice(0,i);if(c=c.slice(i+1),e===``)f!==``&&(h&&(x=h),T(l,f.replace(/\n$/,``))),l=`message`,f=``,h=``;else if(!e.startsWith(`:`)){let t=e.indexOf(`:`),n=t===-1?e:e.slice(0,t),r=t===-1?``:e.slice(t+1).replace(/^ /,``);if(n===`event`)l=r;else if(n===`data`)f+=(f?`
|
|
5
|
+
`:``)+r;else if(n===`id`&&!r.includes(`\0`))h=r;else if(n===`retry`){let e=parseInt(r,10);Number.isNaN(e)||(w=e)}}}}}finally{t.releaseLock()}}async function O(){let e=0;try{for(;!y&&!a.disposed&&!g.signal.aborted;){let n;b=`connecting`;try{b=`open`,await D()}catch(e){if(y||a.disposed||g.signal.aborted)break;n=e instanceof Error?e:Error(String(e))}if(y||a.disposed||g.signal.aborted)break;if(C===0){n&&c?.(n);break}if(e>=C){c?.(n??Error(`[courier] SSE reconnect budget exhausted`));break}b=`reconnecting`;let r=typeof w==`function`?w(e):w;e++,await(0,t.sleep)(r,g.signal).catch(()=>{})}}finally{b=`closed`,_()}}return O().catch(e=>{!y&&!a.disposed&&c?.(e instanceof Error?e:Error(String(e)))}),{get closed(){return y},dispose(){y=!0,g.abort(),h.clear()},on(e,t){if(y)return()=>{};let n=h.get(e);return n||(n=new Set,h.set(e,n)),n.add(t),()=>n.delete(t)},get status(){return b},[Symbol.dispose](){this.dispose()}}}async function*s(e,n={}){if(a.disposed)throw new l(`StreamClient`);let{body:r,fetchInit:i,headers:o,method:s=r===void 0?`GET`:`POST`,onError:c,params:d,parse:f=`text`,query:p,reconnect:m=!1,signal:h,timeout:g}=n;g!==void 0&&v(g);let _=m===!0?{}:m===!1?{times:0}:m,y=_.times??(m?5:0),b=_.delay??E,x=new AbortController,S=a.track(x),C=0,w=!1;try{for(;!a.disposed&&!x.signal.aborted;){let n,l=!1;try{let t=(await Q(a,e,x,{body:r,extSignal:h,fetchInit:i,headers:o,method:s,params:d,query:p,timeout:g})).body.getReader(),n=new TextDecoder;try{if(f===`ndjson`){let e=``;for(;;){let{done:r,value:i}=await t.read();if(r){let t=e.trim();if(t)try{yield JSON.parse(t)}catch{throw new u(`NDJSON: failed to parse line: ${t.slice(0,200)}`)}l=!0;break}e+=n.decode(i,{stream:!0});let a;for(;(a=e.indexOf(`
|
|
6
|
+
`))!==-1;){let t=e.slice(0,a).trim();if(e=e.slice(a+1),t)try{yield JSON.parse(t)}catch{throw new u(`NDJSON: failed to parse line: ${t.slice(0,200)}`)}}}}else for(;;){let{done:e,value:r}=await t.read();if(e){l=!0;break}yield n.decode(r,{stream:!0})}}finally{t.releaseLock()}}catch(e){if(a.disposed||x.signal.aborted)break;n=e instanceof Error?e:Error(String(e))}if(a.disposed||x.signal.aborted)break;if(y===0){if(n)if(c)c(n);else throw n;else w=l;break}if(C>=y){let e=n??Error(`[courier] readable() reconnect budget exhausted`);if(c)c(e);else if(n)throw n;break}if(l&&!n){w=!0;break}let m=typeof b==`function`?b(C):b;C++,await(0,t.sleep)(m,x.signal).catch(()=>{})}}finally{w||x.abort(),S()}}return{cancelAll(){a.cancelAll()},get disposalSignal(){return a.disposalSignal},dispose(){i&&a.dispose()},get disposed(){return a.disposed},getHeaders:a.getHeaders,headers:a.headers,readable:s,sse:o,[Symbol.dispose](){this.dispose()},use:a.use}}function te(e){let{mutationDefaults:t,query:n,...r}=e??{},i=b(r),a=w({transport:i}),o=$({transport:i}),s=(e,t)=>{let n=typeof e==`string`?e:e instanceof URL?e.toString():e.url,{signal:r,...a}=t??{},o=Object.fromEntries(new Headers({...i.getHeaders(),...t?.headers??{}}).entries());return i.dispatch({headers:o,init:{...a,signal:r},url:n})},c=Z({...n,fetch:s});return{api:a,cancelAll(){i.cancelAll(),c.cancelAll()},get disposalSignal(){return i.disposalSignal},dispose(){i.dispose(),c.dispose()},get disposed(){return i.disposed},headers:i.headers,mutation(e,n){let{invalidates:r,sets:i,...a}=n??{},o=async(e,t)=>{if(i){let n=i(e,t);for(let[e,t]of n)c.set(e,t)}if(r)for(let e of r)c.invalidate(e);await a.onSuccess?.(e,t)};return k(e,{...t,...a,onSuccess:o})},query:c,stream:o,[Symbol.dispose](){this.dispose()},use:i.use}}var ne=!globalThis.__COURIER_PROD__;function re(e){ne&&console.warn(`[@vielzeug/courier] ${e}`)}function ie(e,t){let n=[],r=typeof document<`u`,i=typeof window<`u`;if(!r&&!i&&re(`bindRefetch() called with no document/window in scope — no listeners attached`),r){let t=()=>{document.visibilityState===`visible`&&e.refetchStale()};document.addEventListener(`visibilitychange`,t),n.push(()=>document.removeEventListener(`visibilitychange`,t))}if(i){let t=()=>e.refetchStale();window.addEventListener(`online`,t),n.push(()=>window.removeEventListener(`online`,t))}let a=()=>{for(let e of n)e();n.length=0};return t?.signal?.addEventListener(`abort`,a,{once:!0}),a}function ae(e){return async(t,n)=>{let r=typeof e==`function`?await e():e;return n(t.withHeaders({authorization:`Bearer ${r}`}))}}function oe(e){let n=e?.header??`x-request-id`,r=e?.generate??t.uuid;return(e,t)=>t(e.withHeaders({[n]:r()}))}function se(e){let t=e?.logger??((e,t)=>{console.debug(e,t)});return async(e,n)=>{let r=performance.now(),i=(e.init.method??`GET`).toUpperCase();try{let a=await n(e),o=Math.round(performance.now()-r);return t(`${i} ${e.url} ${a.status} (${o}ms)`,{duration:o,method:i,status:a.status,url:e.url}),a}catch(n){let a=Math.round(performance.now()-r);throw t(`${i} ${e.url} ERR (${a}ms)`,{duration:a,method:i,status:0,url:e.url}),n}}}function ce(e,n){let{keys:r,onError:i,prefix:a=`courier:`,storage:o}=n,s=e.keys(),c=typeof r==`function`?s.filter(r):r,l=[];function u(e){return`${a}${(0,t.hash)(e)}`}function d(e,t){if(t.status!==`success`)return;let n={data:t.data,updatedAt:t.updatedAt};try{let t=o.setItem(u(e),JSON.stringify(n));t instanceof Promise&&t.catch(t=>i?.(t,e))}catch(t){i?.(t,e)}}for(let t of c){let n=e.getState(t);n&&d(t,n);let r=e.observe({fetch:!1,key:t}),i=r.subscribe(()=>d(t,r.peek()));l.push(i)}return()=>{for(let e of l)e();l.length=0}}async function le(e,n){let{keys:r,maxAge:i,onError:a,prefix:o=`courier:`,storage:s}=n,c=e.keys(),l=typeof r==`function`?c.filter(r):r;await Promise.all(l.map(async n=>{try{let r=await s.getItem(`${o}${(0,t.hash)(n)}`);if(!r)return;let c=JSON.parse(r);if(typeof c!=`object`||!c||!(`data`in c)||typeof c.updatedAt!=`number`){a?.(Error(`[courier] Malformed persisted entry`),n);return}let l=c;if(i!==void 0&&Date.now()-l.updatedAt>i)return;e.set(n,l.data,{updatedAt:l.updatedAt})}catch(e){a?.(e,n)}}))}function ue(e){return{peek:()=>e.peek(),subscribe:t=>e.subscribe(t)}}return e.CourierAbortError=o,e.CourierBatcherError=c,e.CourierDisposedError=l,e.CourierError=n,e.CourierHttpError=r,e.CourierNetworkError=i,e.CourierParseError=u,e.CourierSchemaValidationError=s,e.CourierTimeoutError=a,e.bindRefetch=ie,e.createApi=w,e.createBatcher=T,e.createCourier=te,e.createMutation=k,e.createQuery=Z,e.createStream=$,e.hydrateQueryCache=le,e.persistQueryCache=ce,e.toSyncStore=ue,e.withBearerAuth=ae,e.withLogging=se,e.withRequestId=oe,e})({},Arsenal);
|
|
7
|
+
//# sourceMappingURL=courier.iife.js.map
|