openapi-typesafe-react-query 1.0.0-rc.5 → 1.0.0-rc.7

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/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  This package is a fork of `openapi-react-query`. The entries above `0.5.4` are releases of openapi-typesafe-react-query; `0.5.4` and the entries below it are the upstream history up to the fork point (upstream commit `d46a319a`), with `openapi-react-query` versions.
4
4
 
5
+ ## 1.0.0-rc.7
6
+
7
+ ### Patch Changes
8
+
9
+ - [#97](https://github.com/openapi-typesafe/openapi-typesafe/pull/97) [`d2bac1c`](https://github.com/openapi-typesafe/openapi-typesafe/commit/d2bac1c48c46b8cc39f516645c2fef1cfe9473db) Thanks [@fedorello](https://github.com/fedorello)! - An init whose `params` or `headers` send nothing now has the query key of no init:
10
+ `{ params: {} }`, `{ params: { query: { cursor: undefined } } }`, `{ params: { query: filters } }`
11
+ with `filters` undefined, and `{ headers: { "X-Tenant": undefined } }`. Each had its own key, so
12
+ `setQueryData`, `getQueryData` and server prefetches of one were not seen by the others, and each
13
+ fetched again. `null`, `[]` and `{}` parameter values still count, and so does an empty JSON body.
14
+
15
+ - [#97](https://github.com/openapi-typesafe/openapi-typesafe/pull/97) [`d2bac1c`](https://github.com/openapi-typesafe/openapi-typesafe/commit/d2bac1c48c46b8cc39f516645c2fef1cfe9473db) Thanks [@fedorello](https://github.com/fedorello)! - A `File`, `Blob`, bytes, `FormData` or `URLSearchParams` value inside an object or array body,
16
+ such as a multipart body written as `{ image: file }`, is now part of the query key by its
17
+ content (a file by its type, size and name). Every file had the same key before, so a query for
18
+ a second file showed the cached result of the first. The key names the kinds of such values in
19
+ `bodyType`, by member name or index (`{ image: "Blob" }`).
20
+ - Updated dependencies [[`171fa71`](https://github.com/openapi-typesafe/openapi-typesafe/commit/171fa71311107e4e26a9ae7a62b431662fb13de5), [`171fa71`](https://github.com/openapi-typesafe/openapi-typesafe/commit/171fa71311107e4e26a9ae7a62b431662fb13de5), [`171fa71`](https://github.com/openapi-typesafe/openapi-typesafe/commit/171fa71311107e4e26a9ae7a62b431662fb13de5)]:
21
+ - openapi-typesafe-fetch@1.0.0-rc.7
22
+
23
+ ## 1.0.0-rc.6
24
+
25
+ ### Patch Changes
26
+
27
+ - [#89](https://github.com/openapi-typesafe/openapi-typesafe/pull/89) [`ebb5b46`](https://github.com/openapi-typesafe/openapi-typesafe/commit/ebb5b46684bc20b78727d295924189c02d2287ce) Thanks [@fedorello](https://github.com/fedorello)! - Keep one query key for a `FormData` or `File` body built while the component renders (the file's date in the key made a new request on every render), name a raw body's kind in `bodyType` so it never shares a key with a JSON body of the same shape, and leave out init fields set to `undefined`, so `{ headers: undefined }` has the same key as no init.
28
+ - Updated dependencies [[`dfb0fe3`](https://github.com/openapi-typesafe/openapi-typesafe/commit/dfb0fe3c61a75d2b8ca512577f4b699049171a64)]:
29
+ - openapi-typesafe-fetch@1.0.0-rc.6
30
+
5
31
  ## 1.0.0-rc.5
6
32
 
7
33
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # openapi-typesafe-react-query
2
2
 
3
- openapi-typesafe-react-query is a small, type-safe wrapper (about 2 kB minified, 1 kB gzipped) around [@tanstack/react-query](https://tanstack.com/query/latest/docs/framework/react/overview) to work with OpenAPI schema.
3
+ openapi-typesafe-react-query is a small, type-safe wrapper (about 3.8 kB minified, 1.7 kB gzipped) around [@tanstack/react-query](https://tanstack.com/query/latest/docs/framework/react/overview) to work with OpenAPI schema.
4
4
 
5
5
  It works by using [openapi-typesafe-fetch](../openapi-typesafe-fetch) and [openapi-typesafe](../openapi-typesafe) so URLs, parameters, request bodies and responses are checked against your schema, with no manual types,
6
6
  no `any` and no `as` assertions.
package/dist/index.cjs CHANGED
@@ -10,21 +10,16 @@ function isClass(value, name) {
10
10
  const type = globalThis[name];
11
11
  return typeof type === "function" && value instanceof type || Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name;
12
12
  }
13
- function plainHeaders(headers) {
14
- if (!(Symbol.iterator in headers)) {
15
- return headers;
16
- }
17
- const record = {};
18
- for (const pair of headers) {
19
- const [name, value] = Array.from(pair);
20
- const key = String(name).toLowerCase();
21
- record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);
13
+ function isPlainRecord(value) {
14
+ if (typeof value !== "object" || value === null) {
15
+ return false;
22
16
  }
23
- return record;
17
+ const prototype = Object.getPrototypeOf(value);
18
+ return prototype === Object.prototype || prototype === null;
24
19
  }
25
20
  function blobKey(blob) {
26
- const { name, lastModified } = blob;
27
- return { type: blob.type, size: blob.size, name, lastModified };
21
+ const { name } = blob;
22
+ return { type: blob.type, size: blob.size, name };
28
23
  }
29
24
  function formDataKey(form) {
30
25
  if (typeof form.entries !== "function") {
@@ -35,43 +30,88 @@ function formDataKey(form) {
35
30
  typeof value === "string" ? value : blobKey(value)
36
31
  ]);
37
32
  }
38
- function bodyBytes(body) {
39
- if (ArrayBuffer.isView(body)) {
40
- return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
33
+ function valueBytes(value) {
34
+ if (ArrayBuffer.isView(value)) {
35
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
36
+ }
37
+ return isClass(value, "ArrayBuffer") ? new Uint8Array(value) : null;
38
+ }
39
+ function rawValueKey(value) {
40
+ if (isClass(value, "URLSearchParams")) {
41
+ return { body: String(value), bodyType: "URLSearchParams" };
42
+ }
43
+ if (isClass(value, "FormData")) {
44
+ return { body: formDataKey(value), bodyType: "FormData" };
45
+ }
46
+ if (isClass(value, "Blob") || isClass(value, "File")) {
47
+ return { body: blobKey(value), bodyType: "Blob" };
41
48
  }
42
- return isClass(body, "ArrayBuffer") ? new Uint8Array(body) : null;
49
+ const bytes = valueBytes(value);
50
+ return bytes === null ? void 0 : { body: Array.from(bytes), bodyType: "bytes" };
51
+ }
52
+ function membersKey(members) {
53
+ const body = Array.isArray(members) ? [] : {};
54
+ const kinds = {};
55
+ for (const [name, value] of Object.entries(members)) {
56
+ const member = bodyKey(value);
57
+ body[name] = member.body;
58
+ if (member.bodyType !== void 0) {
59
+ kinds[name] = member.bodyType;
60
+ }
61
+ }
62
+ return Object.keys(kinds).length === 0 ? { body } : { body, bodyType: kinds };
43
63
  }
44
64
  function bodyKey(body) {
45
- if (typeof body !== "object" || body === null) {
46
- return body;
65
+ if (Array.isArray(body) || isPlainRecord(body)) {
66
+ return membersKey(body);
47
67
  }
48
- if (isClass(body, "URLSearchParams")) {
49
- return { URLSearchParams: String(body) };
68
+ const raw = typeof body === "object" && body !== null ? rawValueKey(body) : void 0;
69
+ return raw ?? { body };
70
+ }
71
+
72
+ function plainHeaders(headers) {
73
+ if (!(Symbol.iterator in headers)) {
74
+ return headers;
50
75
  }
51
- if (isClass(body, "FormData")) {
52
- return { FormData: formDataKey(body) };
76
+ const record = {};
77
+ for (const pair of headers) {
78
+ const [name, value] = Array.from(pair);
79
+ const key = String(name).toLowerCase();
80
+ record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);
53
81
  }
54
- if (isClass(body, "Blob") || isClass(body, "File")) {
55
- return { Blob: blobKey(body) };
82
+ return record;
83
+ }
84
+ function definedMembers(record) {
85
+ const members = Object.entries(record).filter(([, value]) => value !== void 0);
86
+ return members.length === 0 ? void 0 : Object.fromEntries(members);
87
+ }
88
+ function paramsKey(params) {
89
+ if (!isPlainRecord(params)) {
90
+ return params;
56
91
  }
57
- const bytes = bodyBytes(body);
58
- return bytes === null ? body : { bytes: Array.from(bytes) };
92
+ const records = Object.entries(params).map(([location, record]) => [
93
+ location,
94
+ isPlainRecord(record) ? definedMembers(record) : record
95
+ ]);
96
+ return definedMembers(Object.fromEntries(records));
97
+ }
98
+ function headersKey(headers) {
99
+ return typeof headers === "object" && headers !== null ? definedMembers(plainHeaders(headers)) : headers;
59
100
  }
60
101
  function queryKeyInit(init, client) {
61
102
  const { signal: _signal, ...rest } = init ?? {};
62
- const keyInit = { ...rest };
63
- if (typeof rest.headers === "object" && rest.headers !== null) {
64
- keyInit.headers = plainHeaders(rest.headers);
65
- }
66
- if ("body" in rest) {
67
- keyInit.body = bodyKey(rest.body);
68
- }
103
+ const keyInit = {
104
+ ...rest,
105
+ params: paramsKey(rest.params),
106
+ headers: headersKey(rest.headers),
107
+ ...rest.body === void 0 ? {} : bodyKey(rest.body)
108
+ };
69
109
  if (client.keyScope !== void 0) {
70
110
  keyInit.keyScope = client.keyScope;
71
111
  } else if (!rest.baseUrl && client.baseUrl) {
72
112
  keyInit.baseUrl = client.baseUrl;
73
113
  }
74
- return Object.keys(keyInit).length === 0 ? void 0 : keyInit;
114
+ return definedMembers(keyInit);
75
115
  }
76
116
 
77
117
  const ABORT_EVENT = "abort";
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/query-key.ts","../src/query-signal.ts","../src/index.ts"],"sourcesContent":["/**\n * The request part of a query key (ADR-046). TanStack Query hashes a key as JSON: a `Headers`\n * object or a list of header pairs hashed as `{}` or by its order, and so did a FormData, a Blob,\n * an ArrayBuffer or a URLSearchParams body. Two requests that differed in them shared one cache\n * entry, and the `queryFn` of that entry sent the request of the first. Two clients with\n * different base URLs shared entries too. The key's init holds the headers and such a body as\n * plain values, and the base URL the request goes to or the client's key scope, so the key names\n * what was fetched.\n */\n\n/** Headers as a plain object, which TanStack Query hashes by its names and values. */\ntype HeadersRecord = Readonly<Record<string, unknown>>;\n\n/** What the key takes from the fetch client and the options of `createClient`. */\nexport interface KeyClient {\n /** The fetch client's base URL, `\"\"` without one. */\n readonly baseUrl: string;\n /** The name of the API in every key, in place of the base URL. */\n readonly keyScope?: string | undefined;\n}\n\n/** `[object Name]`: the type tag is between these indexes of `Object.prototype.toString`. */\nconst TYPE_TAG_START = \"[object \".length;\nconst TYPE_TAG_END = -1;\n\n/**\n * Whether a value is of the class `name`: an instance of this realm's global class of that name\n * (React Native's classes have no type tag), or a value with its type tag (a class of another\n * realm or of the `undici` package), as the fetch client tells bodies (ADR-030).\n */\nfunction isClass(value: object, name: string): boolean {\n const type = (globalThis as Record<string, unknown>)[name];\n return (\n (typeof type === \"function\" && value instanceof type) ||\n Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name\n );\n}\n\n/**\n * The headers of an init as a plain object. A `Headers` object and a list of pairs, which are both\n * iterable, become the names and values the request sends: names in lowercase, a repeated one\n * joined with `, `, as `Headers` writes them. They are read without `Headers`, which threw for an\n * invalid name or value while the component rendered; the request reports it as a query error. A\n * plain object stays as it is, since its `null` and array values mean more than a string.\n */\nfunction plainHeaders(headers: object): HeadersRecord {\n if (!(Symbol.iterator in headers)) {\n return headers as HeadersRecord;\n }\n const record: Record<string, string> = {};\n for (const pair of headers as Iterable<unknown>) {\n const [name, value] = Array.from(pair as ArrayLike<unknown>);\n const key = String(name).toLowerCase();\n record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);\n }\n return record;\n}\n\n/**\n * A Blob or a File in a key: its type, size, and the name and date of a File. Its bytes cannot be\n * read while the component renders, so two Blobs of the same type and size share an entry.\n */\nfunction blobKey(blob: Blob): object {\n const { name, lastModified } = blob as Partial<File>;\n return { type: blob.type, size: blob.size, name, lastModified };\n}\n\n/** The fields of a FormData in a key, in order, with a file as `blobKey`. */\nfunction formDataKey(form: FormData): unknown[] {\n // React Native's FormData has no `entries`, so its fields cannot be read.\n if (typeof form.entries !== \"function\") {\n return [];\n }\n return Array.from(form.entries(), ([name, value]) => [\n name,\n typeof value === \"string\" ? value : blobKey(value),\n ]);\n}\n\n/** The bytes of an ArrayBuffer or a typed array, or null for another value. */\nfunction bodyBytes(body: object): Uint8Array | null {\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n }\n return isClass(body, \"ArrayBuffer\") ? new Uint8Array(body as ArrayBuffer) : null;\n}\n\n/**\n * A request body as a value TanStack Query hashes by its content. A URLSearchParams is its text,\n * a FormData its fields, a Blob `blobKey` and bytes their numbers, each under its kind, so it\n * differs from a JSON body with the same content. Other values stay as they are.\n */\nfunction bodyKey(body: unknown): unknown {\n if (typeof body !== \"object\" || body === null) {\n return body;\n }\n if (isClass(body, \"URLSearchParams\")) {\n return { URLSearchParams: String(body) };\n }\n if (isClass(body, \"FormData\")) {\n return { FormData: formDataKey(body as FormData) };\n }\n if (isClass(body, \"Blob\") || isClass(body, \"File\")) {\n return { Blob: blobKey(body as Blob) };\n }\n const bytes = bodyBytes(body);\n return bytes === null ? body : { bytes: Array.from(bytes) };\n}\n\n/**\n * The init of a query key: the request init with its headers and body as plain values, and the\n * client's key scope, or its base URL when the init has none. The `signal` is left out: TanStack\n * Query gives each request its own. Undefined when nothing is left, so a call without an init and\n * one with an empty init have the key `[method, path]`.\n */\nexport function queryKeyInit(init: unknown, client: KeyClient): object | undefined {\n const { signal: _signal, ...rest } = (init ?? {}) as {\n signal?: unknown;\n headers?: unknown;\n baseUrl?: unknown;\n body?: unknown;\n };\n const keyInit: Record<string, unknown> = { ...rest };\n if (typeof rest.headers === \"object\" && rest.headers !== null) {\n keyInit.headers = plainHeaders(rest.headers);\n }\n if (\"body\" in rest) {\n keyInit.body = bodyKey(rest.body);\n }\n if (client.keyScope !== undefined) {\n keyInit.keyScope = client.keyScope;\n } else if (!rest.baseUrl && client.baseUrl) {\n keyInit.baseUrl = client.baseUrl;\n }\n return Object.keys(keyInit).length === 0 ? undefined : keyInit;\n}\n","/**\n * The signal of a query's request. TanStack Query gives every request a signal, which it aborts\n * when the query is cancelled or no longer used; the init of the call may bring its own. The hooks\n * sent one of them: `useQuery` the call's, so a cancelled query kept its request, and\n * `useInfiniteQuery` TanStack's, so the call's signal did nothing. The request now stops when\n * either is aborted.\n */\n\n/** The init to send, and how to stop listening to the signals once the request has settled. */\nexport interface QueryRequest {\n readonly init: Record<string, unknown>;\n readonly release: () => void;\n}\n\nconst ABORT_EVENT = \"abort\";\n\nfunction withoutRelease(init: Record<string, unknown>): QueryRequest {\n return { init, release: () => undefined };\n}\n\n/** The init with a signal that aborts when the init's own signal or the query's does. */\nexport function withQuerySignal(init: unknown, querySignal: AbortSignal): QueryRequest {\n const { signal: ownSignal, ...rest } = (init ?? {}) as { signal?: AbortSignal | null };\n if (!ownSignal) {\n return withoutRelease({ ...rest, signal: querySignal });\n }\n const controller = new AbortController();\n const sources = [ownSignal, querySignal];\n const aborted = sources.find((source) => source.aborted);\n if (aborted !== undefined) {\n controller.abort(aborted.reason);\n return withoutRelease({ ...rest, signal: controller.signal });\n }\n const listeners = sources.map((source) => {\n const listener = () => controller.abort(source.reason);\n source.addEventListener(ABORT_EVENT, listener, { once: true });\n return () => source.removeEventListener(ABORT_EVENT, listener);\n });\n return {\n init: { ...rest, signal: controller.signal },\n release: () => {\n for (const remove of listeners) {\n remove();\n }\n },\n };\n}\n","import {\n type DataTag,\n type DefaultError,\n type DefinedUseQueryResult,\n type InfiniteData,\n type QueryClient,\n type QueryFunctionContext,\n type SkipToken,\n type UseInfiniteQueryOptions,\n type UseInfiniteQueryResult,\n type UseMutationOptions,\n type UseMutationResult,\n type UseQueryOptions,\n type UseQueryResult,\n type UseSuspenseQueryOptions,\n type UseSuspenseQueryResult,\n useInfiniteQuery,\n useMutation,\n useQuery,\n useSuspenseQuery,\n} from \"@tanstack/react-query\";\nimport type {\n ClientMethod,\n DefaultParamsOption,\n Client as FetchClient,\n FetchResponse,\n MaybeOptionalInit,\n PathOperation,\n} from \"openapi-typesafe-fetch\";\n// The helper types come from the client, which declares them: types inferred from the hooks then\n// print the client's `helpers` entry, of a peer every user has, and not `openapi-typesafe-helpers`,\n// which Yarn PnP does not let a library reach (ADR-034).\nimport type {\n HttpMethod,\n MediaType,\n PathsWithMethod,\n RequiredKeysOf,\n} from \"openapi-typesafe-fetch/helpers\";\nimport { queryKeyInit } from \"./query-key.js\";\nimport { withQuerySignal } from \"./query-signal.js\";\n\n// Helper type to dynamically infer the type from the `select` property\ntype InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;\n\n/**\n * Query data of a response type: a success without a body is `undefined` in the fetch client and\n * `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).\n */\ntype QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;\n\n/**\n * What the hooks throw when a request fails and the response has no error body: a non-OK status\n * with an empty body, a JSON `null` body, or one whose operation declares no content for it. The\n * fetch client gives `error: undefined` (or `null`) then; throwing that left `error` empty in\n * TanStack Query while its type said there was an error body. Tell it apart with\n * `isResponseError(error)`: `error instanceof Error` also matches a network or parse error. The\n * message names the status, not the URL, which can carry secrets.\n */\nexport interface ResponseError extends Error {\n readonly name: \"ResponseError\";\n /** The response that failed. */\n readonly response: Response;\n /** Its HTTP status, as `response.status`. */\n readonly status: number;\n}\n\n/**\n * The error of a hook: the error body of a failed response, a `ResponseError` when it has none, or\n * what the request threw before there was a response to read: a network error (`TypeError`), an\n * abort, a body that is not JSON (`SyntaxError`) or a middleware error. TanStack Query types that\n * last part as `DefaultError` (`Error` unless `Register` says otherwise; a registered `unknown`\n * makes the whole type `unknown`, as for TanStack's own hooks). `undefined` and `null` are left\n * out: a failed response without an error body throws a `ResponseError`.\n */\nexport type QueryError<ErrorBody> =\n | Exclude<ErrorBody, undefined | null>\n | ResponseError\n | DefaultError;\n\n/**\n * An object whose `queryKey` is tagged with the query's data and error types: the type that\n * TanStack Query 5.102 exports as `QueryKeyWithDataTag`, for the whole peer range. A named object\n * type, so the declarations of an exported `queryOptions` result print it by name. Spelled out,\n * the tag prints TanStack's `dataTagSymbol` keys, which a declaration file cannot import, and\n * the library's users get TS2304, or `any` cached data with `skipLibCheck`.\n */\nexport type QueryKeyWithDataTag<Key, Data, Error> = {\n queryKey: DataTag<Key, Data, Error>;\n};\n\ntype InitWithUnknowns<Init> = Init & { [key: string]: unknown };\n\n/**\n * The arguments after the path: the init, required when the operation requires a parameter or a\n * body, then `Rest`. The condition is openapi-react-query's, as `InitParam` of the fetch client\n * is openapi-fetch's (ADR-030, decision 2): TypeScript relates two conditional types only when\n * their `extends` types are the same, so a hook type copied from openapi-react-query takes these\n * hooks. For a union of inits, `MaybeOptionalInit` leaves out `undefined` when one is required,\n * so `Parameters<typeof $api.queryOptions>` still requires it then (upstream #2178).\n */\ntype InitArguments<Init, Rest extends unknown[]> =\n RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, ...Rest]\n : [InitWithUnknowns<Init>, ...Rest];\n\n/**\n * The key of a query: the method, the path and the request. Its init is the init of the call with\n * the headers and the body as plain values, and the client's `keyScope`, or its `baseUrl` when the\n * init has none, so two requests never share a key; it is left out when nothing is left. Read a\n * query's key from `queryOptions(...).queryKey` rather than writing it out.\n */\nexport type QueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init = MaybeOptionalInit<Paths[Path], Method>,\n> = Init extends undefined ? readonly [Method, Path] : readonly [Method, Path, Init];\n\n/**\n * The last element of an infinite query's key. `useQuery` and `useInfiniteQuery` cache different\n * data (`TData` and `InfiniteData<TData>`), so the same request must not share one key (upstream\n * #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported: it is not\n * needed outside the package, and a named export is public API; `InfiniteQueryKey` types the key.\n */\nconst INFINITE_QUERY_KEY_MARKER = \"infinite\";\n\nexport type InfiniteQueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];\n\n/**\n * Whether the options give an `initialData` that is never `undefined`: a value, or a function that\n * never returns `undefined`. Then `data` is never `undefined` either, as for TanStack Query's own\n * `useQuery` with `DefinedInitialDataOptions`.\n */\ntype HasDefinedInitialData<Options> = Options extends { initialData: infer Initial }\n ? Initial extends (...args: never) => infer Returned\n ? undefined extends Returned\n ? false\n : true\n : undefined extends Initial\n ? false\n : true\n : false;\n\n/** The result of `useQuery`: its `data` is defined when the options give defined initial data. */\ntype QueryResult<Data, Error, Options> =\n HasDefinedInitialData<Options> extends true\n ? DefinedUseQueryResult<Data, Error>\n : UseQueryResult<Data, Error>;\n\n/**\n * A defined `initialData` of the options, in the type `queryOptions` returns, so TanStack Query's\n * `useQuery` takes the result as options with defined initial data. It is typed as the query data,\n * as TanStack's `DefinedInitialDataOptions` types it: the type of a literal such as `[{ id: 1 }]`\n * lacks the optional properties of the data, and TanStack's overload rejected it.\n */\ntype InitialDataOf<Options, Data> =\n HasDefinedInitialData<Options> extends true ? { initialData: Data | (() => Data) } : unknown;\n\nexport type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n path: Path,\n ...[init, options]: InitArguments<Init, [Options?]>\n) => NoInfer<\n Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > &\n QueryKeyWithDataTag<\n QueryKey<Paths, Method, Path>,\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>\n > &\n InitialDataOf<Options, QueryData<Response[\"data\"]>> & {\n queryFn: Exclude<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >[\"queryFn\"],\n SkipToken | undefined\n >;\n }\n>;\n\nexport type UseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => QueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>,\n Options\n>;\n\n/**\n * The type of the page params: the initial one and the ones `getNextPageParam` and\n * `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a\n * return type is untyped, so code that compiled still compiles (roadmap §3): TypeScript cannot\n * infer the return type of a callback that computes it from an unannotated `lastPageParam`,\n * whose type depends on that return type, and gives `never` or `unknown`.\n */\ntype PageParam<Initial, Next, Previous> =\n IsUntyped<Next> extends true\n ? unknown\n : [Previous] extends [NoPreviousPageParam]\n ? NullishToUnknown<Initial | NonNullable<Next>>\n : IsUntyped<Previous> extends true\n ? unknown\n : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;\n\n/** The `Previous` type parameter when the options have no `getPreviousPageParam`. */\ndeclare const NO_PREVIOUS_PAGE_PARAM: unique symbol;\ntype NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;\n\ntype IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;\n\n/** Only `undefined` or `null` names no type: a cursor API's `initialPageParam: undefined`. */\ntype NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;\n\n/** Read only for the return type; `never` arguments add no inference for TanStack's page param. */\ntype PageParamFunction<Result> = (...args: never) => Result;\n\n/**\n * Inference sites of the page param types. Intersected before `Options`, so TanStack's own\n * inference in the implementation reads the full signatures of `Options`.\n */\ninterface PageParamSources<Initial, Next, Previous> {\n initialPageParam: Initial;\n getNextPageParam: PageParamFunction<Next>;\n getPreviousPageParam?: PageParamFunction<Previous>;\n}\n\n/**\n * `placeholderData` of `useInfiniteQuery`, with an `unknown` page param as before: TypeScript types\n * a `(previousData) => previousData` callback while it still infers the page param, so it got\n * `unknown` there and failed against the typed page param.\n */\ntype InfinitePlaceholderData<\n Data,\n Error,\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = UseInfiniteQueryOptions<\n Data,\n Error,\n InfiniteData<Data, unknown>,\n InfiniteQueryKey<Paths, Method, Path>,\n unknown\n>[\"placeholderData\"];\n\nexport type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseInfiniteQueryOptions<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n InfiniteQueryKey<Paths, Method, Path>,\n PageParam<Initial, Next, Previous>\n >,\n \"queryKey\" | \"queryFn\" | \"placeholderData\"\n > & {\n placeholderData?: InfinitePlaceholderData<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n Paths,\n Method,\n Path\n >;\n pageParamName?: string;\n },\n Initial = unknown,\n Next = never,\n Previous = NoPreviousPageParam,\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n>(\n method: Method,\n url: Path,\n init: InitWithUnknowns<Init>,\n options: PageParamSources<Initial, Next, Previous> & Options,\n queryClient?: QueryClient,\n) => UseInfiniteQueryResult<\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseSuspenseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => UseSuspenseQueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseMutationMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>;\n\nexport interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {\n queryOptions: QueryOptionsFunction<Paths, Media>;\n useQuery: UseQueryMethod<Paths, Media>;\n useSuspenseQuery: UseSuspenseQueryMethod<Paths, Media>;\n useInfiniteQuery: UseInfiniteQueryMethod<Paths, Media>;\n useMutation: UseMutationMethod<Paths, Media>;\n}\n\nexport type MethodResponse<\n // biome-ignore lint/suspicious/noExplicitAny: matches a client of any paths, as upstream's\n CreatedClient extends OpenapiQueryClient<any, any>,\n Method extends HttpMethod,\n Path extends CreatedClient extends OpenapiQueryClient<infer Paths, infer _Media>\n ? PathsWithMethod<Paths, Method>\n : never,\n Options = object,\n> =\n CreatedClient extends OpenapiQueryClient<\n // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces\n infer Paths extends { [key: string]: any },\n infer Media extends MediaType\n >\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/** The `name` of every `ResponseError`. */\nconst RESPONSE_ERROR_NAME = \"ResponseError\";\n\n/** The `ResponseError` of a failed response without an error body. */\nclass ResponseWithoutErrorBody extends Error implements ResponseError {\n override readonly name = RESPONSE_ERROR_NAME;\n readonly response: Response;\n readonly status: number;\n\n constructor(response: Response) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n super(`Request failed with status ${response.status}${statusText} and no error body`);\n this.response = response;\n this.status = response.status;\n }\n}\n\n/**\n * Whether `error` is the `ResponseError` of a failed response without an error body. It narrows a\n * hook's `error`, where `error instanceof Error` also matches network and parse errors. It checks\n * the `name`, not the class, so a `ResponseError` of another copy of this package (its CommonJS and\n * ES module builds loaded side by side) is one too. An error body from JSON is never an `Error`.\n */\nexport function isResponseError(error: unknown): error is ResponseError {\n return error instanceof Error && error.name === RESPONSE_ERROR_NAME;\n}\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response\n * with an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as\n * `0`. Without an error body a `ResponseError` is thrown, so the hooks' `error` is never\n * `undefined` (ADR-013, decision 3). A JSON `null` body is no error body either: thrown as is, it\n * left `error` `null` while the query's status was `\"error\"`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined && result.error !== null) {\n throw result.error;\n }\n if (!result.response.ok) {\n throw new ResponseWithoutErrorBody(result.response);\n }\n}\n\n/** The query parameter that carries the page param unless `pageParamName` names another. */\nconst DEFAULT_PAGE_PARAM_NAME = \"cursor\";\n\ninterface PageRequest {\n readonly pageParamName: string;\n readonly pageParam: unknown;\n}\n\n/**\n * The request init of one page. An `undefined` page param (the first page with\n * `initialPageParam: undefined`) is left out instead of being sent as `0` (upstream #2715, #2340,\n * ADR-022), so a cursor API gets no cursor on the first page.\n */\nfunction pageInit(init: unknown, { pageParamName, pageParam }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n/** Options of `createClient`. */\nexport interface CreateClientOptions {\n /**\n * The name of the API in every query key, in place of the fetch client's `baseUrl`. Give the\n * same name where the server and the browser reach one API by different URLs, so the browser\n * reads the data the server rendered with; give different names to clients of one base URL that\n * fetch different data, such as one per tenant header.\n */\n keyScope?: string;\n}\n\n/**\n * Hooks and query options for a fetch client. A `QueryClient` other than the one from the React\n * context is passed to each hook as its last argument; `createClient` does not take one.\n */\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: inherited, kept until 1.1 (ADR-036)\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n { keyScope }: CreateClientOptions = {},\n): OpenapiQueryClient<Paths, Media> {\n const keyClient = { baseUrl: client.baseUrl, keyScope };\n /**\n * Send one request of a query: the call's own init, with a signal that TanStack Query can abort.\n * The key only names the cache entry, as for `useInfiniteQuery`: a function in the init (a\n * `fetch`, a `middleware`) cannot be part of a key, so the request is read from the call.\n */\n const fetchPage = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>(\n method: Method,\n path: Path,\n init: unknown,\n signal: AbortSignal,\n ) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const request = withQuerySignal(init, signal);\n try {\n // The init is `unknown` here. An `any` init lets the call infer the generic response type\n // that `queryOptions` declares; a typed init makes TypeScript compare two unresolved\n // conditional types, which it cannot do.\n // biome-ignore lint/suspicious/noExplicitAny: see the comment above\n const result = await fn(path, request.init as any);\n throwIfFailed(result);\n return result.data;\n } finally {\n request.release();\n }\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => {\n const keyInit = queryKeyInit(init, keyClient);\n return {\n queryKey: (keyInit === undefined\n ? ([method, path] as const)\n : ([method, path, keyInit] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the data type\n any,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the error type\n any\n >,\n // TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for\n // every success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD\n // request (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.\n queryFn: async ({ signal }: QueryFunctionContext) =>\n (await fetchPage(method, path, init, signal)) ?? null,\n // Without options, `Options` is its constraint, which has no `initialData` to keep.\n ...(options as typeof options & {}),\n // The declared type types a defined `initialData` as the query data, a conditional type of\n // the generic options that TypeScript cannot relate to the object; it is the same object.\n } as never;\n };\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n // TanStack Query's `useQuery` returns `DefinedUseQueryResult` for options with defined\n // `initialData`; while `Options` is generic it cannot pick that overload, and the declared\n // `QueryResult` gives the caller the same answer. Both are the same object at runtime.\n useQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ) as never,\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ),\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n useInfiniteQuery: (method, path, init, options, queryClient) => {\n const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;\n const { queryKey } = queryOptions(method, path, init);\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // An empty page stays `undefined`, as in upstream: TanStack Query rejects only\n // `undefined` query data, and the infinite query data is the `{ pages }` object.\n queryFn: ({ pageParam, signal }) =>\n fetchPage(method, path, pageInit(init, { pageParamName, pageParam }), signal),\n ...restOptions,\n // Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack\n // passes the previous data of this query, with its own page params, and takes it back.\n // biome-ignore lint/suspicious/noExplicitAny: TanStack's type carries its own page params\n placeholderData: placeholderData as any,\n },\n queryClient,\n );\n },\n useMutation: (method, path, options, queryClient) =>\n useMutation(\n {\n mutationKey: [method, path],\n mutationFn: async (init) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const result = await fn(path, init as InitWithUnknowns<typeof init>);\n throwIfFailed(result);\n // TanStack Query accepts `undefined` mutation data, so a success without a body stays\n // `undefined`, as in upstream; only query data needs `null` (upstream #2234). The cast\n // only bridges the generic types: `Response[\"data\"]` still has `undefined` for an\n // operation with a response without a body.\n const { data } = result;\n return data as Exclude<typeof data, undefined>;\n },\n ...options,\n },\n queryClient,\n ),\n };\n}\n"],"names":["useQuery","useSuspenseQuery","useInfiniteQuery","useMutation"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/body-key.ts","../src/query-key.ts","../src/query-signal.ts","../src/index.ts"],"sourcesContent":["/**\n * The body part of a query key (ADR-046). TanStack Query hashes a key as JSON, which writes a\n * FormData, a Blob, an ArrayBuffer or a URLSearchParams as `{}`, as the whole body or as a field\n * of an object body (a multipart body written as `{ image: file }`). The key holds each such value\n * by its content and names its kind beside the body, so the key names what is sent.\n */\n\n/** `[object Name]`: the type tag is between these indexes of `Object.prototype.toString`. */\nconst TYPE_TAG_START = \"[object \".length;\nconst TYPE_TAG_END = -1;\n\n/** The kind of a value that JSON cannot hold. */\ntype RawKind = \"URLSearchParams\" | \"FormData\" | \"Blob\" | \"bytes\";\n\n/**\n * The kinds of the values JSON cannot hold in a body: the kind of a body that is one, or, for an\n * object or an array body, the kinds of its members by their names or indexes, only where there\n * are some.\n */\ntype BodyKinds = RawKind | { readonly [member: string]: BodyKinds };\n\n/** A body as a value TanStack Query hashes, and the kinds of the values JSON cannot hold in it. */\nexport interface BodyKey {\n readonly body: unknown;\n readonly bodyType?: BodyKinds;\n}\n\n/**\n * Whether a value is of the class `name`: an instance of this realm's global class of that name\n * (React Native's classes have no type tag), or a value with its type tag (a class of another\n * realm or of the `undici` package), as the fetch client tells bodies (ADR-030).\n */\nfunction isClass(value: object, name: string): boolean {\n const type = (globalThis as Record<string, unknown>)[name];\n return (\n (typeof type === \"function\" && value instanceof type) ||\n Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name\n );\n}\n\n/**\n * Whether a value is an object literal, whose members JSON writes. A Date or another class has\n * its own JSON form, which the key keeps.\n */\nexport function isPlainRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const prototype: unknown = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * A Blob or a File in a key: its type, size, and the name of a File. Its bytes cannot be read while\n * the component renders, so two Blobs of the same type and size share an entry. The date of a File\n * is left out: `FormData.append` and `new File` set it to the current time, so a body built while\n * rendering got a new key, and a new request, on every render.\n */\nfunction blobKey(blob: Blob): object {\n const { name } = blob as Partial<File>;\n return { type: blob.type, size: blob.size, name };\n}\n\n/** The fields of a FormData in a key, in order, with a file as `blobKey`. */\nfunction formDataKey(form: FormData): unknown[] {\n // React Native's FormData has no `entries`, so its fields cannot be read.\n if (typeof form.entries !== \"function\") {\n return [];\n }\n return Array.from(form.entries(), ([name, value]) => [\n name,\n typeof value === \"string\" ? value : blobKey(value),\n ]);\n}\n\n/** The bytes of an ArrayBuffer or a typed array, or null for another value. */\nfunction valueBytes(value: object): Uint8Array | null {\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n return isClass(value, \"ArrayBuffer\") ? new Uint8Array(value as ArrayBuffer) : null;\n}\n\n/**\n * A value that JSON cannot hold, by its content: a URLSearchParams as its text, a FormData as its\n * fields, a Blob as `blobKey` and bytes as their numbers. Undefined for any other value.\n */\nfunction rawValueKey(value: object): BodyKey | undefined {\n if (isClass(value, \"URLSearchParams\")) {\n return { body: String(value), bodyType: \"URLSearchParams\" };\n }\n if (isClass(value, \"FormData\")) {\n return { body: formDataKey(value as FormData), bodyType: \"FormData\" };\n }\n if (isClass(value, \"Blob\") || isClass(value, \"File\")) {\n return { body: blobKey(value as Blob), bodyType: \"Blob\" };\n }\n const bytes = valueBytes(value);\n return bytes === null ? undefined : { body: Array.from(bytes), bodyType: \"bytes\" };\n}\n\n/**\n * The members of an object or an array body, each as `bodyKey`, and their kinds by name or index.\n * An empty object or array stays: a JSON `{}` or `[]` is a body, unlike none.\n */\nfunction membersKey(members: object): BodyKey {\n const body: Record<string, unknown> | unknown[] = Array.isArray(members) ? [] : {};\n const kinds: Record<string, BodyKinds> = {};\n for (const [name, value] of Object.entries(members)) {\n const member = bodyKey(value);\n (body as Record<string, unknown>)[name] = member.body;\n if (member.bodyType !== undefined) {\n kinds[name] = member.bodyType;\n }\n }\n return Object.keys(kinds).length === 0 ? { body } : { body, bodyType: kinds };\n}\n\n/**\n * A body in a key: a value JSON cannot hold by its content, wherever it is in the body, and the\n * kinds of such values in `bodyType`, a field no init has. A JSON body has no `bodyType`, so it\n * never shares a key with a body that holds such a value written as the same JSON.\n */\nexport function bodyKey(body: unknown): BodyKey {\n if (Array.isArray(body) || isPlainRecord(body)) {\n return membersKey(body);\n }\n const raw = typeof body === \"object\" && body !== null ? rawValueKey(body) : undefined;\n return raw ?? { body };\n}\n","/**\n * The request part of a query key (ADR-046). TanStack Query hashes a key as JSON: a `Headers`\n * object or a list of header pairs hashed as `{}` or by its order, and so did a FormData, a Blob,\n * an ArrayBuffer or a URLSearchParams body. Two requests that differed in them shared one cache\n * entry, and the `queryFn` of that entry sent the request of the first. Two clients with\n * different base URLs shared entries too. The key's init holds the headers and such a body as\n * plain values, and the base URL the request goes to or the client's key scope, so the key names\n * what was fetched.\n */\nimport { bodyKey, isPlainRecord } from \"./body-key.js\";\n\n/** Headers as a plain object, which TanStack Query hashes by its names and values. */\ntype HeadersRecord = Readonly<Record<string, unknown>>;\n\n/** What the key takes from the fetch client and the options of `createClient`. */\nexport interface KeyClient {\n /** The fetch client's base URL, `\"\"` without one. */\n readonly baseUrl: string;\n /** The name of the API in every key, in place of the base URL. */\n readonly keyScope?: string | undefined;\n}\n\n/**\n * The headers of an init as a plain object. A `Headers` object and a list of pairs, which are both\n * iterable, become the names and values the request sends: names in lowercase, a repeated one\n * joined with `, `, as `Headers` writes them. They are read without `Headers`, which threw for an\n * invalid name or value while the component rendered; the request reports it as a query error. A\n * plain object stays as it is, since its `null` and array values mean more than a string.\n */\nfunction plainHeaders(headers: object): HeadersRecord {\n if (!(Symbol.iterator in headers)) {\n return headers as HeadersRecord;\n }\n const record: Record<string, string> = {};\n for (const pair of headers as Iterable<unknown>) {\n const [name, value] = Array.from(pair as ArrayLike<unknown>);\n const key = String(name).toLowerCase();\n record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);\n }\n return record;\n}\n\n/**\n * The members of an object that are not `undefined`, or undefined when none is. A member set to\n * `undefined` (`headers: token ? … : undefined`, `query: { cursor: undefined }`) sends the same\n * request as none, and TanStack Query's hash leaves it out too, so a record of only such members\n * sends nothing and must not count as one. `null`, `[]` and `{}` members stay: `null` removes a\n * header, and a query serializer of the client may send them.\n */\nfunction definedMembers(record: object): Record<string, unknown> | undefined {\n const members = Object.entries(record).filter(([, value]) => value !== undefined);\n return members.length === 0 ? undefined : Object.fromEntries(members);\n}\n\n/**\n * The `params` of an init without the records that send nothing: `{}`, `{ query: {} }` and\n * `{ query: { cursor: undefined } }` send the request of no `params`, since the fetch client reads\n * a missing record as an empty one. Undefined when no record is left.\n */\nfunction paramsKey(params: unknown): unknown {\n if (!isPlainRecord(params)) {\n return params;\n }\n const records = Object.entries(params).map(([location, record]) => [\n location,\n isPlainRecord(record) ? definedMembers(record) : record,\n ]);\n return definedMembers(Object.fromEntries(records));\n}\n\n/** The headers of an init as `plainHeaders`, or undefined when they set none. */\nfunction headersKey(headers: unknown): unknown {\n return typeof headers === \"object\" && headers !== null\n ? definedMembers(plainHeaders(headers))\n : headers;\n}\n\n/**\n * The init of a query key: the request init with its params and headers without what sends\n * nothing, its body as `bodyKey`, and the client's key scope, or its base URL when the init has\n * none. The `signal` is left out: TanStack Query gives each request its own. Undefined when\n * nothing is left, so a call without an init and one with an init that sends nothing more, such\n * as `{}` or `{ params: { query: { cursor: undefined } } }`, have the key `[method, path]`.\n */\nexport function queryKeyInit(init: unknown, client: KeyClient): object | undefined {\n const { signal: _signal, ...rest } = (init ?? {}) as {\n signal?: unknown;\n params?: unknown;\n headers?: unknown;\n baseUrl?: unknown;\n body?: unknown;\n };\n const keyInit: Record<string, unknown> = {\n ...rest,\n params: paramsKey(rest.params),\n headers: headersKey(rest.headers),\n ...(rest.body === undefined ? {} : bodyKey(rest.body)),\n };\n if (client.keyScope !== undefined) {\n keyInit.keyScope = client.keyScope;\n } else if (!rest.baseUrl && client.baseUrl) {\n keyInit.baseUrl = client.baseUrl;\n }\n return definedMembers(keyInit);\n}\n","/**\n * The signal of a query's request. TanStack Query gives every request a signal, which it aborts\n * when the query is cancelled or no longer used; the init of the call may bring its own. The hooks\n * sent one of them: `useQuery` the call's, so a cancelled query kept its request, and\n * `useInfiniteQuery` TanStack's, so the call's signal did nothing. The request now stops when\n * either is aborted.\n */\n\n/** The init to send, and how to stop listening to the signals once the request has settled. */\nexport interface QueryRequest {\n readonly init: Record<string, unknown>;\n readonly release: () => void;\n}\n\nconst ABORT_EVENT = \"abort\";\n\nfunction withoutRelease(init: Record<string, unknown>): QueryRequest {\n return { init, release: () => undefined };\n}\n\n/** The init with a signal that aborts when the init's own signal or the query's does. */\nexport function withQuerySignal(init: unknown, querySignal: AbortSignal): QueryRequest {\n const { signal: ownSignal, ...rest } = (init ?? {}) as { signal?: AbortSignal | null };\n if (!ownSignal) {\n return withoutRelease({ ...rest, signal: querySignal });\n }\n const controller = new AbortController();\n const sources = [ownSignal, querySignal];\n const aborted = sources.find((source) => source.aborted);\n if (aborted !== undefined) {\n controller.abort(aborted.reason);\n return withoutRelease({ ...rest, signal: controller.signal });\n }\n const listeners = sources.map((source) => {\n const listener = () => controller.abort(source.reason);\n source.addEventListener(ABORT_EVENT, listener, { once: true });\n return () => source.removeEventListener(ABORT_EVENT, listener);\n });\n return {\n init: { ...rest, signal: controller.signal },\n release: () => {\n for (const remove of listeners) {\n remove();\n }\n },\n };\n}\n","import {\n type DataTag,\n type DefaultError,\n type DefinedUseQueryResult,\n type InfiniteData,\n type QueryClient,\n type QueryFunctionContext,\n type SkipToken,\n type UseInfiniteQueryOptions,\n type UseInfiniteQueryResult,\n type UseMutationOptions,\n type UseMutationResult,\n type UseQueryOptions,\n type UseQueryResult,\n type UseSuspenseQueryOptions,\n type UseSuspenseQueryResult,\n useInfiniteQuery,\n useMutation,\n useQuery,\n useSuspenseQuery,\n} from \"@tanstack/react-query\";\nimport type {\n ClientMethod,\n DefaultParamsOption,\n Client as FetchClient,\n FetchResponse,\n MaybeOptionalInit,\n PathOperation,\n} from \"openapi-typesafe-fetch\";\n// The helper types come from the client, which declares them: types inferred from the hooks then\n// print the client's `helpers` entry, of a peer every user has, and not `openapi-typesafe-helpers`,\n// which Yarn PnP does not let a library reach (ADR-034).\nimport type {\n HttpMethod,\n MediaType,\n PathsWithMethod,\n RequiredKeysOf,\n} from \"openapi-typesafe-fetch/helpers\";\nimport { queryKeyInit } from \"./query-key.js\";\nimport { withQuerySignal } from \"./query-signal.js\";\n\n// Helper type to dynamically infer the type from the `select` property\ntype InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;\n\n/**\n * Query data of a response type: a success without a body is `undefined` in the fetch client and\n * `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).\n */\ntype QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;\n\n/**\n * What the hooks throw when a request fails and the response has no error body: a non-OK status\n * with an empty body, a JSON `null` body, or one whose operation declares no content for it. The\n * fetch client gives `error: undefined` (or `null`) then; throwing that left `error` empty in\n * TanStack Query while its type said there was an error body. Tell it apart with\n * `isResponseError(error)`: `error instanceof Error` also matches a network or parse error. The\n * message names the status, not the URL, which can carry secrets.\n */\nexport interface ResponseError extends Error {\n readonly name: \"ResponseError\";\n /** The response that failed. */\n readonly response: Response;\n /** Its HTTP status, as `response.status`. */\n readonly status: number;\n}\n\n/**\n * The error of a hook: the error body of a failed response, a `ResponseError` when it has none, or\n * what the request threw before there was a response to read: a network error (`TypeError`), an\n * abort, a body that is not JSON (`SyntaxError`) or a middleware error. TanStack Query types that\n * last part as `DefaultError` (`Error` unless `Register` says otherwise; a registered `unknown`\n * makes the whole type `unknown`, as for TanStack's own hooks). `undefined` and `null` are left\n * out: a failed response without an error body throws a `ResponseError`.\n */\nexport type QueryError<ErrorBody> =\n | Exclude<ErrorBody, undefined | null>\n | ResponseError\n | DefaultError;\n\n/**\n * An object whose `queryKey` is tagged with the query's data and error types: the type that\n * TanStack Query 5.102 exports as `QueryKeyWithDataTag`, for the whole peer range. A named object\n * type, so the declarations of an exported `queryOptions` result print it by name. Spelled out,\n * the tag prints TanStack's `dataTagSymbol` keys, which a declaration file cannot import, and\n * the library's users get TS2304, or `any` cached data with `skipLibCheck`.\n */\nexport type QueryKeyWithDataTag<Key, Data, Error> = {\n queryKey: DataTag<Key, Data, Error>;\n};\n\ntype InitWithUnknowns<Init> = Init & { [key: string]: unknown };\n\n/**\n * The arguments after the path: the init, required when the operation requires a parameter or a\n * body, then `Rest`. The condition is openapi-react-query's, as `InitParam` of the fetch client\n * is openapi-fetch's (ADR-030, decision 2): TypeScript relates two conditional types only when\n * their `extends` types are the same, so a hook type copied from openapi-react-query takes these\n * hooks. For a union of inits, `MaybeOptionalInit` leaves out `undefined` when one is required,\n * so `Parameters<typeof $api.queryOptions>` still requires it then (upstream #2178).\n */\ntype InitArguments<Init, Rest extends unknown[]> =\n RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, ...Rest]\n : [InitWithUnknowns<Init>, ...Rest];\n\n/**\n * The key of a query: the method, the path and the request. Its init is the init of the call with\n * the headers and the body as plain values, and the client's `keyScope`, or its `baseUrl` when the\n * init has none, so two requests never share a key; it is left out when nothing is left. Read a\n * query's key from `queryOptions(...).queryKey` rather than writing it out.\n */\nexport type QueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init = MaybeOptionalInit<Paths[Path], Method>,\n> = Init extends undefined ? readonly [Method, Path] : readonly [Method, Path, Init];\n\n/**\n * The last element of an infinite query's key. `useQuery` and `useInfiniteQuery` cache different\n * data (`TData` and `InfiniteData<TData>`), so the same request must not share one key (upstream\n * #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported: it is not\n * needed outside the package, and a named export is public API; `InfiniteQueryKey` types the key.\n */\nconst INFINITE_QUERY_KEY_MARKER = \"infinite\";\n\nexport type InfiniteQueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];\n\n/**\n * Whether the options give an `initialData` that is never `undefined`: a value, or a function that\n * never returns `undefined`. Then `data` is never `undefined` either, as for TanStack Query's own\n * `useQuery` with `DefinedInitialDataOptions`.\n */\ntype HasDefinedInitialData<Options> = Options extends { initialData: infer Initial }\n ? Initial extends (...args: never) => infer Returned\n ? undefined extends Returned\n ? false\n : true\n : undefined extends Initial\n ? false\n : true\n : false;\n\n/** The result of `useQuery`: its `data` is defined when the options give defined initial data. */\ntype QueryResult<Data, Error, Options> =\n HasDefinedInitialData<Options> extends true\n ? DefinedUseQueryResult<Data, Error>\n : UseQueryResult<Data, Error>;\n\n/**\n * A defined `initialData` of the options, in the type `queryOptions` returns, so TanStack Query's\n * `useQuery` takes the result as options with defined initial data. It is typed as the query data,\n * as TanStack's `DefinedInitialDataOptions` types it: the type of a literal such as `[{ id: 1 }]`\n * lacks the optional properties of the data, and TanStack's overload rejected it.\n */\ntype InitialDataOf<Options, Data> =\n HasDefinedInitialData<Options> extends true ? { initialData: Data | (() => Data) } : unknown;\n\nexport type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n path: Path,\n ...[init, options]: InitArguments<Init, [Options?]>\n) => NoInfer<\n Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > &\n QueryKeyWithDataTag<\n QueryKey<Paths, Method, Path>,\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>\n > &\n InitialDataOf<Options, QueryData<Response[\"data\"]>> & {\n queryFn: Exclude<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >[\"queryFn\"],\n SkipToken | undefined\n >;\n }\n>;\n\nexport type UseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => QueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>,\n Options\n>;\n\n/**\n * The type of the page params: the initial one and the ones `getNextPageParam` and\n * `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a\n * return type is untyped, so code that compiled still compiles (roadmap §3): TypeScript cannot\n * infer the return type of a callback that computes it from an unannotated `lastPageParam`,\n * whose type depends on that return type, and gives `never` or `unknown`.\n */\ntype PageParam<Initial, Next, Previous> =\n IsUntyped<Next> extends true\n ? unknown\n : [Previous] extends [NoPreviousPageParam]\n ? NullishToUnknown<Initial | NonNullable<Next>>\n : IsUntyped<Previous> extends true\n ? unknown\n : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;\n\n/** The `Previous` type parameter when the options have no `getPreviousPageParam`. */\ndeclare const NO_PREVIOUS_PAGE_PARAM: unique symbol;\ntype NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;\n\ntype IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;\n\n/** Only `undefined` or `null` names no type: a cursor API's `initialPageParam: undefined`. */\ntype NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;\n\n/** Read only for the return type; `never` arguments add no inference for TanStack's page param. */\ntype PageParamFunction<Result> = (...args: never) => Result;\n\n/**\n * Inference sites of the page param types. Intersected before `Options`, so TanStack's own\n * inference in the implementation reads the full signatures of `Options`.\n */\ninterface PageParamSources<Initial, Next, Previous> {\n initialPageParam: Initial;\n getNextPageParam: PageParamFunction<Next>;\n getPreviousPageParam?: PageParamFunction<Previous>;\n}\n\n/**\n * `placeholderData` of `useInfiniteQuery`, with an `unknown` page param as before: TypeScript types\n * a `(previousData) => previousData` callback while it still infers the page param, so it got\n * `unknown` there and failed against the typed page param.\n */\ntype InfinitePlaceholderData<\n Data,\n Error,\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = UseInfiniteQueryOptions<\n Data,\n Error,\n InfiniteData<Data, unknown>,\n InfiniteQueryKey<Paths, Method, Path>,\n unknown\n>[\"placeholderData\"];\n\nexport type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseInfiniteQueryOptions<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n InfiniteQueryKey<Paths, Method, Path>,\n PageParam<Initial, Next, Previous>\n >,\n \"queryKey\" | \"queryFn\" | \"placeholderData\"\n > & {\n placeholderData?: InfinitePlaceholderData<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n Paths,\n Method,\n Path\n >;\n pageParamName?: string;\n },\n Initial = unknown,\n Next = never,\n Previous = NoPreviousPageParam,\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n>(\n method: Method,\n url: Path,\n init: InitWithUnknowns<Init>,\n options: PageParamSources<Initial, Next, Previous> & Options,\n queryClient?: QueryClient,\n) => UseInfiniteQueryResult<\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseSuspenseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => UseSuspenseQueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseMutationMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>;\n\nexport interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {\n queryOptions: QueryOptionsFunction<Paths, Media>;\n useQuery: UseQueryMethod<Paths, Media>;\n useSuspenseQuery: UseSuspenseQueryMethod<Paths, Media>;\n useInfiniteQuery: UseInfiniteQueryMethod<Paths, Media>;\n useMutation: UseMutationMethod<Paths, Media>;\n}\n\nexport type MethodResponse<\n // biome-ignore lint/suspicious/noExplicitAny: matches a client of any paths, as upstream's\n CreatedClient extends OpenapiQueryClient<any, any>,\n Method extends HttpMethod,\n Path extends CreatedClient extends OpenapiQueryClient<infer Paths, infer _Media>\n ? PathsWithMethod<Paths, Method>\n : never,\n Options = object,\n> =\n CreatedClient extends OpenapiQueryClient<\n // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces\n infer Paths extends { [key: string]: any },\n infer Media extends MediaType\n >\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/** The `name` of every `ResponseError`. */\nconst RESPONSE_ERROR_NAME = \"ResponseError\";\n\n/** The `ResponseError` of a failed response without an error body. */\nclass ResponseWithoutErrorBody extends Error implements ResponseError {\n override readonly name = RESPONSE_ERROR_NAME;\n readonly response: Response;\n readonly status: number;\n\n constructor(response: Response) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n super(`Request failed with status ${response.status}${statusText} and no error body`);\n this.response = response;\n this.status = response.status;\n }\n}\n\n/**\n * Whether `error` is the `ResponseError` of a failed response without an error body. It narrows a\n * hook's `error`, where `error instanceof Error` also matches network and parse errors. It checks\n * the `name`, not the class, so a `ResponseError` of another copy of this package (its CommonJS and\n * ES module builds loaded side by side) is one too. An error body from JSON is never an `Error`.\n */\nexport function isResponseError(error: unknown): error is ResponseError {\n return error instanceof Error && error.name === RESPONSE_ERROR_NAME;\n}\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response\n * with an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as\n * `0`. Without an error body a `ResponseError` is thrown, so the hooks' `error` is never\n * `undefined` (ADR-013, decision 3). A JSON `null` body is no error body either: thrown as is, it\n * left `error` `null` while the query's status was `\"error\"`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined && result.error !== null) {\n throw result.error;\n }\n if (!result.response.ok) {\n throw new ResponseWithoutErrorBody(result.response);\n }\n}\n\n/** The query parameter that carries the page param unless `pageParamName` names another. */\nconst DEFAULT_PAGE_PARAM_NAME = \"cursor\";\n\ninterface PageRequest {\n readonly pageParamName: string;\n readonly pageParam: unknown;\n}\n\n/**\n * The request init of one page. An `undefined` page param (the first page with\n * `initialPageParam: undefined`) is left out instead of being sent as `0` (upstream #2715, #2340,\n * ADR-022), so a cursor API gets no cursor on the first page.\n */\nfunction pageInit(init: unknown, { pageParamName, pageParam }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n/** Options of `createClient`. */\nexport interface CreateClientOptions {\n /**\n * The name of the API in every query key, in place of the fetch client's `baseUrl`. Give the\n * same name where the server and the browser reach one API by different URLs, so the browser\n * reads the data the server rendered with; give different names to clients of one base URL that\n * fetch different data, such as one per tenant header.\n */\n keyScope?: string;\n}\n\n/**\n * Hooks and query options for a fetch client. A `QueryClient` other than the one from the React\n * context is passed to each hook as its last argument; `createClient` does not take one.\n */\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: inherited, kept until 1.1 (ADR-036)\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n { keyScope }: CreateClientOptions = {},\n): OpenapiQueryClient<Paths, Media> {\n const keyClient = { baseUrl: client.baseUrl, keyScope };\n /**\n * Send one request of a query: the call's own init, with a signal that TanStack Query can abort.\n * The key only names the cache entry, as for `useInfiniteQuery`: a function in the init (a\n * `fetch`, a `middleware`) cannot be part of a key, so the request is read from the call.\n */\n const fetchPage = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>(\n method: Method,\n path: Path,\n init: unknown,\n signal: AbortSignal,\n ) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const request = withQuerySignal(init, signal);\n try {\n // The init is `unknown` here. An `any` init lets the call infer the generic response type\n // that `queryOptions` declares; a typed init makes TypeScript compare two unresolved\n // conditional types, which it cannot do.\n // biome-ignore lint/suspicious/noExplicitAny: see the comment above\n const result = await fn(path, request.init as any);\n throwIfFailed(result);\n return result.data;\n } finally {\n request.release();\n }\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => {\n const keyInit = queryKeyInit(init, keyClient);\n return {\n queryKey: (keyInit === undefined\n ? ([method, path] as const)\n : ([method, path, keyInit] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the data type\n any,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the error type\n any\n >,\n // TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for\n // every success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD\n // request (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.\n queryFn: async ({ signal }: QueryFunctionContext) =>\n (await fetchPage(method, path, init, signal)) ?? null,\n // Without options, `Options` is its constraint, which has no `initialData` to keep.\n ...(options as typeof options & {}),\n // The declared type types a defined `initialData` as the query data, a conditional type of\n // the generic options that TypeScript cannot relate to the object; it is the same object.\n } as never;\n };\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n // TanStack Query's `useQuery` returns `DefinedUseQueryResult` for options with defined\n // `initialData`; while `Options` is generic it cannot pick that overload, and the declared\n // `QueryResult` gives the caller the same answer. Both are the same object at runtime.\n useQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ) as never,\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ),\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n useInfiniteQuery: (method, path, init, options, queryClient) => {\n const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;\n const { queryKey } = queryOptions(method, path, init);\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // An empty page stays `undefined`, as in upstream: TanStack Query rejects only\n // `undefined` query data, and the infinite query data is the `{ pages }` object.\n queryFn: ({ pageParam, signal }) =>\n fetchPage(method, path, pageInit(init, { pageParamName, pageParam }), signal),\n ...restOptions,\n // Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack\n // passes the previous data of this query, with its own page params, and takes it back.\n // biome-ignore lint/suspicious/noExplicitAny: TanStack's type carries its own page params\n placeholderData: placeholderData as any,\n },\n queryClient,\n );\n },\n useMutation: (method, path, options, queryClient) =>\n useMutation(\n {\n mutationKey: [method, path],\n mutationFn: async (init) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const result = await fn(path, init as InitWithUnknowns<typeof init>);\n throwIfFailed(result);\n // TanStack Query accepts `undefined` mutation data, so a success without a body stays\n // `undefined`, as in upstream; only query data needs `null` (upstream #2234). The cast\n // only bridges the generic types: `Response[\"data\"]` still has `undefined` for an\n // operation with a response without a body.\n const { data } = result;\n return data as Exclude<typeof data, undefined>;\n },\n ...options,\n },\n queryClient,\n ),\n };\n}\n"],"names":["useQuery","useSuspenseQuery","useInfiniteQuery","useMutation"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -6,21 +6,16 @@ function isClass(value, name) {
6
6
  const type = globalThis[name];
7
7
  return typeof type === "function" && value instanceof type || Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name;
8
8
  }
9
- function plainHeaders(headers) {
10
- if (!(Symbol.iterator in headers)) {
11
- return headers;
12
- }
13
- const record = {};
14
- for (const pair of headers) {
15
- const [name, value] = Array.from(pair);
16
- const key = String(name).toLowerCase();
17
- record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);
9
+ function isPlainRecord(value) {
10
+ if (typeof value !== "object" || value === null) {
11
+ return false;
18
12
  }
19
- return record;
13
+ const prototype = Object.getPrototypeOf(value);
14
+ return prototype === Object.prototype || prototype === null;
20
15
  }
21
16
  function blobKey(blob) {
22
- const { name, lastModified } = blob;
23
- return { type: blob.type, size: blob.size, name, lastModified };
17
+ const { name } = blob;
18
+ return { type: blob.type, size: blob.size, name };
24
19
  }
25
20
  function formDataKey(form) {
26
21
  if (typeof form.entries !== "function") {
@@ -31,43 +26,88 @@ function formDataKey(form) {
31
26
  typeof value === "string" ? value : blobKey(value)
32
27
  ]);
33
28
  }
34
- function bodyBytes(body) {
35
- if (ArrayBuffer.isView(body)) {
36
- return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
29
+ function valueBytes(value) {
30
+ if (ArrayBuffer.isView(value)) {
31
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
32
+ }
33
+ return isClass(value, "ArrayBuffer") ? new Uint8Array(value) : null;
34
+ }
35
+ function rawValueKey(value) {
36
+ if (isClass(value, "URLSearchParams")) {
37
+ return { body: String(value), bodyType: "URLSearchParams" };
38
+ }
39
+ if (isClass(value, "FormData")) {
40
+ return { body: formDataKey(value), bodyType: "FormData" };
41
+ }
42
+ if (isClass(value, "Blob") || isClass(value, "File")) {
43
+ return { body: blobKey(value), bodyType: "Blob" };
37
44
  }
38
- return isClass(body, "ArrayBuffer") ? new Uint8Array(body) : null;
45
+ const bytes = valueBytes(value);
46
+ return bytes === null ? void 0 : { body: Array.from(bytes), bodyType: "bytes" };
47
+ }
48
+ function membersKey(members) {
49
+ const body = Array.isArray(members) ? [] : {};
50
+ const kinds = {};
51
+ for (const [name, value] of Object.entries(members)) {
52
+ const member = bodyKey(value);
53
+ body[name] = member.body;
54
+ if (member.bodyType !== void 0) {
55
+ kinds[name] = member.bodyType;
56
+ }
57
+ }
58
+ return Object.keys(kinds).length === 0 ? { body } : { body, bodyType: kinds };
39
59
  }
40
60
  function bodyKey(body) {
41
- if (typeof body !== "object" || body === null) {
42
- return body;
61
+ if (Array.isArray(body) || isPlainRecord(body)) {
62
+ return membersKey(body);
43
63
  }
44
- if (isClass(body, "URLSearchParams")) {
45
- return { URLSearchParams: String(body) };
64
+ const raw = typeof body === "object" && body !== null ? rawValueKey(body) : void 0;
65
+ return raw ?? { body };
66
+ }
67
+
68
+ function plainHeaders(headers) {
69
+ if (!(Symbol.iterator in headers)) {
70
+ return headers;
46
71
  }
47
- if (isClass(body, "FormData")) {
48
- return { FormData: formDataKey(body) };
72
+ const record = {};
73
+ for (const pair of headers) {
74
+ const [name, value] = Array.from(pair);
75
+ const key = String(name).toLowerCase();
76
+ record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);
49
77
  }
50
- if (isClass(body, "Blob") || isClass(body, "File")) {
51
- return { Blob: blobKey(body) };
78
+ return record;
79
+ }
80
+ function definedMembers(record) {
81
+ const members = Object.entries(record).filter(([, value]) => value !== void 0);
82
+ return members.length === 0 ? void 0 : Object.fromEntries(members);
83
+ }
84
+ function paramsKey(params) {
85
+ if (!isPlainRecord(params)) {
86
+ return params;
52
87
  }
53
- const bytes = bodyBytes(body);
54
- return bytes === null ? body : { bytes: Array.from(bytes) };
88
+ const records = Object.entries(params).map(([location, record]) => [
89
+ location,
90
+ isPlainRecord(record) ? definedMembers(record) : record
91
+ ]);
92
+ return definedMembers(Object.fromEntries(records));
93
+ }
94
+ function headersKey(headers) {
95
+ return typeof headers === "object" && headers !== null ? definedMembers(plainHeaders(headers)) : headers;
55
96
  }
56
97
  function queryKeyInit(init, client) {
57
98
  const { signal: _signal, ...rest } = init ?? {};
58
- const keyInit = { ...rest };
59
- if (typeof rest.headers === "object" && rest.headers !== null) {
60
- keyInit.headers = plainHeaders(rest.headers);
61
- }
62
- if ("body" in rest) {
63
- keyInit.body = bodyKey(rest.body);
64
- }
99
+ const keyInit = {
100
+ ...rest,
101
+ params: paramsKey(rest.params),
102
+ headers: headersKey(rest.headers),
103
+ ...rest.body === void 0 ? {} : bodyKey(rest.body)
104
+ };
65
105
  if (client.keyScope !== void 0) {
66
106
  keyInit.keyScope = client.keyScope;
67
107
  } else if (!rest.baseUrl && client.baseUrl) {
68
108
  keyInit.baseUrl = client.baseUrl;
69
109
  }
70
- return Object.keys(keyInit).length === 0 ? void 0 : keyInit;
110
+ return definedMembers(keyInit);
71
111
  }
72
112
 
73
113
  const ABORT_EVENT = "abort";
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/query-key.ts","../src/query-signal.ts","../src/index.ts"],"sourcesContent":["/**\n * The request part of a query key (ADR-046). TanStack Query hashes a key as JSON: a `Headers`\n * object or a list of header pairs hashed as `{}` or by its order, and so did a FormData, a Blob,\n * an ArrayBuffer or a URLSearchParams body. Two requests that differed in them shared one cache\n * entry, and the `queryFn` of that entry sent the request of the first. Two clients with\n * different base URLs shared entries too. The key's init holds the headers and such a body as\n * plain values, and the base URL the request goes to or the client's key scope, so the key names\n * what was fetched.\n */\n\n/** Headers as a plain object, which TanStack Query hashes by its names and values. */\ntype HeadersRecord = Readonly<Record<string, unknown>>;\n\n/** What the key takes from the fetch client and the options of `createClient`. */\nexport interface KeyClient {\n /** The fetch client's base URL, `\"\"` without one. */\n readonly baseUrl: string;\n /** The name of the API in every key, in place of the base URL. */\n readonly keyScope?: string | undefined;\n}\n\n/** `[object Name]`: the type tag is between these indexes of `Object.prototype.toString`. */\nconst TYPE_TAG_START = \"[object \".length;\nconst TYPE_TAG_END = -1;\n\n/**\n * Whether a value is of the class `name`: an instance of this realm's global class of that name\n * (React Native's classes have no type tag), or a value with its type tag (a class of another\n * realm or of the `undici` package), as the fetch client tells bodies (ADR-030).\n */\nfunction isClass(value: object, name: string): boolean {\n const type = (globalThis as Record<string, unknown>)[name];\n return (\n (typeof type === \"function\" && value instanceof type) ||\n Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name\n );\n}\n\n/**\n * The headers of an init as a plain object. A `Headers` object and a list of pairs, which are both\n * iterable, become the names and values the request sends: names in lowercase, a repeated one\n * joined with `, `, as `Headers` writes them. They are read without `Headers`, which threw for an\n * invalid name or value while the component rendered; the request reports it as a query error. A\n * plain object stays as it is, since its `null` and array values mean more than a string.\n */\nfunction plainHeaders(headers: object): HeadersRecord {\n if (!(Symbol.iterator in headers)) {\n return headers as HeadersRecord;\n }\n const record: Record<string, string> = {};\n for (const pair of headers as Iterable<unknown>) {\n const [name, value] = Array.from(pair as ArrayLike<unknown>);\n const key = String(name).toLowerCase();\n record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);\n }\n return record;\n}\n\n/**\n * A Blob or a File in a key: its type, size, and the name and date of a File. Its bytes cannot be\n * read while the component renders, so two Blobs of the same type and size share an entry.\n */\nfunction blobKey(blob: Blob): object {\n const { name, lastModified } = blob as Partial<File>;\n return { type: blob.type, size: blob.size, name, lastModified };\n}\n\n/** The fields of a FormData in a key, in order, with a file as `blobKey`. */\nfunction formDataKey(form: FormData): unknown[] {\n // React Native's FormData has no `entries`, so its fields cannot be read.\n if (typeof form.entries !== \"function\") {\n return [];\n }\n return Array.from(form.entries(), ([name, value]) => [\n name,\n typeof value === \"string\" ? value : blobKey(value),\n ]);\n}\n\n/** The bytes of an ArrayBuffer or a typed array, or null for another value. */\nfunction bodyBytes(body: object): Uint8Array | null {\n if (ArrayBuffer.isView(body)) {\n return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);\n }\n return isClass(body, \"ArrayBuffer\") ? new Uint8Array(body as ArrayBuffer) : null;\n}\n\n/**\n * A request body as a value TanStack Query hashes by its content. A URLSearchParams is its text,\n * a FormData its fields, a Blob `blobKey` and bytes their numbers, each under its kind, so it\n * differs from a JSON body with the same content. Other values stay as they are.\n */\nfunction bodyKey(body: unknown): unknown {\n if (typeof body !== \"object\" || body === null) {\n return body;\n }\n if (isClass(body, \"URLSearchParams\")) {\n return { URLSearchParams: String(body) };\n }\n if (isClass(body, \"FormData\")) {\n return { FormData: formDataKey(body as FormData) };\n }\n if (isClass(body, \"Blob\") || isClass(body, \"File\")) {\n return { Blob: blobKey(body as Blob) };\n }\n const bytes = bodyBytes(body);\n return bytes === null ? body : { bytes: Array.from(bytes) };\n}\n\n/**\n * The init of a query key: the request init with its headers and body as plain values, and the\n * client's key scope, or its base URL when the init has none. The `signal` is left out: TanStack\n * Query gives each request its own. Undefined when nothing is left, so a call without an init and\n * one with an empty init have the key `[method, path]`.\n */\nexport function queryKeyInit(init: unknown, client: KeyClient): object | undefined {\n const { signal: _signal, ...rest } = (init ?? {}) as {\n signal?: unknown;\n headers?: unknown;\n baseUrl?: unknown;\n body?: unknown;\n };\n const keyInit: Record<string, unknown> = { ...rest };\n if (typeof rest.headers === \"object\" && rest.headers !== null) {\n keyInit.headers = plainHeaders(rest.headers);\n }\n if (\"body\" in rest) {\n keyInit.body = bodyKey(rest.body);\n }\n if (client.keyScope !== undefined) {\n keyInit.keyScope = client.keyScope;\n } else if (!rest.baseUrl && client.baseUrl) {\n keyInit.baseUrl = client.baseUrl;\n }\n return Object.keys(keyInit).length === 0 ? undefined : keyInit;\n}\n","/**\n * The signal of a query's request. TanStack Query gives every request a signal, which it aborts\n * when the query is cancelled or no longer used; the init of the call may bring its own. The hooks\n * sent one of them: `useQuery` the call's, so a cancelled query kept its request, and\n * `useInfiniteQuery` TanStack's, so the call's signal did nothing. The request now stops when\n * either is aborted.\n */\n\n/** The init to send, and how to stop listening to the signals once the request has settled. */\nexport interface QueryRequest {\n readonly init: Record<string, unknown>;\n readonly release: () => void;\n}\n\nconst ABORT_EVENT = \"abort\";\n\nfunction withoutRelease(init: Record<string, unknown>): QueryRequest {\n return { init, release: () => undefined };\n}\n\n/** The init with a signal that aborts when the init's own signal or the query's does. */\nexport function withQuerySignal(init: unknown, querySignal: AbortSignal): QueryRequest {\n const { signal: ownSignal, ...rest } = (init ?? {}) as { signal?: AbortSignal | null };\n if (!ownSignal) {\n return withoutRelease({ ...rest, signal: querySignal });\n }\n const controller = new AbortController();\n const sources = [ownSignal, querySignal];\n const aborted = sources.find((source) => source.aborted);\n if (aborted !== undefined) {\n controller.abort(aborted.reason);\n return withoutRelease({ ...rest, signal: controller.signal });\n }\n const listeners = sources.map((source) => {\n const listener = () => controller.abort(source.reason);\n source.addEventListener(ABORT_EVENT, listener, { once: true });\n return () => source.removeEventListener(ABORT_EVENT, listener);\n });\n return {\n init: { ...rest, signal: controller.signal },\n release: () => {\n for (const remove of listeners) {\n remove();\n }\n },\n };\n}\n","import {\n type DataTag,\n type DefaultError,\n type DefinedUseQueryResult,\n type InfiniteData,\n type QueryClient,\n type QueryFunctionContext,\n type SkipToken,\n type UseInfiniteQueryOptions,\n type UseInfiniteQueryResult,\n type UseMutationOptions,\n type UseMutationResult,\n type UseQueryOptions,\n type UseQueryResult,\n type UseSuspenseQueryOptions,\n type UseSuspenseQueryResult,\n useInfiniteQuery,\n useMutation,\n useQuery,\n useSuspenseQuery,\n} from \"@tanstack/react-query\";\nimport type {\n ClientMethod,\n DefaultParamsOption,\n Client as FetchClient,\n FetchResponse,\n MaybeOptionalInit,\n PathOperation,\n} from \"openapi-typesafe-fetch\";\n// The helper types come from the client, which declares them: types inferred from the hooks then\n// print the client's `helpers` entry, of a peer every user has, and not `openapi-typesafe-helpers`,\n// which Yarn PnP does not let a library reach (ADR-034).\nimport type {\n HttpMethod,\n MediaType,\n PathsWithMethod,\n RequiredKeysOf,\n} from \"openapi-typesafe-fetch/helpers\";\nimport { queryKeyInit } from \"./query-key.js\";\nimport { withQuerySignal } from \"./query-signal.js\";\n\n// Helper type to dynamically infer the type from the `select` property\ntype InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;\n\n/**\n * Query data of a response type: a success without a body is `undefined` in the fetch client and\n * `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).\n */\ntype QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;\n\n/**\n * What the hooks throw when a request fails and the response has no error body: a non-OK status\n * with an empty body, a JSON `null` body, or one whose operation declares no content for it. The\n * fetch client gives `error: undefined` (or `null`) then; throwing that left `error` empty in\n * TanStack Query while its type said there was an error body. Tell it apart with\n * `isResponseError(error)`: `error instanceof Error` also matches a network or parse error. The\n * message names the status, not the URL, which can carry secrets.\n */\nexport interface ResponseError extends Error {\n readonly name: \"ResponseError\";\n /** The response that failed. */\n readonly response: Response;\n /** Its HTTP status, as `response.status`. */\n readonly status: number;\n}\n\n/**\n * The error of a hook: the error body of a failed response, a `ResponseError` when it has none, or\n * what the request threw before there was a response to read: a network error (`TypeError`), an\n * abort, a body that is not JSON (`SyntaxError`) or a middleware error. TanStack Query types that\n * last part as `DefaultError` (`Error` unless `Register` says otherwise; a registered `unknown`\n * makes the whole type `unknown`, as for TanStack's own hooks). `undefined` and `null` are left\n * out: a failed response without an error body throws a `ResponseError`.\n */\nexport type QueryError<ErrorBody> =\n | Exclude<ErrorBody, undefined | null>\n | ResponseError\n | DefaultError;\n\n/**\n * An object whose `queryKey` is tagged with the query's data and error types: the type that\n * TanStack Query 5.102 exports as `QueryKeyWithDataTag`, for the whole peer range. A named object\n * type, so the declarations of an exported `queryOptions` result print it by name. Spelled out,\n * the tag prints TanStack's `dataTagSymbol` keys, which a declaration file cannot import, and\n * the library's users get TS2304, or `any` cached data with `skipLibCheck`.\n */\nexport type QueryKeyWithDataTag<Key, Data, Error> = {\n queryKey: DataTag<Key, Data, Error>;\n};\n\ntype InitWithUnknowns<Init> = Init & { [key: string]: unknown };\n\n/**\n * The arguments after the path: the init, required when the operation requires a parameter or a\n * body, then `Rest`. The condition is openapi-react-query's, as `InitParam` of the fetch client\n * is openapi-fetch's (ADR-030, decision 2): TypeScript relates two conditional types only when\n * their `extends` types are the same, so a hook type copied from openapi-react-query takes these\n * hooks. For a union of inits, `MaybeOptionalInit` leaves out `undefined` when one is required,\n * so `Parameters<typeof $api.queryOptions>` still requires it then (upstream #2178).\n */\ntype InitArguments<Init, Rest extends unknown[]> =\n RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, ...Rest]\n : [InitWithUnknowns<Init>, ...Rest];\n\n/**\n * The key of a query: the method, the path and the request. Its init is the init of the call with\n * the headers and the body as plain values, and the client's `keyScope`, or its `baseUrl` when the\n * init has none, so two requests never share a key; it is left out when nothing is left. Read a\n * query's key from `queryOptions(...).queryKey` rather than writing it out.\n */\nexport type QueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init = MaybeOptionalInit<Paths[Path], Method>,\n> = Init extends undefined ? readonly [Method, Path] : readonly [Method, Path, Init];\n\n/**\n * The last element of an infinite query's key. `useQuery` and `useInfiniteQuery` cache different\n * data (`TData` and `InfiniteData<TData>`), so the same request must not share one key (upstream\n * #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported: it is not\n * needed outside the package, and a named export is public API; `InfiniteQueryKey` types the key.\n */\nconst INFINITE_QUERY_KEY_MARKER = \"infinite\";\n\nexport type InfiniteQueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];\n\n/**\n * Whether the options give an `initialData` that is never `undefined`: a value, or a function that\n * never returns `undefined`. Then `data` is never `undefined` either, as for TanStack Query's own\n * `useQuery` with `DefinedInitialDataOptions`.\n */\ntype HasDefinedInitialData<Options> = Options extends { initialData: infer Initial }\n ? Initial extends (...args: never) => infer Returned\n ? undefined extends Returned\n ? false\n : true\n : undefined extends Initial\n ? false\n : true\n : false;\n\n/** The result of `useQuery`: its `data` is defined when the options give defined initial data. */\ntype QueryResult<Data, Error, Options> =\n HasDefinedInitialData<Options> extends true\n ? DefinedUseQueryResult<Data, Error>\n : UseQueryResult<Data, Error>;\n\n/**\n * A defined `initialData` of the options, in the type `queryOptions` returns, so TanStack Query's\n * `useQuery` takes the result as options with defined initial data. It is typed as the query data,\n * as TanStack's `DefinedInitialDataOptions` types it: the type of a literal such as `[{ id: 1 }]`\n * lacks the optional properties of the data, and TanStack's overload rejected it.\n */\ntype InitialDataOf<Options, Data> =\n HasDefinedInitialData<Options> extends true ? { initialData: Data | (() => Data) } : unknown;\n\nexport type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n path: Path,\n ...[init, options]: InitArguments<Init, [Options?]>\n) => NoInfer<\n Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > &\n QueryKeyWithDataTag<\n QueryKey<Paths, Method, Path>,\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>\n > &\n InitialDataOf<Options, QueryData<Response[\"data\"]>> & {\n queryFn: Exclude<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >[\"queryFn\"],\n SkipToken | undefined\n >;\n }\n>;\n\nexport type UseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => QueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>,\n Options\n>;\n\n/**\n * The type of the page params: the initial one and the ones `getNextPageParam` and\n * `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a\n * return type is untyped, so code that compiled still compiles (roadmap §3): TypeScript cannot\n * infer the return type of a callback that computes it from an unannotated `lastPageParam`,\n * whose type depends on that return type, and gives `never` or `unknown`.\n */\ntype PageParam<Initial, Next, Previous> =\n IsUntyped<Next> extends true\n ? unknown\n : [Previous] extends [NoPreviousPageParam]\n ? NullishToUnknown<Initial | NonNullable<Next>>\n : IsUntyped<Previous> extends true\n ? unknown\n : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;\n\n/** The `Previous` type parameter when the options have no `getPreviousPageParam`. */\ndeclare const NO_PREVIOUS_PAGE_PARAM: unique symbol;\ntype NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;\n\ntype IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;\n\n/** Only `undefined` or `null` names no type: a cursor API's `initialPageParam: undefined`. */\ntype NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;\n\n/** Read only for the return type; `never` arguments add no inference for TanStack's page param. */\ntype PageParamFunction<Result> = (...args: never) => Result;\n\n/**\n * Inference sites of the page param types. Intersected before `Options`, so TanStack's own\n * inference in the implementation reads the full signatures of `Options`.\n */\ninterface PageParamSources<Initial, Next, Previous> {\n initialPageParam: Initial;\n getNextPageParam: PageParamFunction<Next>;\n getPreviousPageParam?: PageParamFunction<Previous>;\n}\n\n/**\n * `placeholderData` of `useInfiniteQuery`, with an `unknown` page param as before: TypeScript types\n * a `(previousData) => previousData` callback while it still infers the page param, so it got\n * `unknown` there and failed against the typed page param.\n */\ntype InfinitePlaceholderData<\n Data,\n Error,\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = UseInfiniteQueryOptions<\n Data,\n Error,\n InfiniteData<Data, unknown>,\n InfiniteQueryKey<Paths, Method, Path>,\n unknown\n>[\"placeholderData\"];\n\nexport type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseInfiniteQueryOptions<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n InfiniteQueryKey<Paths, Method, Path>,\n PageParam<Initial, Next, Previous>\n >,\n \"queryKey\" | \"queryFn\" | \"placeholderData\"\n > & {\n placeholderData?: InfinitePlaceholderData<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n Paths,\n Method,\n Path\n >;\n pageParamName?: string;\n },\n Initial = unknown,\n Next = never,\n Previous = NoPreviousPageParam,\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n>(\n method: Method,\n url: Path,\n init: InitWithUnknowns<Init>,\n options: PageParamSources<Initial, Next, Previous> & Options,\n queryClient?: QueryClient,\n) => UseInfiniteQueryResult<\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseSuspenseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => UseSuspenseQueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseMutationMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>;\n\nexport interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {\n queryOptions: QueryOptionsFunction<Paths, Media>;\n useQuery: UseQueryMethod<Paths, Media>;\n useSuspenseQuery: UseSuspenseQueryMethod<Paths, Media>;\n useInfiniteQuery: UseInfiniteQueryMethod<Paths, Media>;\n useMutation: UseMutationMethod<Paths, Media>;\n}\n\nexport type MethodResponse<\n // biome-ignore lint/suspicious/noExplicitAny: matches a client of any paths, as upstream's\n CreatedClient extends OpenapiQueryClient<any, any>,\n Method extends HttpMethod,\n Path extends CreatedClient extends OpenapiQueryClient<infer Paths, infer _Media>\n ? PathsWithMethod<Paths, Method>\n : never,\n Options = object,\n> =\n CreatedClient extends OpenapiQueryClient<\n // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces\n infer Paths extends { [key: string]: any },\n infer Media extends MediaType\n >\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/** The `name` of every `ResponseError`. */\nconst RESPONSE_ERROR_NAME = \"ResponseError\";\n\n/** The `ResponseError` of a failed response without an error body. */\nclass ResponseWithoutErrorBody extends Error implements ResponseError {\n override readonly name = RESPONSE_ERROR_NAME;\n readonly response: Response;\n readonly status: number;\n\n constructor(response: Response) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n super(`Request failed with status ${response.status}${statusText} and no error body`);\n this.response = response;\n this.status = response.status;\n }\n}\n\n/**\n * Whether `error` is the `ResponseError` of a failed response without an error body. It narrows a\n * hook's `error`, where `error instanceof Error` also matches network and parse errors. It checks\n * the `name`, not the class, so a `ResponseError` of another copy of this package (its CommonJS and\n * ES module builds loaded side by side) is one too. An error body from JSON is never an `Error`.\n */\nexport function isResponseError(error: unknown): error is ResponseError {\n return error instanceof Error && error.name === RESPONSE_ERROR_NAME;\n}\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response\n * with an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as\n * `0`. Without an error body a `ResponseError` is thrown, so the hooks' `error` is never\n * `undefined` (ADR-013, decision 3). A JSON `null` body is no error body either: thrown as is, it\n * left `error` `null` while the query's status was `\"error\"`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined && result.error !== null) {\n throw result.error;\n }\n if (!result.response.ok) {\n throw new ResponseWithoutErrorBody(result.response);\n }\n}\n\n/** The query parameter that carries the page param unless `pageParamName` names another. */\nconst DEFAULT_PAGE_PARAM_NAME = \"cursor\";\n\ninterface PageRequest {\n readonly pageParamName: string;\n readonly pageParam: unknown;\n}\n\n/**\n * The request init of one page. An `undefined` page param (the first page with\n * `initialPageParam: undefined`) is left out instead of being sent as `0` (upstream #2715, #2340,\n * ADR-022), so a cursor API gets no cursor on the first page.\n */\nfunction pageInit(init: unknown, { pageParamName, pageParam }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n/** Options of `createClient`. */\nexport interface CreateClientOptions {\n /**\n * The name of the API in every query key, in place of the fetch client's `baseUrl`. Give the\n * same name where the server and the browser reach one API by different URLs, so the browser\n * reads the data the server rendered with; give different names to clients of one base URL that\n * fetch different data, such as one per tenant header.\n */\n keyScope?: string;\n}\n\n/**\n * Hooks and query options for a fetch client. A `QueryClient` other than the one from the React\n * context is passed to each hook as its last argument; `createClient` does not take one.\n */\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: inherited, kept until 1.1 (ADR-036)\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n { keyScope }: CreateClientOptions = {},\n): OpenapiQueryClient<Paths, Media> {\n const keyClient = { baseUrl: client.baseUrl, keyScope };\n /**\n * Send one request of a query: the call's own init, with a signal that TanStack Query can abort.\n * The key only names the cache entry, as for `useInfiniteQuery`: a function in the init (a\n * `fetch`, a `middleware`) cannot be part of a key, so the request is read from the call.\n */\n const fetchPage = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>(\n method: Method,\n path: Path,\n init: unknown,\n signal: AbortSignal,\n ) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const request = withQuerySignal(init, signal);\n try {\n // The init is `unknown` here. An `any` init lets the call infer the generic response type\n // that `queryOptions` declares; a typed init makes TypeScript compare two unresolved\n // conditional types, which it cannot do.\n // biome-ignore lint/suspicious/noExplicitAny: see the comment above\n const result = await fn(path, request.init as any);\n throwIfFailed(result);\n return result.data;\n } finally {\n request.release();\n }\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => {\n const keyInit = queryKeyInit(init, keyClient);\n return {\n queryKey: (keyInit === undefined\n ? ([method, path] as const)\n : ([method, path, keyInit] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the data type\n any,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the error type\n any\n >,\n // TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for\n // every success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD\n // request (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.\n queryFn: async ({ signal }: QueryFunctionContext) =>\n (await fetchPage(method, path, init, signal)) ?? null,\n // Without options, `Options` is its constraint, which has no `initialData` to keep.\n ...(options as typeof options & {}),\n // The declared type types a defined `initialData` as the query data, a conditional type of\n // the generic options that TypeScript cannot relate to the object; it is the same object.\n } as never;\n };\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n // TanStack Query's `useQuery` returns `DefinedUseQueryResult` for options with defined\n // `initialData`; while `Options` is generic it cannot pick that overload, and the declared\n // `QueryResult` gives the caller the same answer. Both are the same object at runtime.\n useQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ) as never,\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ),\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n useInfiniteQuery: (method, path, init, options, queryClient) => {\n const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;\n const { queryKey } = queryOptions(method, path, init);\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // An empty page stays `undefined`, as in upstream: TanStack Query rejects only\n // `undefined` query data, and the infinite query data is the `{ pages }` object.\n queryFn: ({ pageParam, signal }) =>\n fetchPage(method, path, pageInit(init, { pageParamName, pageParam }), signal),\n ...restOptions,\n // Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack\n // passes the previous data of this query, with its own page params, and takes it back.\n // biome-ignore lint/suspicious/noExplicitAny: TanStack's type carries its own page params\n placeholderData: placeholderData as any,\n },\n queryClient,\n );\n },\n useMutation: (method, path, options, queryClient) =>\n useMutation(\n {\n mutationKey: [method, path],\n mutationFn: async (init) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const result = await fn(path, init as InitWithUnknowns<typeof init>);\n throwIfFailed(result);\n // TanStack Query accepts `undefined` mutation data, so a success without a body stays\n // `undefined`, as in upstream; only query data needs `null` (upstream #2234). The cast\n // only bridges the generic types: `Response[\"data\"]` still has `undefined` for an\n // operation with a response without a body.\n const { data } = result;\n return data as Exclude<typeof data, undefined>;\n },\n ...options,\n },\n queryClient,\n ),\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/body-key.ts","../src/query-key.ts","../src/query-signal.ts","../src/index.ts"],"sourcesContent":["/**\n * The body part of a query key (ADR-046). TanStack Query hashes a key as JSON, which writes a\n * FormData, a Blob, an ArrayBuffer or a URLSearchParams as `{}`, as the whole body or as a field\n * of an object body (a multipart body written as `{ image: file }`). The key holds each such value\n * by its content and names its kind beside the body, so the key names what is sent.\n */\n\n/** `[object Name]`: the type tag is between these indexes of `Object.prototype.toString`. */\nconst TYPE_TAG_START = \"[object \".length;\nconst TYPE_TAG_END = -1;\n\n/** The kind of a value that JSON cannot hold. */\ntype RawKind = \"URLSearchParams\" | \"FormData\" | \"Blob\" | \"bytes\";\n\n/**\n * The kinds of the values JSON cannot hold in a body: the kind of a body that is one, or, for an\n * object or an array body, the kinds of its members by their names or indexes, only where there\n * are some.\n */\ntype BodyKinds = RawKind | { readonly [member: string]: BodyKinds };\n\n/** A body as a value TanStack Query hashes, and the kinds of the values JSON cannot hold in it. */\nexport interface BodyKey {\n readonly body: unknown;\n readonly bodyType?: BodyKinds;\n}\n\n/**\n * Whether a value is of the class `name`: an instance of this realm's global class of that name\n * (React Native's classes have no type tag), or a value with its type tag (a class of another\n * realm or of the `undici` package), as the fetch client tells bodies (ADR-030).\n */\nfunction isClass(value: object, name: string): boolean {\n const type = (globalThis as Record<string, unknown>)[name];\n return (\n (typeof type === \"function\" && value instanceof type) ||\n Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name\n );\n}\n\n/**\n * Whether a value is an object literal, whose members JSON writes. A Date or another class has\n * its own JSON form, which the key keeps.\n */\nexport function isPlainRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const prototype: unknown = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * A Blob or a File in a key: its type, size, and the name of a File. Its bytes cannot be read while\n * the component renders, so two Blobs of the same type and size share an entry. The date of a File\n * is left out: `FormData.append` and `new File` set it to the current time, so a body built while\n * rendering got a new key, and a new request, on every render.\n */\nfunction blobKey(blob: Blob): object {\n const { name } = blob as Partial<File>;\n return { type: blob.type, size: blob.size, name };\n}\n\n/** The fields of a FormData in a key, in order, with a file as `blobKey`. */\nfunction formDataKey(form: FormData): unknown[] {\n // React Native's FormData has no `entries`, so its fields cannot be read.\n if (typeof form.entries !== \"function\") {\n return [];\n }\n return Array.from(form.entries(), ([name, value]) => [\n name,\n typeof value === \"string\" ? value : blobKey(value),\n ]);\n}\n\n/** The bytes of an ArrayBuffer or a typed array, or null for another value. */\nfunction valueBytes(value: object): Uint8Array | null {\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n }\n return isClass(value, \"ArrayBuffer\") ? new Uint8Array(value as ArrayBuffer) : null;\n}\n\n/**\n * A value that JSON cannot hold, by its content: a URLSearchParams as its text, a FormData as its\n * fields, a Blob as `blobKey` and bytes as their numbers. Undefined for any other value.\n */\nfunction rawValueKey(value: object): BodyKey | undefined {\n if (isClass(value, \"URLSearchParams\")) {\n return { body: String(value), bodyType: \"URLSearchParams\" };\n }\n if (isClass(value, \"FormData\")) {\n return { body: formDataKey(value as FormData), bodyType: \"FormData\" };\n }\n if (isClass(value, \"Blob\") || isClass(value, \"File\")) {\n return { body: blobKey(value as Blob), bodyType: \"Blob\" };\n }\n const bytes = valueBytes(value);\n return bytes === null ? undefined : { body: Array.from(bytes), bodyType: \"bytes\" };\n}\n\n/**\n * The members of an object or an array body, each as `bodyKey`, and their kinds by name or index.\n * An empty object or array stays: a JSON `{}` or `[]` is a body, unlike none.\n */\nfunction membersKey(members: object): BodyKey {\n const body: Record<string, unknown> | unknown[] = Array.isArray(members) ? [] : {};\n const kinds: Record<string, BodyKinds> = {};\n for (const [name, value] of Object.entries(members)) {\n const member = bodyKey(value);\n (body as Record<string, unknown>)[name] = member.body;\n if (member.bodyType !== undefined) {\n kinds[name] = member.bodyType;\n }\n }\n return Object.keys(kinds).length === 0 ? { body } : { body, bodyType: kinds };\n}\n\n/**\n * A body in a key: a value JSON cannot hold by its content, wherever it is in the body, and the\n * kinds of such values in `bodyType`, a field no init has. A JSON body has no `bodyType`, so it\n * never shares a key with a body that holds such a value written as the same JSON.\n */\nexport function bodyKey(body: unknown): BodyKey {\n if (Array.isArray(body) || isPlainRecord(body)) {\n return membersKey(body);\n }\n const raw = typeof body === \"object\" && body !== null ? rawValueKey(body) : undefined;\n return raw ?? { body };\n}\n","/**\n * The request part of a query key (ADR-046). TanStack Query hashes a key as JSON: a `Headers`\n * object or a list of header pairs hashed as `{}` or by its order, and so did a FormData, a Blob,\n * an ArrayBuffer or a URLSearchParams body. Two requests that differed in them shared one cache\n * entry, and the `queryFn` of that entry sent the request of the first. Two clients with\n * different base URLs shared entries too. The key's init holds the headers and such a body as\n * plain values, and the base URL the request goes to or the client's key scope, so the key names\n * what was fetched.\n */\nimport { bodyKey, isPlainRecord } from \"./body-key.js\";\n\n/** Headers as a plain object, which TanStack Query hashes by its names and values. */\ntype HeadersRecord = Readonly<Record<string, unknown>>;\n\n/** What the key takes from the fetch client and the options of `createClient`. */\nexport interface KeyClient {\n /** The fetch client's base URL, `\"\"` without one. */\n readonly baseUrl: string;\n /** The name of the API in every key, in place of the base URL. */\n readonly keyScope?: string | undefined;\n}\n\n/**\n * The headers of an init as a plain object. A `Headers` object and a list of pairs, which are both\n * iterable, become the names and values the request sends: names in lowercase, a repeated one\n * joined with `, `, as `Headers` writes them. They are read without `Headers`, which threw for an\n * invalid name or value while the component rendered; the request reports it as a query error. A\n * plain object stays as it is, since its `null` and array values mean more than a string.\n */\nfunction plainHeaders(headers: object): HeadersRecord {\n if (!(Symbol.iterator in headers)) {\n return headers as HeadersRecord;\n }\n const record: Record<string, string> = {};\n for (const pair of headers as Iterable<unknown>) {\n const [name, value] = Array.from(pair as ArrayLike<unknown>);\n const key = String(name).toLowerCase();\n record[key] = key in record ? `${record[key]}, ${String(value)}` : String(value);\n }\n return record;\n}\n\n/**\n * The members of an object that are not `undefined`, or undefined when none is. A member set to\n * `undefined` (`headers: token ? … : undefined`, `query: { cursor: undefined }`) sends the same\n * request as none, and TanStack Query's hash leaves it out too, so a record of only such members\n * sends nothing and must not count as one. `null`, `[]` and `{}` members stay: `null` removes a\n * header, and a query serializer of the client may send them.\n */\nfunction definedMembers(record: object): Record<string, unknown> | undefined {\n const members = Object.entries(record).filter(([, value]) => value !== undefined);\n return members.length === 0 ? undefined : Object.fromEntries(members);\n}\n\n/**\n * The `params` of an init without the records that send nothing: `{}`, `{ query: {} }` and\n * `{ query: { cursor: undefined } }` send the request of no `params`, since the fetch client reads\n * a missing record as an empty one. Undefined when no record is left.\n */\nfunction paramsKey(params: unknown): unknown {\n if (!isPlainRecord(params)) {\n return params;\n }\n const records = Object.entries(params).map(([location, record]) => [\n location,\n isPlainRecord(record) ? definedMembers(record) : record,\n ]);\n return definedMembers(Object.fromEntries(records));\n}\n\n/** The headers of an init as `plainHeaders`, or undefined when they set none. */\nfunction headersKey(headers: unknown): unknown {\n return typeof headers === \"object\" && headers !== null\n ? definedMembers(plainHeaders(headers))\n : headers;\n}\n\n/**\n * The init of a query key: the request init with its params and headers without what sends\n * nothing, its body as `bodyKey`, and the client's key scope, or its base URL when the init has\n * none. The `signal` is left out: TanStack Query gives each request its own. Undefined when\n * nothing is left, so a call without an init and one with an init that sends nothing more, such\n * as `{}` or `{ params: { query: { cursor: undefined } } }`, have the key `[method, path]`.\n */\nexport function queryKeyInit(init: unknown, client: KeyClient): object | undefined {\n const { signal: _signal, ...rest } = (init ?? {}) as {\n signal?: unknown;\n params?: unknown;\n headers?: unknown;\n baseUrl?: unknown;\n body?: unknown;\n };\n const keyInit: Record<string, unknown> = {\n ...rest,\n params: paramsKey(rest.params),\n headers: headersKey(rest.headers),\n ...(rest.body === undefined ? {} : bodyKey(rest.body)),\n };\n if (client.keyScope !== undefined) {\n keyInit.keyScope = client.keyScope;\n } else if (!rest.baseUrl && client.baseUrl) {\n keyInit.baseUrl = client.baseUrl;\n }\n return definedMembers(keyInit);\n}\n","/**\n * The signal of a query's request. TanStack Query gives every request a signal, which it aborts\n * when the query is cancelled or no longer used; the init of the call may bring its own. The hooks\n * sent one of them: `useQuery` the call's, so a cancelled query kept its request, and\n * `useInfiniteQuery` TanStack's, so the call's signal did nothing. The request now stops when\n * either is aborted.\n */\n\n/** The init to send, and how to stop listening to the signals once the request has settled. */\nexport interface QueryRequest {\n readonly init: Record<string, unknown>;\n readonly release: () => void;\n}\n\nconst ABORT_EVENT = \"abort\";\n\nfunction withoutRelease(init: Record<string, unknown>): QueryRequest {\n return { init, release: () => undefined };\n}\n\n/** The init with a signal that aborts when the init's own signal or the query's does. */\nexport function withQuerySignal(init: unknown, querySignal: AbortSignal): QueryRequest {\n const { signal: ownSignal, ...rest } = (init ?? {}) as { signal?: AbortSignal | null };\n if (!ownSignal) {\n return withoutRelease({ ...rest, signal: querySignal });\n }\n const controller = new AbortController();\n const sources = [ownSignal, querySignal];\n const aborted = sources.find((source) => source.aborted);\n if (aborted !== undefined) {\n controller.abort(aborted.reason);\n return withoutRelease({ ...rest, signal: controller.signal });\n }\n const listeners = sources.map((source) => {\n const listener = () => controller.abort(source.reason);\n source.addEventListener(ABORT_EVENT, listener, { once: true });\n return () => source.removeEventListener(ABORT_EVENT, listener);\n });\n return {\n init: { ...rest, signal: controller.signal },\n release: () => {\n for (const remove of listeners) {\n remove();\n }\n },\n };\n}\n","import {\n type DataTag,\n type DefaultError,\n type DefinedUseQueryResult,\n type InfiniteData,\n type QueryClient,\n type QueryFunctionContext,\n type SkipToken,\n type UseInfiniteQueryOptions,\n type UseInfiniteQueryResult,\n type UseMutationOptions,\n type UseMutationResult,\n type UseQueryOptions,\n type UseQueryResult,\n type UseSuspenseQueryOptions,\n type UseSuspenseQueryResult,\n useInfiniteQuery,\n useMutation,\n useQuery,\n useSuspenseQuery,\n} from \"@tanstack/react-query\";\nimport type {\n ClientMethod,\n DefaultParamsOption,\n Client as FetchClient,\n FetchResponse,\n MaybeOptionalInit,\n PathOperation,\n} from \"openapi-typesafe-fetch\";\n// The helper types come from the client, which declares them: types inferred from the hooks then\n// print the client's `helpers` entry, of a peer every user has, and not `openapi-typesafe-helpers`,\n// which Yarn PnP does not let a library reach (ADR-034).\nimport type {\n HttpMethod,\n MediaType,\n PathsWithMethod,\n RequiredKeysOf,\n} from \"openapi-typesafe-fetch/helpers\";\nimport { queryKeyInit } from \"./query-key.js\";\nimport { withQuerySignal } from \"./query-signal.js\";\n\n// Helper type to dynamically infer the type from the `select` property\ntype InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;\n\n/**\n * Query data of a response type: a success without a body is `undefined` in the fetch client and\n * `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).\n */\ntype QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;\n\n/**\n * What the hooks throw when a request fails and the response has no error body: a non-OK status\n * with an empty body, a JSON `null` body, or one whose operation declares no content for it. The\n * fetch client gives `error: undefined` (or `null`) then; throwing that left `error` empty in\n * TanStack Query while its type said there was an error body. Tell it apart with\n * `isResponseError(error)`: `error instanceof Error` also matches a network or parse error. The\n * message names the status, not the URL, which can carry secrets.\n */\nexport interface ResponseError extends Error {\n readonly name: \"ResponseError\";\n /** The response that failed. */\n readonly response: Response;\n /** Its HTTP status, as `response.status`. */\n readonly status: number;\n}\n\n/**\n * The error of a hook: the error body of a failed response, a `ResponseError` when it has none, or\n * what the request threw before there was a response to read: a network error (`TypeError`), an\n * abort, a body that is not JSON (`SyntaxError`) or a middleware error. TanStack Query types that\n * last part as `DefaultError` (`Error` unless `Register` says otherwise; a registered `unknown`\n * makes the whole type `unknown`, as for TanStack's own hooks). `undefined` and `null` are left\n * out: a failed response without an error body throws a `ResponseError`.\n */\nexport type QueryError<ErrorBody> =\n | Exclude<ErrorBody, undefined | null>\n | ResponseError\n | DefaultError;\n\n/**\n * An object whose `queryKey` is tagged with the query's data and error types: the type that\n * TanStack Query 5.102 exports as `QueryKeyWithDataTag`, for the whole peer range. A named object\n * type, so the declarations of an exported `queryOptions` result print it by name. Spelled out,\n * the tag prints TanStack's `dataTagSymbol` keys, which a declaration file cannot import, and\n * the library's users get TS2304, or `any` cached data with `skipLibCheck`.\n */\nexport type QueryKeyWithDataTag<Key, Data, Error> = {\n queryKey: DataTag<Key, Data, Error>;\n};\n\ntype InitWithUnknowns<Init> = Init & { [key: string]: unknown };\n\n/**\n * The arguments after the path: the init, required when the operation requires a parameter or a\n * body, then `Rest`. The condition is openapi-react-query's, as `InitParam` of the fetch client\n * is openapi-fetch's (ADR-030, decision 2): TypeScript relates two conditional types only when\n * their `extends` types are the same, so a hook type copied from openapi-react-query takes these\n * hooks. For a union of inits, `MaybeOptionalInit` leaves out `undefined` when one is required,\n * so `Parameters<typeof $api.queryOptions>` still requires it then (upstream #2178).\n */\ntype InitArguments<Init, Rest extends unknown[]> =\n RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, ...Rest]\n : [InitWithUnknowns<Init>, ...Rest];\n\n/**\n * The key of a query: the method, the path and the request. Its init is the init of the call with\n * the headers and the body as plain values, and the client's `keyScope`, or its `baseUrl` when the\n * init has none, so two requests never share a key; it is left out when nothing is left. Read a\n * query's key from `queryOptions(...).queryKey` rather than writing it out.\n */\nexport type QueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init = MaybeOptionalInit<Paths[Path], Method>,\n> = Init extends undefined ? readonly [Method, Path] : readonly [Method, Path, Init];\n\n/**\n * The last element of an infinite query's key. `useQuery` and `useInfiniteQuery` cache different\n * data (`TData` and `InfiniteData<TData>`), so the same request must not share one key (upstream\n * #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported: it is not\n * needed outside the package, and a named export is public API; `InfiniteQueryKey` types the key.\n */\nconst INFINITE_QUERY_KEY_MARKER = \"infinite\";\n\nexport type InfiniteQueryKey<\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];\n\n/**\n * Whether the options give an `initialData` that is never `undefined`: a value, or a function that\n * never returns `undefined`. Then `data` is never `undefined` either, as for TanStack Query's own\n * `useQuery` with `DefinedInitialDataOptions`.\n */\ntype HasDefinedInitialData<Options> = Options extends { initialData: infer Initial }\n ? Initial extends (...args: never) => infer Returned\n ? undefined extends Returned\n ? false\n : true\n : undefined extends Initial\n ? false\n : true\n : false;\n\n/** The result of `useQuery`: its `data` is defined when the options give defined initial data. */\ntype QueryResult<Data, Error, Options> =\n HasDefinedInitialData<Options> extends true\n ? DefinedUseQueryResult<Data, Error>\n : UseQueryResult<Data, Error>;\n\n/**\n * A defined `initialData` of the options, in the type `queryOptions` returns, so TanStack Query's\n * `useQuery` takes the result as options with defined initial data. It is typed as the query data,\n * as TanStack's `DefinedInitialDataOptions` types it: the type of a literal such as `[{ id: 1 }]`\n * lacks the optional properties of the data, and TanStack's overload rejected it.\n */\ntype InitialDataOf<Options, Data> =\n HasDefinedInitialData<Options> extends true ? { initialData: Data | (() => Data) } : unknown;\n\nexport type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n path: Path,\n ...[init, options]: InitArguments<Init, [Options?]>\n) => NoInfer<\n Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > &\n QueryKeyWithDataTag<\n QueryKey<Paths, Method, Path>,\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>\n > &\n InitialDataOf<Options, QueryData<Response[\"data\"]>> & {\n queryFn: Exclude<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >[\"queryFn\"],\n SkipToken | undefined\n >;\n }\n>;\n\nexport type UseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => QueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>,\n Options\n>;\n\n/**\n * The type of the page params: the initial one and the ones `getNextPageParam` and\n * `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a\n * return type is untyped, so code that compiled still compiles (roadmap §3): TypeScript cannot\n * infer the return type of a callback that computes it from an unannotated `lastPageParam`,\n * whose type depends on that return type, and gives `never` or `unknown`.\n */\ntype PageParam<Initial, Next, Previous> =\n IsUntyped<Next> extends true\n ? unknown\n : [Previous] extends [NoPreviousPageParam]\n ? NullishToUnknown<Initial | NonNullable<Next>>\n : IsUntyped<Previous> extends true\n ? unknown\n : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;\n\n/** The `Previous` type parameter when the options have no `getPreviousPageParam`. */\ndeclare const NO_PREVIOUS_PAGE_PARAM: unique symbol;\ntype NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;\n\ntype IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;\n\n/** Only `undefined` or `null` names no type: a cursor API's `initialPageParam: undefined`. */\ntype NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;\n\n/** Read only for the return type; `never` arguments add no inference for TanStack's page param. */\ntype PageParamFunction<Result> = (...args: never) => Result;\n\n/**\n * Inference sites of the page param types. Intersected before `Options`, so TanStack's own\n * inference in the implementation reads the full signatures of `Options`.\n */\ninterface PageParamSources<Initial, Next, Previous> {\n initialPageParam: Initial;\n getNextPageParam: PageParamFunction<Next>;\n getPreviousPageParam?: PageParamFunction<Previous>;\n}\n\n/**\n * `placeholderData` of `useInfiniteQuery`, with an `unknown` page param as before: TypeScript types\n * a `(previousData) => previousData` callback while it still infers the page param, so it got\n * `unknown` there and failed against the typed page param.\n */\ntype InfinitePlaceholderData<\n Data,\n Error,\n Paths extends {},\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = UseInfiniteQueryOptions<\n Data,\n Error,\n InfiniteData<Data, unknown>,\n InfiniteQueryKey<Paths, Method, Path>,\n unknown\n>[\"placeholderData\"];\n\nexport type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseInfiniteQueryOptions<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n InfiniteQueryKey<Paths, Method, Path>,\n PageParam<Initial, Next, Previous>\n >,\n \"queryKey\" | \"queryFn\" | \"placeholderData\"\n > & {\n placeholderData?: InfinitePlaceholderData<\n Response[\"data\"],\n QueryError<Response[\"error\"]>,\n Paths,\n Method,\n Path\n >;\n pageParamName?: string;\n },\n Initial = unknown,\n Next = never,\n Previous = NoPreviousPageParam,\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n>(\n method: Method,\n url: Path,\n init: InitWithUnknowns<Init>,\n options: PageParamSources<Initial, Next, Previous> & Options,\n queryClient?: QueryClient,\n) => UseInfiniteQueryResult<\n InferSelectReturnType<\n InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>,\n Options[\"select\"]\n >,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n Options extends Omit<\n UseSuspenseQueryOptions<\n QueryData<Response[\"data\"]>,\n QueryError<Response[\"error\"]>,\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n url: Path,\n ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>\n) => UseSuspenseQueryResult<\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryError<Response[\"error\"]>\n>;\n\nexport type UseMutationMethod<Paths extends {}, Media extends MediaType> = <\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n Init extends MaybeOptionalInit<Paths[Path], Method>,\n // note: Required is used to avoid repeating NonNullable in UseQuery types\n Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], QueryError<Response[\"error\"]>, Init, TOnMutateResult>;\n\nexport interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {\n queryOptions: QueryOptionsFunction<Paths, Media>;\n useQuery: UseQueryMethod<Paths, Media>;\n useSuspenseQuery: UseSuspenseQueryMethod<Paths, Media>;\n useInfiniteQuery: UseInfiniteQueryMethod<Paths, Media>;\n useMutation: UseMutationMethod<Paths, Media>;\n}\n\nexport type MethodResponse<\n // biome-ignore lint/suspicious/noExplicitAny: matches a client of any paths, as upstream's\n CreatedClient extends OpenapiQueryClient<any, any>,\n Method extends HttpMethod,\n Path extends CreatedClient extends OpenapiQueryClient<infer Paths, infer _Media>\n ? PathsWithMethod<Paths, Method>\n : never,\n Options = object,\n> =\n CreatedClient extends OpenapiQueryClient<\n // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces\n infer Paths extends { [key: string]: any },\n infer Media extends MediaType\n >\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/** The `name` of every `ResponseError`. */\nconst RESPONSE_ERROR_NAME = \"ResponseError\";\n\n/** The `ResponseError` of a failed response without an error body. */\nclass ResponseWithoutErrorBody extends Error implements ResponseError {\n override readonly name = RESPONSE_ERROR_NAME;\n readonly response: Response;\n readonly status: number;\n\n constructor(response: Response) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n super(`Request failed with status ${response.status}${statusText} and no error body`);\n this.response = response;\n this.status = response.status;\n }\n}\n\n/**\n * Whether `error` is the `ResponseError` of a failed response without an error body. It narrows a\n * hook's `error`, where `error instanceof Error` also matches network and parse errors. It checks\n * the `name`, not the class, so a `ResponseError` of another copy of this package (its CommonJS and\n * ES module builds loaded side by side) is one too. An error body from JSON is never an `Error`.\n */\nexport function isResponseError(error: unknown): error is ResponseError {\n return error instanceof Error && error.name === RESPONSE_ERROR_NAME;\n}\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response\n * with an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as\n * `0`. Without an error body a `ResponseError` is thrown, so the hooks' `error` is never\n * `undefined` (ADR-013, decision 3). A JSON `null` body is no error body either: thrown as is, it\n * left `error` `null` while the query's status was `\"error\"`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined && result.error !== null) {\n throw result.error;\n }\n if (!result.response.ok) {\n throw new ResponseWithoutErrorBody(result.response);\n }\n}\n\n/** The query parameter that carries the page param unless `pageParamName` names another. */\nconst DEFAULT_PAGE_PARAM_NAME = \"cursor\";\n\ninterface PageRequest {\n readonly pageParamName: string;\n readonly pageParam: unknown;\n}\n\n/**\n * The request init of one page. An `undefined` page param (the first page with\n * `initialPageParam: undefined`) is left out instead of being sent as `0` (upstream #2715, #2340,\n * ADR-022), so a cursor API gets no cursor on the first page.\n */\nfunction pageInit(init: unknown, { pageParamName, pageParam }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n/** Options of `createClient`. */\nexport interface CreateClientOptions {\n /**\n * The name of the API in every query key, in place of the fetch client's `baseUrl`. Give the\n * same name where the server and the browser reach one API by different URLs, so the browser\n * reads the data the server rendered with; give different names to clients of one base URL that\n * fetch different data, such as one per tenant header.\n */\n keyScope?: string;\n}\n\n/**\n * Hooks and query options for a fetch client. A `QueryClient` other than the one from the React\n * context is passed to each hook as its last argument; `createClient` does not take one.\n */\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: inherited, kept until 1.1 (ADR-036)\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n { keyScope }: CreateClientOptions = {},\n): OpenapiQueryClient<Paths, Media> {\n const keyClient = { baseUrl: client.baseUrl, keyScope };\n /**\n * Send one request of a query: the call's own init, with a signal that TanStack Query can abort.\n * The key only names the cache entry, as for `useInfiniteQuery`: a function in the init (a\n * `fetch`, a `middleware`) cannot be part of a key, so the request is read from the call.\n */\n const fetchPage = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>(\n method: Method,\n path: Path,\n init: unknown,\n signal: AbortSignal,\n ) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const request = withQuerySignal(init, signal);\n try {\n // The init is `unknown` here. An `any` init lets the call infer the generic response type\n // that `queryOptions` declares; a typed init makes TypeScript compare two unresolved\n // conditional types, which it cannot do.\n // biome-ignore lint/suspicious/noExplicitAny: see the comment above\n const result = await fn(path, request.init as any);\n throwIfFailed(result);\n return result.data;\n } finally {\n request.release();\n }\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => {\n const keyInit = queryKeyInit(init, keyClient);\n return {\n queryKey: (keyInit === undefined\n ? ([method, path] as const)\n : ([method, path, keyInit] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the data type\n any,\n // biome-ignore lint/suspicious/noExplicitAny: the declared return type sets the error type\n any\n >,\n // TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for\n // every success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD\n // request (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.\n queryFn: async ({ signal }: QueryFunctionContext) =>\n (await fetchPage(method, path, init, signal)) ?? null,\n // Without options, `Options` is its constraint, which has no `initialData` to keep.\n ...(options as typeof options & {}),\n // The declared type types a defined `initialData` as the query data, a conditional type of\n // the generic options that TypeScript cannot relate to the object; it is the same object.\n } as never;\n };\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n // TanStack Query's `useQuery` returns `DefinedUseQueryResult` for options with defined\n // `initialData`; while `Options` is generic it cannot pick that overload, and the declared\n // `QueryResult` gives the caller the same answer. Both are the same object at runtime.\n useQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ) as never,\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(\n queryOptions(method, path, init as InitWithUnknowns<typeof init>, options),\n queryClient,\n ),\n // biome-ignore lint/complexity/useMaxParams: public signature of 1.x (ADR-036)\n useInfiniteQuery: (method, path, init, options, queryClient) => {\n const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;\n const { queryKey } = queryOptions(method, path, init);\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // An empty page stays `undefined`, as in upstream: TanStack Query rejects only\n // `undefined` query data, and the infinite query data is the `{ pages }` object.\n queryFn: ({ pageParam, signal }) =>\n fetchPage(method, path, pageInit(init, { pageParamName, pageParam }), signal),\n ...restOptions,\n // Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack\n // passes the previous data of this query, with its own page params, and takes it back.\n // biome-ignore lint/suspicious/noExplicitAny: TanStack's type carries its own page params\n placeholderData: placeholderData as any,\n },\n queryClient,\n );\n },\n useMutation: (method, path, options, queryClient) =>\n useMutation(\n {\n mutationKey: [method, path],\n mutationFn: async (init) => {\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n const result = await fn(path, init as InitWithUnknowns<typeof init>);\n throwIfFailed(result);\n // TanStack Query accepts `undefined` mutation data, so a success without a body stays\n // `undefined`, as in upstream; only query data needs `null` (upstream #2234). The cast\n // only bridges the generic types: `Response[\"data\"]` still has `undefined` for an\n // operation with a response without a body.\n const { data } = result;\n return data as Exclude<typeof data, undefined>;\n },\n ...options,\n },\n queryClient,\n ),\n };\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openapi-typesafe-react-query",
3
3
  "description": "Fast, type-safe @tanstack/react-query client to work with your OpenAPI schema.",
4
- "version": "1.0.0-rc.5",
4
+ "version": "1.0.0-rc.7",
5
5
  "author": {
6
6
  "name": "Fedor Chishchin",
7
7
  "url": "https://github.com/fedorello"
@@ -58,9 +58,9 @@
58
58
  "@vitejs/plugin-react": "6.2.1",
59
59
  "jsdom": "31.0.0",
60
60
  "msw": "3.0.3",
61
- "openapi-typesafe": "^1.0.0-rc.5",
62
- "openapi-typesafe-fetch": "^1.0.0-rc.5",
63
- "openapi-typesafe-helpers": "^1.0.0-rc.5",
61
+ "openapi-typesafe": "^1.0.0-rc.7",
62
+ "openapi-typesafe-fetch": "^1.0.0-rc.7",
63
+ "openapi-typesafe-helpers": "^1.0.0-rc.7",
64
64
  "react": "19.3.1",
65
65
  "react-dom": "19.3.1",
66
66
  "react-error-boundary": "6.1.6",
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "peerDependencies": {
70
70
  "@tanstack/react-query": "^5.80.0",
71
- "openapi-typesafe-fetch": "^1.0.0-rc.5"
71
+ "openapi-typesafe-fetch": "^1.0.0-rc.7"
72
72
  },
73
73
  "engines": {
74
74
  "node": ">=22"
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The body part of a query key (ADR-046). TanStack Query hashes a key as JSON, which writes a
3
+ * FormData, a Blob, an ArrayBuffer or a URLSearchParams as `{}`, as the whole body or as a field
4
+ * of an object body (a multipart body written as `{ image: file }`). The key holds each such value
5
+ * by its content and names its kind beside the body, so the key names what is sent.
6
+ */
7
+
8
+ /** `[object Name]`: the type tag is between these indexes of `Object.prototype.toString`. */
9
+ const TYPE_TAG_START = "[object ".length;
10
+ const TYPE_TAG_END = -1;
11
+
12
+ /** The kind of a value that JSON cannot hold. */
13
+ type RawKind = "URLSearchParams" | "FormData" | "Blob" | "bytes";
14
+
15
+ /**
16
+ * The kinds of the values JSON cannot hold in a body: the kind of a body that is one, or, for an
17
+ * object or an array body, the kinds of its members by their names or indexes, only where there
18
+ * are some.
19
+ */
20
+ type BodyKinds = RawKind | { readonly [member: string]: BodyKinds };
21
+
22
+ /** A body as a value TanStack Query hashes, and the kinds of the values JSON cannot hold in it. */
23
+ export interface BodyKey {
24
+ readonly body: unknown;
25
+ readonly bodyType?: BodyKinds;
26
+ }
27
+
28
+ /**
29
+ * Whether a value is of the class `name`: an instance of this realm's global class of that name
30
+ * (React Native's classes have no type tag), or a value with its type tag (a class of another
31
+ * realm or of the `undici` package), as the fetch client tells bodies (ADR-030).
32
+ */
33
+ function isClass(value: object, name: string): boolean {
34
+ const type = (globalThis as Record<string, unknown>)[name];
35
+ return (
36
+ (typeof type === "function" && value instanceof type) ||
37
+ Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name
38
+ );
39
+ }
40
+
41
+ /**
42
+ * Whether a value is an object literal, whose members JSON writes. A Date or another class has
43
+ * its own JSON form, which the key keeps.
44
+ */
45
+ export function isPlainRecord(value: unknown): value is Readonly<Record<string, unknown>> {
46
+ if (typeof value !== "object" || value === null) {
47
+ return false;
48
+ }
49
+ const prototype: unknown = Object.getPrototypeOf(value);
50
+ return prototype === Object.prototype || prototype === null;
51
+ }
52
+
53
+ /**
54
+ * A Blob or a File in a key: its type, size, and the name of a File. Its bytes cannot be read while
55
+ * the component renders, so two Blobs of the same type and size share an entry. The date of a File
56
+ * is left out: `FormData.append` and `new File` set it to the current time, so a body built while
57
+ * rendering got a new key, and a new request, on every render.
58
+ */
59
+ function blobKey(blob: Blob): object {
60
+ const { name } = blob as Partial<File>;
61
+ return { type: blob.type, size: blob.size, name };
62
+ }
63
+
64
+ /** The fields of a FormData in a key, in order, with a file as `blobKey`. */
65
+ function formDataKey(form: FormData): unknown[] {
66
+ // React Native's FormData has no `entries`, so its fields cannot be read.
67
+ if (typeof form.entries !== "function") {
68
+ return [];
69
+ }
70
+ return Array.from(form.entries(), ([name, value]) => [
71
+ name,
72
+ typeof value === "string" ? value : blobKey(value),
73
+ ]);
74
+ }
75
+
76
+ /** The bytes of an ArrayBuffer or a typed array, or null for another value. */
77
+ function valueBytes(value: object): Uint8Array | null {
78
+ if (ArrayBuffer.isView(value)) {
79
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
80
+ }
81
+ return isClass(value, "ArrayBuffer") ? new Uint8Array(value as ArrayBuffer) : null;
82
+ }
83
+
84
+ /**
85
+ * A value that JSON cannot hold, by its content: a URLSearchParams as its text, a FormData as its
86
+ * fields, a Blob as `blobKey` and bytes as their numbers. Undefined for any other value.
87
+ */
88
+ function rawValueKey(value: object): BodyKey | undefined {
89
+ if (isClass(value, "URLSearchParams")) {
90
+ return { body: String(value), bodyType: "URLSearchParams" };
91
+ }
92
+ if (isClass(value, "FormData")) {
93
+ return { body: formDataKey(value as FormData), bodyType: "FormData" };
94
+ }
95
+ if (isClass(value, "Blob") || isClass(value, "File")) {
96
+ return { body: blobKey(value as Blob), bodyType: "Blob" };
97
+ }
98
+ const bytes = valueBytes(value);
99
+ return bytes === null ? undefined : { body: Array.from(bytes), bodyType: "bytes" };
100
+ }
101
+
102
+ /**
103
+ * The members of an object or an array body, each as `bodyKey`, and their kinds by name or index.
104
+ * An empty object or array stays: a JSON `{}` or `[]` is a body, unlike none.
105
+ */
106
+ function membersKey(members: object): BodyKey {
107
+ const body: Record<string, unknown> | unknown[] = Array.isArray(members) ? [] : {};
108
+ const kinds: Record<string, BodyKinds> = {};
109
+ for (const [name, value] of Object.entries(members)) {
110
+ const member = bodyKey(value);
111
+ (body as Record<string, unknown>)[name] = member.body;
112
+ if (member.bodyType !== undefined) {
113
+ kinds[name] = member.bodyType;
114
+ }
115
+ }
116
+ return Object.keys(kinds).length === 0 ? { body } : { body, bodyType: kinds };
117
+ }
118
+
119
+ /**
120
+ * A body in a key: a value JSON cannot hold by its content, wherever it is in the body, and the
121
+ * kinds of such values in `bodyType`, a field no init has. A JSON body has no `bodyType`, so it
122
+ * never shares a key with a body that holds such a value written as the same JSON.
123
+ */
124
+ export function bodyKey(body: unknown): BodyKey {
125
+ if (Array.isArray(body) || isPlainRecord(body)) {
126
+ return membersKey(body);
127
+ }
128
+ const raw = typeof body === "object" && body !== null ? rawValueKey(body) : undefined;
129
+ return raw ?? { body };
130
+ }
package/src/query-key.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  * plain values, and the base URL the request goes to or the client's key scope, so the key names
8
8
  * what was fetched.
9
9
  */
10
+ import { bodyKey, isPlainRecord } from "./body-key.js";
10
11
 
11
12
  /** Headers as a plain object, which TanStack Query hashes by its names and values. */
12
13
  type HeadersRecord = Readonly<Record<string, unknown>>;
@@ -19,23 +20,6 @@ export interface KeyClient {
19
20
  readonly keyScope?: string | undefined;
20
21
  }
21
22
 
22
- /** `[object Name]`: the type tag is between these indexes of `Object.prototype.toString`. */
23
- const TYPE_TAG_START = "[object ".length;
24
- const TYPE_TAG_END = -1;
25
-
26
- /**
27
- * Whether a value is of the class `name`: an instance of this realm's global class of that name
28
- * (React Native's classes have no type tag), or a value with its type tag (a class of another
29
- * realm or of the `undici` package), as the fetch client tells bodies (ADR-030).
30
- */
31
- function isClass(value: object, name: string): boolean {
32
- const type = (globalThis as Record<string, unknown>)[name];
33
- return (
34
- (typeof type === "function" && value instanceof type) ||
35
- Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name
36
- );
37
- }
38
-
39
23
  /**
40
24
  * The headers of an init as a plain object. A `Headers` object and a list of pairs, which are both
41
25
  * iterable, become the names and values the request sends: names in lowercase, a repeated one
@@ -57,80 +41,65 @@ function plainHeaders(headers: object): HeadersRecord {
57
41
  }
58
42
 
59
43
  /**
60
- * A Blob or a File in a key: its type, size, and the name and date of a File. Its bytes cannot be
61
- * read while the component renders, so two Blobs of the same type and size share an entry.
44
+ * The members of an object that are not `undefined`, or undefined when none is. A member set to
45
+ * `undefined` (`headers: token ? … : undefined`, `query: { cursor: undefined }`) sends the same
46
+ * request as none, and TanStack Query's hash leaves it out too, so a record of only such members
47
+ * sends nothing and must not count as one. `null`, `[]` and `{}` members stay: `null` removes a
48
+ * header, and a query serializer of the client may send them.
62
49
  */
63
- function blobKey(blob: Blob): object {
64
- const { name, lastModified } = blob as Partial<File>;
65
- return { type: blob.type, size: blob.size, name, lastModified };
50
+ function definedMembers(record: object): Record<string, unknown> | undefined {
51
+ const members = Object.entries(record).filter(([, value]) => value !== undefined);
52
+ return members.length === 0 ? undefined : Object.fromEntries(members);
66
53
  }
67
54
 
68
- /** The fields of a FormData in a key, in order, with a file as `blobKey`. */
69
- function formDataKey(form: FormData): unknown[] {
70
- // React Native's FormData has no `entries`, so its fields cannot be read.
71
- if (typeof form.entries !== "function") {
72
- return [];
55
+ /**
56
+ * The `params` of an init without the records that send nothing: `{}`, `{ query: {} }` and
57
+ * `{ query: { cursor: undefined } }` send the request of no `params`, since the fetch client reads
58
+ * a missing record as an empty one. Undefined when no record is left.
59
+ */
60
+ function paramsKey(params: unknown): unknown {
61
+ if (!isPlainRecord(params)) {
62
+ return params;
73
63
  }
74
- return Array.from(form.entries(), ([name, value]) => [
75
- name,
76
- typeof value === "string" ? value : blobKey(value),
64
+ const records = Object.entries(params).map(([location, record]) => [
65
+ location,
66
+ isPlainRecord(record) ? definedMembers(record) : record,
77
67
  ]);
68
+ return definedMembers(Object.fromEntries(records));
78
69
  }
79
70
 
80
- /** The bytes of an ArrayBuffer or a typed array, or null for another value. */
81
- function bodyBytes(body: object): Uint8Array | null {
82
- if (ArrayBuffer.isView(body)) {
83
- return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
84
- }
85
- return isClass(body, "ArrayBuffer") ? new Uint8Array(body as ArrayBuffer) : null;
71
+ /** The headers of an init as `plainHeaders`, or undefined when they set none. */
72
+ function headersKey(headers: unknown): unknown {
73
+ return typeof headers === "object" && headers !== null
74
+ ? definedMembers(plainHeaders(headers))
75
+ : headers;
86
76
  }
87
77
 
88
78
  /**
89
- * A request body as a value TanStack Query hashes by its content. A URLSearchParams is its text,
90
- * a FormData its fields, a Blob `blobKey` and bytes their numbers, each under its kind, so it
91
- * differs from a JSON body with the same content. Other values stay as they are.
92
- */
93
- function bodyKey(body: unknown): unknown {
94
- if (typeof body !== "object" || body === null) {
95
- return body;
96
- }
97
- if (isClass(body, "URLSearchParams")) {
98
- return { URLSearchParams: String(body) };
99
- }
100
- if (isClass(body, "FormData")) {
101
- return { FormData: formDataKey(body as FormData) };
102
- }
103
- if (isClass(body, "Blob") || isClass(body, "File")) {
104
- return { Blob: blobKey(body as Blob) };
105
- }
106
- const bytes = bodyBytes(body);
107
- return bytes === null ? body : { bytes: Array.from(bytes) };
108
- }
109
-
110
- /**
111
- * The init of a query key: the request init with its headers and body as plain values, and the
112
- * client's key scope, or its base URL when the init has none. The `signal` is left out: TanStack
113
- * Query gives each request its own. Undefined when nothing is left, so a call without an init and
114
- * one with an empty init have the key `[method, path]`.
79
+ * The init of a query key: the request init with its params and headers without what sends
80
+ * nothing, its body as `bodyKey`, and the client's key scope, or its base URL when the init has
81
+ * none. The `signal` is left out: TanStack Query gives each request its own. Undefined when
82
+ * nothing is left, so a call without an init and one with an init that sends nothing more, such
83
+ * as `{}` or `{ params: { query: { cursor: undefined } } }`, have the key `[method, path]`.
115
84
  */
116
85
  export function queryKeyInit(init: unknown, client: KeyClient): object | undefined {
117
86
  const { signal: _signal, ...rest } = (init ?? {}) as {
118
87
  signal?: unknown;
88
+ params?: unknown;
119
89
  headers?: unknown;
120
90
  baseUrl?: unknown;
121
91
  body?: unknown;
122
92
  };
123
- const keyInit: Record<string, unknown> = { ...rest };
124
- if (typeof rest.headers === "object" && rest.headers !== null) {
125
- keyInit.headers = plainHeaders(rest.headers);
126
- }
127
- if ("body" in rest) {
128
- keyInit.body = bodyKey(rest.body);
129
- }
93
+ const keyInit: Record<string, unknown> = {
94
+ ...rest,
95
+ params: paramsKey(rest.params),
96
+ headers: headersKey(rest.headers),
97
+ ...(rest.body === undefined ? {} : bodyKey(rest.body)),
98
+ };
130
99
  if (client.keyScope !== undefined) {
131
100
  keyInit.keyScope = client.keyScope;
132
101
  } else if (!rest.baseUrl && client.baseUrl) {
133
102
  keyInit.baseUrl = client.baseUrl;
134
103
  }
135
- return Object.keys(keyInit).length === 0 ? undefined : keyInit;
104
+ return definedMembers(keyInit);
136
105
  }