openapi-typesafe-react-query 1.0.0-rc.3 → 1.0.0-rc.5
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 +416 -0
- package/README.md +11 -1
- package/dist/index.cjs +163 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -15
- package/dist/index.d.mts +91 -16
- package/dist/index.d.ts +91 -16
- package/dist/index.mjs +159 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -9
- package/src/index.ts +217 -79
- package/src/query-key.ts +136 -0
- package/src/query-signal.ts +47 -0
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { UseQueryOptions, DataTag, SkipToken, QueryClient, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
1
|
+
import { UseQueryOptions, DefaultError, DataTag, SkipToken, QueryClient, DefinedUseQueryResult, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
2
2
|
import { MaybeOptionalInit, FetchResponse, PathOperation, Client } from 'openapi-typesafe-fetch';
|
|
3
|
-
import { HttpMethod, PathsWithMethod, MediaType, RequiredKeysOf } from 'openapi-typesafe-helpers';
|
|
3
|
+
import { HttpMethod, PathsWithMethod, MediaType, RequiredKeysOf } from 'openapi-typesafe-fetch/helpers';
|
|
4
4
|
|
|
5
5
|
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;
|
|
6
6
|
/**
|
|
@@ -8,6 +8,40 @@ type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => in
|
|
|
8
8
|
* `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).
|
|
9
9
|
*/
|
|
10
10
|
type QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;
|
|
11
|
+
/**
|
|
12
|
+
* What the hooks throw when a request fails and the response has no error body: a non-OK status
|
|
13
|
+
* with an empty body, a JSON `null` body, or one whose operation declares no content for it. The
|
|
14
|
+
* fetch client gives `error: undefined` (or `null`) then; throwing that left `error` empty in
|
|
15
|
+
* TanStack Query while its type said there was an error body. Tell it apart with
|
|
16
|
+
* `isResponseError(error)`: `error instanceof Error` also matches a network or parse error. The
|
|
17
|
+
* message names the status, not the URL, which can carry secrets.
|
|
18
|
+
*/
|
|
19
|
+
interface ResponseError extends Error {
|
|
20
|
+
readonly name: "ResponseError";
|
|
21
|
+
/** The response that failed. */
|
|
22
|
+
readonly response: Response;
|
|
23
|
+
/** Its HTTP status, as `response.status`. */
|
|
24
|
+
readonly status: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The error of a hook: the error body of a failed response, a `ResponseError` when it has none, or
|
|
28
|
+
* what the request threw before there was a response to read: a network error (`TypeError`), an
|
|
29
|
+
* abort, a body that is not JSON (`SyntaxError`) or a middleware error. TanStack Query types that
|
|
30
|
+
* last part as `DefaultError` (`Error` unless `Register` says otherwise; a registered `unknown`
|
|
31
|
+
* makes the whole type `unknown`, as for TanStack's own hooks). `undefined` and `null` are left
|
|
32
|
+
* out: a failed response without an error body throws a `ResponseError`.
|
|
33
|
+
*/
|
|
34
|
+
type QueryError<ErrorBody> = Exclude<ErrorBody, undefined | null> | ResponseError | DefaultError;
|
|
35
|
+
/**
|
|
36
|
+
* An object whose `queryKey` is tagged with the query's data and error types: the type that
|
|
37
|
+
* TanStack Query 5.102 exports as `QueryKeyWithDataTag`, for the whole peer range. A named object
|
|
38
|
+
* type, so the declarations of an exported `queryOptions` result print it by name. Spelled out,
|
|
39
|
+
* the tag prints TanStack's `dataTagSymbol` keys, which a declaration file cannot import, and
|
|
40
|
+
* the library's users get TS2304, or `any` cached data with `skipLibCheck`.
|
|
41
|
+
*/
|
|
42
|
+
type QueryKeyWithDataTag<Key, Data, Error> = {
|
|
43
|
+
queryKey: DataTag<Key, Data, Error>;
|
|
44
|
+
};
|
|
11
45
|
type InitWithUnknowns<Init> = Init & {
|
|
12
46
|
[key: string]: unknown;
|
|
13
47
|
};
|
|
@@ -20,20 +54,44 @@ type InitWithUnknowns<Init> = Init & {
|
|
|
20
54
|
* so `Parameters<typeof $api.queryOptions>` still requires it then (upstream #2178).
|
|
21
55
|
*/
|
|
22
56
|
type InitArguments<Init, Rest extends unknown[]> = RequiredKeysOf<Init> extends never ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];
|
|
57
|
+
/**
|
|
58
|
+
* The key of a query: the method, the path and the request. Its init is the init of the call with
|
|
59
|
+
* the headers and the body as plain values, and the client's `keyScope`, or its `baseUrl` when the
|
|
60
|
+
* init has none, so two requests never share a key; it is left out when nothing is left. Read a
|
|
61
|
+
* query's key from `queryOptions(...).queryKey` rather than writing it out.
|
|
62
|
+
*/
|
|
23
63
|
type QueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init = MaybeOptionalInit<Paths[Path], Method>> = Init extends undefined ? readonly [Method, Path] : readonly [Method, Path, Init];
|
|
24
64
|
/**
|
|
25
65
|
* The last element of an infinite query's key. `useQuery` and `useInfiniteQuery` cache different
|
|
26
66
|
* data (`TData` and `InfiniteData<TData>`), so the same request must not share one key (upstream
|
|
27
|
-
* #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported:
|
|
28
|
-
*
|
|
67
|
+
* #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported: it is not
|
|
68
|
+
* needed outside the package, and a named export is public API; `InfiniteQueryKey` types the key.
|
|
29
69
|
*/
|
|
30
70
|
declare const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
31
71
|
type InfiniteQueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Whether the options give an `initialData` that is never `undefined`: a value, or a function that
|
|
74
|
+
* never returns `undefined`. Then `data` is never `undefined` either, as for TanStack Query's own
|
|
75
|
+
* `useQuery` with `DefinedInitialDataOptions`.
|
|
76
|
+
*/
|
|
77
|
+
type HasDefinedInitialData<Options> = Options extends {
|
|
78
|
+
initialData: infer Initial;
|
|
79
|
+
} ? Initial extends (...args: never) => infer Returned ? undefined extends Returned ? false : true : undefined extends Initial ? false : true : false;
|
|
80
|
+
/** The result of `useQuery`: its `data` is defined when the options give defined initial data. */
|
|
81
|
+
type QueryResult<Data, Error, Options> = HasDefinedInitialData<Options> extends true ? DefinedUseQueryResult<Data, Error> : UseQueryResult<Data, Error>;
|
|
82
|
+
/**
|
|
83
|
+
* A defined `initialData` of the options, in the type `queryOptions` returns, so TanStack Query's
|
|
84
|
+
* `useQuery` takes the result as options with defined initial data. It is typed as the query data,
|
|
85
|
+
* as TanStack's `DefinedInitialDataOptions` types it: the type of a literal such as `[{ id: 1 }]`
|
|
86
|
+
* lacks the optional properties of the data, and TanStack's overload rejected it.
|
|
87
|
+
*/
|
|
88
|
+
type InitialDataOf<Options, Data> = HasDefinedInitialData<Options> extends true ? {
|
|
89
|
+
initialData: Data | (() => Data);
|
|
90
|
+
} : unknown;
|
|
91
|
+
type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, path: Path, ...[init, options]: InitArguments<Init, [Options?]>) => NoInfer<Omit<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryFn" | "queryKey"> & QueryKeyWithDataTag<QueryKey<Paths, Method, Path>, QueryData<Response["data"]>, QueryError<Response["error"]>> & InitialDataOf<Options, QueryData<Response["data"]>> & {
|
|
92
|
+
queryFn: Exclude<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>["queryFn"], SkipToken | undefined>;
|
|
35
93
|
}>;
|
|
36
|
-
type UseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseQueryOptions<QueryData<Response["data"]>, Response["error"]
|
|
94
|
+
type UseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => QueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryError<Response["error"]>, Options>;
|
|
37
95
|
/**
|
|
38
96
|
* The type of the page params: the initial one and the ones `getNextPageParam` and
|
|
39
97
|
* `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a
|
|
@@ -65,12 +123,12 @@ interface PageParamSources<Initial, Next, Previous> {
|
|
|
65
123
|
* `unknown` there and failed against the typed page param.
|
|
66
124
|
*/
|
|
67
125
|
type InfinitePlaceholderData<Data, Error, Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = UseInfiniteQueryOptions<Data, Error, InfiniteData<Data, unknown>, InfiniteQueryKey<Paths, Method, Path>, unknown>["placeholderData"];
|
|
68
|
-
type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseInfiniteQueryOptions<Response["data"], Response["error"]
|
|
69
|
-
placeholderData?: InfinitePlaceholderData<Response["data"], Response["error"]
|
|
126
|
+
type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseInfiniteQueryOptions<Response["data"], QueryError<Response["error"]>, InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, InfiniteQueryKey<Paths, Method, Path>, PageParam<Initial, Next, Previous>>, "queryKey" | "queryFn" | "placeholderData"> & {
|
|
127
|
+
placeholderData?: InfinitePlaceholderData<Response["data"], QueryError<Response["error"]>, Paths, Method, Path>;
|
|
70
128
|
pageParamName?: string;
|
|
71
|
-
}, Initial = unknown, Next = never, Previous = NoPreviousPageParam>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: PageParamSources<Initial, Next, Previous> & Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, Response["error"]
|
|
72
|
-
type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseSuspenseQueryOptions<QueryData<Response["data"]>, Response["error"]
|
|
73
|
-
type UseMutationMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, TOnMutateResult = unknown>(method: Method, url: Path, options?: Omit<UseMutationOptions<Response["data"], Response["error"]
|
|
129
|
+
}, Initial = unknown, Next = never, Previous = NoPreviousPageParam>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: PageParamSources<Initial, Next, Previous> & Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, QueryError<Response["error"]>>;
|
|
130
|
+
type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseSuspenseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => UseSuspenseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryError<Response["error"]>>;
|
|
131
|
+
type UseMutationMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, TOnMutateResult = unknown>(method: Method, url: Path, options?: Omit<UseMutationOptions<Response["data"], QueryError<Response["error"]>, Init, TOnMutateResult>, "mutationKey" | "mutationFn">, queryClient?: QueryClient) => UseMutationResult<Response["data"], QueryError<Response["error"]>, Init, TOnMutateResult>;
|
|
74
132
|
interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
75
133
|
queryOptions: QueryOptionsFunction<Paths, Media>;
|
|
76
134
|
useQuery: UseQueryMethod<Paths, Media>;
|
|
@@ -81,11 +139,28 @@ interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaTy
|
|
|
81
139
|
type MethodResponse<CreatedClient extends OpenapiQueryClient<any, any>, Method extends HttpMethod, Path extends CreatedClient extends OpenapiQueryClient<infer Paths, infer _Media> ? PathsWithMethod<Paths, Method> : never, Options = object> = CreatedClient extends OpenapiQueryClient<infer Paths extends {
|
|
82
140
|
[key: string]: any;
|
|
83
141
|
}, infer Media extends MediaType> ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>["data"]> : never;
|
|
142
|
+
/**
|
|
143
|
+
* Whether `error` is the `ResponseError` of a failed response without an error body. It narrows a
|
|
144
|
+
* hook's `error`, where `error instanceof Error` also matches network and parse errors. It checks
|
|
145
|
+
* the `name`, not the class, so a `ResponseError` of another copy of this package (its CommonJS and
|
|
146
|
+
* ES module builds loaded side by side) is one too. An error body from JSON is never an `Error`.
|
|
147
|
+
*/
|
|
148
|
+
declare function isResponseError(error: unknown): error is ResponseError;
|
|
149
|
+
/** Options of `createClient`. */
|
|
150
|
+
interface CreateClientOptions {
|
|
151
|
+
/**
|
|
152
|
+
* The name of the API in every query key, in place of the fetch client's `baseUrl`. Give the
|
|
153
|
+
* same name where the server and the browser reach one API by different URLs, so the browser
|
|
154
|
+
* reads the data the server rendered with; give different names to clients of one base URL that
|
|
155
|
+
* fetch different data, such as one per tenant header.
|
|
156
|
+
*/
|
|
157
|
+
keyScope?: string;
|
|
158
|
+
}
|
|
84
159
|
/**
|
|
85
160
|
* Hooks and query options for a fetch client. A `QueryClient` other than the one from the React
|
|
86
161
|
* context is passed to each hook as its last argument; `createClient` does not take one.
|
|
87
162
|
*/
|
|
88
|
-
declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media
|
|
163
|
+
declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media>, { keyScope }?: CreateClientOptions): OpenapiQueryClient<Paths, Media>;
|
|
89
164
|
|
|
90
|
-
export { createClient as default };
|
|
91
|
-
export type { InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryKey, QueryOptionsFunction, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
|
165
|
+
export { createClient as default, isResponseError };
|
|
166
|
+
export type { CreateClientOptions, InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryError, QueryKey, QueryKeyWithDataTag, QueryOptionsFunction, ResponseError, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { UseQueryOptions, DataTag, SkipToken, QueryClient, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
1
|
+
import { UseQueryOptions, DefaultError, DataTag, SkipToken, QueryClient, DefinedUseQueryResult, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
2
2
|
import { MaybeOptionalInit, FetchResponse, PathOperation, Client } from 'openapi-typesafe-fetch';
|
|
3
|
-
import { HttpMethod, PathsWithMethod, MediaType, RequiredKeysOf } from 'openapi-typesafe-helpers';
|
|
3
|
+
import { HttpMethod, PathsWithMethod, MediaType, RequiredKeysOf } from 'openapi-typesafe-fetch/helpers';
|
|
4
4
|
|
|
5
5
|
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;
|
|
6
6
|
/**
|
|
@@ -8,6 +8,40 @@ type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => in
|
|
|
8
8
|
* `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).
|
|
9
9
|
*/
|
|
10
10
|
type QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;
|
|
11
|
+
/**
|
|
12
|
+
* What the hooks throw when a request fails and the response has no error body: a non-OK status
|
|
13
|
+
* with an empty body, a JSON `null` body, or one whose operation declares no content for it. The
|
|
14
|
+
* fetch client gives `error: undefined` (or `null`) then; throwing that left `error` empty in
|
|
15
|
+
* TanStack Query while its type said there was an error body. Tell it apart with
|
|
16
|
+
* `isResponseError(error)`: `error instanceof Error` also matches a network or parse error. The
|
|
17
|
+
* message names the status, not the URL, which can carry secrets.
|
|
18
|
+
*/
|
|
19
|
+
interface ResponseError extends Error {
|
|
20
|
+
readonly name: "ResponseError";
|
|
21
|
+
/** The response that failed. */
|
|
22
|
+
readonly response: Response;
|
|
23
|
+
/** Its HTTP status, as `response.status`. */
|
|
24
|
+
readonly status: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The error of a hook: the error body of a failed response, a `ResponseError` when it has none, or
|
|
28
|
+
* what the request threw before there was a response to read: a network error (`TypeError`), an
|
|
29
|
+
* abort, a body that is not JSON (`SyntaxError`) or a middleware error. TanStack Query types that
|
|
30
|
+
* last part as `DefaultError` (`Error` unless `Register` says otherwise; a registered `unknown`
|
|
31
|
+
* makes the whole type `unknown`, as for TanStack's own hooks). `undefined` and `null` are left
|
|
32
|
+
* out: a failed response without an error body throws a `ResponseError`.
|
|
33
|
+
*/
|
|
34
|
+
type QueryError<ErrorBody> = Exclude<ErrorBody, undefined | null> | ResponseError | DefaultError;
|
|
35
|
+
/**
|
|
36
|
+
* An object whose `queryKey` is tagged with the query's data and error types: the type that
|
|
37
|
+
* TanStack Query 5.102 exports as `QueryKeyWithDataTag`, for the whole peer range. A named object
|
|
38
|
+
* type, so the declarations of an exported `queryOptions` result print it by name. Spelled out,
|
|
39
|
+
* the tag prints TanStack's `dataTagSymbol` keys, which a declaration file cannot import, and
|
|
40
|
+
* the library's users get TS2304, or `any` cached data with `skipLibCheck`.
|
|
41
|
+
*/
|
|
42
|
+
type QueryKeyWithDataTag<Key, Data, Error> = {
|
|
43
|
+
queryKey: DataTag<Key, Data, Error>;
|
|
44
|
+
};
|
|
11
45
|
type InitWithUnknowns<Init> = Init & {
|
|
12
46
|
[key: string]: unknown;
|
|
13
47
|
};
|
|
@@ -20,20 +54,44 @@ type InitWithUnknowns<Init> = Init & {
|
|
|
20
54
|
* so `Parameters<typeof $api.queryOptions>` still requires it then (upstream #2178).
|
|
21
55
|
*/
|
|
22
56
|
type InitArguments<Init, Rest extends unknown[]> = RequiredKeysOf<Init> extends never ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];
|
|
57
|
+
/**
|
|
58
|
+
* The key of a query: the method, the path and the request. Its init is the init of the call with
|
|
59
|
+
* the headers and the body as plain values, and the client's `keyScope`, or its `baseUrl` when the
|
|
60
|
+
* init has none, so two requests never share a key; it is left out when nothing is left. Read a
|
|
61
|
+
* query's key from `queryOptions(...).queryKey` rather than writing it out.
|
|
62
|
+
*/
|
|
23
63
|
type QueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init = MaybeOptionalInit<Paths[Path], Method>> = Init extends undefined ? readonly [Method, Path] : readonly [Method, Path, Init];
|
|
24
64
|
/**
|
|
25
65
|
* The last element of an infinite query's key. `useQuery` and `useInfiniteQuery` cache different
|
|
26
66
|
* data (`TData` and `InfiniteData<TData>`), so the same request must not share one key (upstream
|
|
27
|
-
* #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported:
|
|
28
|
-
*
|
|
67
|
+
* #2184, ADR-022). A prefix such as `[method, path]` still matches both. Not exported: it is not
|
|
68
|
+
* needed outside the package, and a named export is public API; `InfiniteQueryKey` types the key.
|
|
29
69
|
*/
|
|
30
70
|
declare const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
31
71
|
type InfiniteQueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Whether the options give an `initialData` that is never `undefined`: a value, or a function that
|
|
74
|
+
* never returns `undefined`. Then `data` is never `undefined` either, as for TanStack Query's own
|
|
75
|
+
* `useQuery` with `DefinedInitialDataOptions`.
|
|
76
|
+
*/
|
|
77
|
+
type HasDefinedInitialData<Options> = Options extends {
|
|
78
|
+
initialData: infer Initial;
|
|
79
|
+
} ? Initial extends (...args: never) => infer Returned ? undefined extends Returned ? false : true : undefined extends Initial ? false : true : false;
|
|
80
|
+
/** The result of `useQuery`: its `data` is defined when the options give defined initial data. */
|
|
81
|
+
type QueryResult<Data, Error, Options> = HasDefinedInitialData<Options> extends true ? DefinedUseQueryResult<Data, Error> : UseQueryResult<Data, Error>;
|
|
82
|
+
/**
|
|
83
|
+
* A defined `initialData` of the options, in the type `queryOptions` returns, so TanStack Query's
|
|
84
|
+
* `useQuery` takes the result as options with defined initial data. It is typed as the query data,
|
|
85
|
+
* as TanStack's `DefinedInitialDataOptions` types it: the type of a literal such as `[{ id: 1 }]`
|
|
86
|
+
* lacks the optional properties of the data, and TanStack's overload rejected it.
|
|
87
|
+
*/
|
|
88
|
+
type InitialDataOf<Options, Data> = HasDefinedInitialData<Options> extends true ? {
|
|
89
|
+
initialData: Data | (() => Data);
|
|
90
|
+
} : unknown;
|
|
91
|
+
type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, path: Path, ...[init, options]: InitArguments<Init, [Options?]>) => NoInfer<Omit<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryFn" | "queryKey"> & QueryKeyWithDataTag<QueryKey<Paths, Method, Path>, QueryData<Response["data"]>, QueryError<Response["error"]>> & InitialDataOf<Options, QueryData<Response["data"]>> & {
|
|
92
|
+
queryFn: Exclude<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>["queryFn"], SkipToken | undefined>;
|
|
35
93
|
}>;
|
|
36
|
-
type UseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseQueryOptions<QueryData<Response["data"]>, Response["error"]
|
|
94
|
+
type UseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => QueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryError<Response["error"]>, Options>;
|
|
37
95
|
/**
|
|
38
96
|
* The type of the page params: the initial one and the ones `getNextPageParam` and
|
|
39
97
|
* `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a
|
|
@@ -65,12 +123,12 @@ interface PageParamSources<Initial, Next, Previous> {
|
|
|
65
123
|
* `unknown` there and failed against the typed page param.
|
|
66
124
|
*/
|
|
67
125
|
type InfinitePlaceholderData<Data, Error, Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = UseInfiniteQueryOptions<Data, Error, InfiniteData<Data, unknown>, InfiniteQueryKey<Paths, Method, Path>, unknown>["placeholderData"];
|
|
68
|
-
type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseInfiniteQueryOptions<Response["data"], Response["error"]
|
|
69
|
-
placeholderData?: InfinitePlaceholderData<Response["data"], Response["error"]
|
|
126
|
+
type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseInfiniteQueryOptions<Response["data"], QueryError<Response["error"]>, InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, InfiniteQueryKey<Paths, Method, Path>, PageParam<Initial, Next, Previous>>, "queryKey" | "queryFn" | "placeholderData"> & {
|
|
127
|
+
placeholderData?: InfinitePlaceholderData<Response["data"], QueryError<Response["error"]>, Paths, Method, Path>;
|
|
70
128
|
pageParamName?: string;
|
|
71
|
-
}, Initial = unknown, Next = never, Previous = NoPreviousPageParam>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: PageParamSources<Initial, Next, Previous> & Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, Response["error"]
|
|
72
|
-
type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseSuspenseQueryOptions<QueryData<Response["data"]>, Response["error"]
|
|
73
|
-
type UseMutationMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, TOnMutateResult = unknown>(method: Method, url: Path, options?: Omit<UseMutationOptions<Response["data"], Response["error"]
|
|
129
|
+
}, Initial = unknown, Next = never, Previous = NoPreviousPageParam>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: PageParamSources<Initial, Next, Previous> & Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, QueryError<Response["error"]>>;
|
|
130
|
+
type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, Options extends Omit<UseSuspenseQueryOptions<QueryData<Response["data"]>, QueryError<Response["error"]>, InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => UseSuspenseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryError<Response["error"]>>;
|
|
131
|
+
type UseMutationMethod<Paths extends {}, Media extends MediaType> = <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, TOnMutateResult = unknown>(method: Method, url: Path, options?: Omit<UseMutationOptions<Response["data"], QueryError<Response["error"]>, Init, TOnMutateResult>, "mutationKey" | "mutationFn">, queryClient?: QueryClient) => UseMutationResult<Response["data"], QueryError<Response["error"]>, Init, TOnMutateResult>;
|
|
74
132
|
interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
75
133
|
queryOptions: QueryOptionsFunction<Paths, Media>;
|
|
76
134
|
useQuery: UseQueryMethod<Paths, Media>;
|
|
@@ -81,11 +139,28 @@ interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaTy
|
|
|
81
139
|
type MethodResponse<CreatedClient extends OpenapiQueryClient<any, any>, Method extends HttpMethod, Path extends CreatedClient extends OpenapiQueryClient<infer Paths, infer _Media> ? PathsWithMethod<Paths, Method> : never, Options = object> = CreatedClient extends OpenapiQueryClient<infer Paths extends {
|
|
82
140
|
[key: string]: any;
|
|
83
141
|
}, infer Media extends MediaType> ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>["data"]> : never;
|
|
142
|
+
/**
|
|
143
|
+
* Whether `error` is the `ResponseError` of a failed response without an error body. It narrows a
|
|
144
|
+
* hook's `error`, where `error instanceof Error` also matches network and parse errors. It checks
|
|
145
|
+
* the `name`, not the class, so a `ResponseError` of another copy of this package (its CommonJS and
|
|
146
|
+
* ES module builds loaded side by side) is one too. An error body from JSON is never an `Error`.
|
|
147
|
+
*/
|
|
148
|
+
declare function isResponseError(error: unknown): error is ResponseError;
|
|
149
|
+
/** Options of `createClient`. */
|
|
150
|
+
interface CreateClientOptions {
|
|
151
|
+
/**
|
|
152
|
+
* The name of the API in every query key, in place of the fetch client's `baseUrl`. Give the
|
|
153
|
+
* same name where the server and the browser reach one API by different URLs, so the browser
|
|
154
|
+
* reads the data the server rendered with; give different names to clients of one base URL that
|
|
155
|
+
* fetch different data, such as one per tenant header.
|
|
156
|
+
*/
|
|
157
|
+
keyScope?: string;
|
|
158
|
+
}
|
|
84
159
|
/**
|
|
85
160
|
* Hooks and query options for a fetch client. A `QueryClient` other than the one from the React
|
|
86
161
|
* context is passed to each hook as its last argument; `createClient` does not take one.
|
|
87
162
|
*/
|
|
88
|
-
declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media
|
|
163
|
+
declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media>, { keyScope }?: CreateClientOptions): OpenapiQueryClient<Paths, Media>;
|
|
89
164
|
|
|
90
|
-
export { createClient as default };
|
|
91
|
-
export type { InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryKey, QueryOptionsFunction, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
|
165
|
+
export { createClient as default, isResponseError };
|
|
166
|
+
export type { CreateClientOptions, InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryError, QueryKey, QueryKeyWithDataTag, QueryOptionsFunction, ResponseError, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
package/dist/index.mjs
CHANGED
|
@@ -1,39 +1,174 @@
|
|
|
1
1
|
import { useMutation, useInfiniteQuery, useSuspenseQuery, useQuery } from '@tanstack/react-query';
|
|
2
2
|
|
|
3
|
+
const TYPE_TAG_START = "[object ".length;
|
|
4
|
+
const TYPE_TAG_END = -1;
|
|
5
|
+
function isClass(value, name) {
|
|
6
|
+
const type = globalThis[name];
|
|
7
|
+
return typeof type === "function" && value instanceof type || Object.prototype.toString.call(value).slice(TYPE_TAG_START, TYPE_TAG_END) === name;
|
|
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);
|
|
18
|
+
}
|
|
19
|
+
return record;
|
|
20
|
+
}
|
|
21
|
+
function blobKey(blob) {
|
|
22
|
+
const { name, lastModified } = blob;
|
|
23
|
+
return { type: blob.type, size: blob.size, name, lastModified };
|
|
24
|
+
}
|
|
25
|
+
function formDataKey(form) {
|
|
26
|
+
if (typeof form.entries !== "function") {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
return Array.from(form.entries(), ([name, value]) => [
|
|
30
|
+
name,
|
|
31
|
+
typeof value === "string" ? value : blobKey(value)
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
function bodyBytes(body) {
|
|
35
|
+
if (ArrayBuffer.isView(body)) {
|
|
36
|
+
return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
|
|
37
|
+
}
|
|
38
|
+
return isClass(body, "ArrayBuffer") ? new Uint8Array(body) : null;
|
|
39
|
+
}
|
|
40
|
+
function bodyKey(body) {
|
|
41
|
+
if (typeof body !== "object" || body === null) {
|
|
42
|
+
return body;
|
|
43
|
+
}
|
|
44
|
+
if (isClass(body, "URLSearchParams")) {
|
|
45
|
+
return { URLSearchParams: String(body) };
|
|
46
|
+
}
|
|
47
|
+
if (isClass(body, "FormData")) {
|
|
48
|
+
return { FormData: formDataKey(body) };
|
|
49
|
+
}
|
|
50
|
+
if (isClass(body, "Blob") || isClass(body, "File")) {
|
|
51
|
+
return { Blob: blobKey(body) };
|
|
52
|
+
}
|
|
53
|
+
const bytes = bodyBytes(body);
|
|
54
|
+
return bytes === null ? body : { bytes: Array.from(bytes) };
|
|
55
|
+
}
|
|
56
|
+
function queryKeyInit(init, client) {
|
|
57
|
+
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
|
+
}
|
|
65
|
+
if (client.keyScope !== void 0) {
|
|
66
|
+
keyInit.keyScope = client.keyScope;
|
|
67
|
+
} else if (!rest.baseUrl && client.baseUrl) {
|
|
68
|
+
keyInit.baseUrl = client.baseUrl;
|
|
69
|
+
}
|
|
70
|
+
return Object.keys(keyInit).length === 0 ? void 0 : keyInit;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const ABORT_EVENT = "abort";
|
|
74
|
+
function withoutRelease(init) {
|
|
75
|
+
return { init, release: () => void 0 };
|
|
76
|
+
}
|
|
77
|
+
function withQuerySignal(init, querySignal) {
|
|
78
|
+
const { signal: ownSignal, ...rest } = init ?? {};
|
|
79
|
+
if (!ownSignal) {
|
|
80
|
+
return withoutRelease({ ...rest, signal: querySignal });
|
|
81
|
+
}
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
const sources = [ownSignal, querySignal];
|
|
84
|
+
const aborted = sources.find((source) => source.aborted);
|
|
85
|
+
if (aborted !== void 0) {
|
|
86
|
+
controller.abort(aborted.reason);
|
|
87
|
+
return withoutRelease({ ...rest, signal: controller.signal });
|
|
88
|
+
}
|
|
89
|
+
const listeners = sources.map((source) => {
|
|
90
|
+
const listener = () => controller.abort(source.reason);
|
|
91
|
+
source.addEventListener(ABORT_EVENT, listener, { once: true });
|
|
92
|
+
return () => source.removeEventListener(ABORT_EVENT, listener);
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
init: { ...rest, signal: controller.signal },
|
|
96
|
+
release: () => {
|
|
97
|
+
for (const remove of listeners) {
|
|
98
|
+
remove();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
3
104
|
const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
105
|
+
const RESPONSE_ERROR_NAME = "ResponseError";
|
|
106
|
+
class ResponseWithoutErrorBody extends Error {
|
|
107
|
+
name = RESPONSE_ERROR_NAME;
|
|
108
|
+
response;
|
|
109
|
+
status;
|
|
110
|
+
constructor(response) {
|
|
111
|
+
const statusText = response.statusText ? ` ${response.statusText}` : "";
|
|
112
|
+
super(`Request failed with status ${response.status}${statusText} and no error body`);
|
|
113
|
+
this.response = response;
|
|
114
|
+
this.status = response.status;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function isResponseError(error) {
|
|
118
|
+
return error instanceof Error && error.name === RESPONSE_ERROR_NAME;
|
|
119
|
+
}
|
|
4
120
|
function throwIfFailed(result) {
|
|
5
|
-
if (result.error !== void 0
|
|
121
|
+
if (result.error !== void 0 && result.error !== null) {
|
|
6
122
|
throw result.error;
|
|
7
123
|
}
|
|
124
|
+
if (!result.response.ok) {
|
|
125
|
+
throw new ResponseWithoutErrorBody(result.response);
|
|
126
|
+
}
|
|
8
127
|
}
|
|
9
128
|
const DEFAULT_PAGE_PARAM_NAME = "cursor";
|
|
10
|
-
function pageInit(init, { pageParamName, pageParam
|
|
129
|
+
function pageInit(init, { pageParamName, pageParam }) {
|
|
11
130
|
const { params, ...rest } = init ?? {};
|
|
12
131
|
const page = pageParam === void 0 ? {} : { [pageParamName]: pageParam };
|
|
13
|
-
return { ...rest,
|
|
132
|
+
return { ...rest, params: { ...params, query: { ...params?.query, ...page } } };
|
|
14
133
|
}
|
|
15
|
-
function createClient(client) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
signal
|
|
19
|
-
}) => {
|
|
20
|
-
const [method, path, init] = queryKey;
|
|
134
|
+
function createClient(client, { keyScope } = {}) {
|
|
135
|
+
const keyClient = { baseUrl: client.baseUrl, keyScope };
|
|
136
|
+
const fetchPage = async (method, path, init, signal) => {
|
|
21
137
|
const mth = method.toUpperCase();
|
|
22
138
|
const fn = client[mth];
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
139
|
+
const request = withQuerySignal(init, signal);
|
|
140
|
+
try {
|
|
141
|
+
const result = await fn(path, request.init);
|
|
142
|
+
throwIfFailed(result);
|
|
143
|
+
return result.data;
|
|
144
|
+
} finally {
|
|
145
|
+
request.release();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const queryOptions = (method, path, ...[init, options]) => {
|
|
149
|
+
const keyInit = queryKeyInit(init, keyClient);
|
|
150
|
+
return {
|
|
151
|
+
queryKey: keyInit === void 0 ? [method, path] : [method, path, keyInit],
|
|
152
|
+
// TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for
|
|
153
|
+
// every success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD
|
|
154
|
+
// request (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.
|
|
155
|
+
queryFn: async ({ signal }) => await fetchPage(method, path, init, signal) ?? null,
|
|
156
|
+
// Without options, `Options` is its constraint, which has no `initialData` to keep.
|
|
157
|
+
...options
|
|
158
|
+
// The declared type types a defined `initialData` as the query data, a conditional type of
|
|
159
|
+
// the generic options that TypeScript cannot relate to the object; it is the same object.
|
|
160
|
+
};
|
|
26
161
|
};
|
|
27
|
-
const queryOptions = (method, path, ...[init, options]) => ({
|
|
28
|
-
queryKey: init === void 0 ? [method, path] : [method, path, init],
|
|
29
|
-
queryFn,
|
|
30
|
-
...options
|
|
31
|
-
});
|
|
32
162
|
return {
|
|
33
163
|
queryOptions,
|
|
34
|
-
useQuery: (method, path, ...[init, options, queryClient]) =>
|
|
35
|
-
|
|
36
|
-
|
|
164
|
+
useQuery: (method, path, ...[init, options, queryClient]) => (
|
|
165
|
+
// TanStack Query's `useQuery` returns `DefinedUseQueryResult` for options with defined
|
|
166
|
+
// `initialData`; while `Options` is generic it cannot pick that overload, and the declared
|
|
167
|
+
// `QueryResult` gives the caller the same answer. Both are the same object at runtime.
|
|
168
|
+
useQuery(
|
|
169
|
+
queryOptions(method, path, init, options),
|
|
170
|
+
queryClient
|
|
171
|
+
)
|
|
37
172
|
),
|
|
38
173
|
useSuspenseQuery: (method, path, ...[init, options, queryClient]) => useSuspenseQuery(
|
|
39
174
|
queryOptions(method, path, init, options),
|
|
@@ -43,21 +178,12 @@ function createClient(client) {
|
|
|
43
178
|
useInfiniteQuery: (method, path, init, options, queryClient) => {
|
|
44
179
|
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;
|
|
45
180
|
const { queryKey } = queryOptions(method, path, init);
|
|
46
|
-
const mth = method.toUpperCase();
|
|
47
|
-
const fn = client[mth];
|
|
48
181
|
return useInfiniteQuery(
|
|
49
182
|
{
|
|
50
183
|
queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER],
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
path,
|
|
55
|
-
// biome-ignore lint/suspicious/noExplicitAny: a generic init; see queryFn
|
|
56
|
-
pageInit(init, { pageParamName, pageParam, signal })
|
|
57
|
-
);
|
|
58
|
-
throwIfFailed(result);
|
|
59
|
-
return result.data;
|
|
60
|
-
},
|
|
184
|
+
// An empty page stays `undefined`, as in upstream: TanStack Query rejects only
|
|
185
|
+
// `undefined` query data, and the infinite query data is the `{ pages }` object.
|
|
186
|
+
queryFn: ({ pageParam, signal }) => fetchPage(method, path, pageInit(init, { pageParamName, pageParam }), signal),
|
|
61
187
|
...restOptions,
|
|
62
188
|
// Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack
|
|
63
189
|
// passes the previous data of this query, with its own page params, and takes it back.
|
|
@@ -85,5 +211,5 @@ function createClient(client) {
|
|
|
85
211
|
};
|
|
86
212
|
}
|
|
87
213
|
|
|
88
|
-
export { createClient as default };
|
|
214
|
+
export { createClient as default, isResponseError };
|
|
89
215
|
//# sourceMappingURL=index.mjs.map
|