openapi-typesafe-react-query 1.0.0-rc.0 → 1.0.0-rc.1
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/dist/index.cjs +8 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -13
- package/dist/index.d.mts +27 -12
- package/dist/index.d.ts +28 -13
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +129 -49
package/dist/index.cjs
CHANGED
|
@@ -16,18 +16,15 @@ function pageInit(init, { pageParamName, pageParam, signal }) {
|
|
|
16
16
|
}
|
|
17
17
|
function createClient(client) {
|
|
18
18
|
const queryFn = async ({
|
|
19
|
-
queryKey
|
|
19
|
+
queryKey,
|
|
20
20
|
signal
|
|
21
21
|
}) => {
|
|
22
|
+
const [method, path, init] = queryKey;
|
|
22
23
|
const mth = method.toUpperCase();
|
|
23
24
|
const fn = client[mth];
|
|
24
25
|
const result = await fn(path, { signal, ...init });
|
|
25
26
|
throwIfFailed(result);
|
|
26
|
-
|
|
27
|
-
if (response.status === 204 || response.headers.get("Content-Length") === "0") {
|
|
28
|
-
return data ?? null;
|
|
29
|
-
}
|
|
30
|
-
return data;
|
|
27
|
+
return result.data ?? null;
|
|
31
28
|
};
|
|
32
29
|
const queryOptions = (method, path, ...[init, options]) => ({
|
|
33
30
|
queryKey: init === void 0 ? [method, path] : [method, path, init],
|
|
@@ -39,7 +36,7 @@ function createClient(client) {
|
|
|
39
36
|
useQuery: (method, path, ...[init, options, queryClient]) => reactQuery.useQuery(queryOptions(method, path, init, options), queryClient),
|
|
40
37
|
useSuspenseQuery: (method, path, ...[init, options, queryClient]) => reactQuery.useSuspenseQuery(queryOptions(method, path, init, options), queryClient),
|
|
41
38
|
useInfiniteQuery: (method, path, init, options, queryClient) => {
|
|
42
|
-
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, ...restOptions } = options;
|
|
39
|
+
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;
|
|
43
40
|
const { queryKey } = queryOptions(method, path, init);
|
|
44
41
|
const mth = method.toUpperCase();
|
|
45
42
|
const fn = client[mth];
|
|
@@ -52,7 +49,10 @@ function createClient(client) {
|
|
|
52
49
|
throwIfFailed(result);
|
|
53
50
|
return result.data;
|
|
54
51
|
},
|
|
55
|
-
...restOptions
|
|
52
|
+
...restOptions,
|
|
53
|
+
// Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack
|
|
54
|
+
// passes the previous data of this query, with its own page params, and takes it back.
|
|
55
|
+
placeholderData
|
|
56
56
|
},
|
|
57
57
|
queryClient
|
|
58
58
|
);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import {\n type DataTag,\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} from \"openapi-typesafe-fetch\";\nimport type { HttpMethod, MediaType, PathsWithMethod, RequiredKeysOf } from \"openapi-typesafe-helpers\";\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\ntype InitWithUnknowns<Init> = Init & { [key: string]: unknown };\n\nexport type QueryKey<\n Paths extends Record<string, Record<HttpMethod, {}>>,\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: a runtime\n * named export next to the default export would change what `require()` returns.\n */\nconst INFINITE_QUERY_KEY_MARKER = \"infinite\";\n\nexport type InfiniteQueryKey<\n Paths extends Record<string, Record<HttpMethod, {}>>,\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];\n\nexport type QueryOptionsFunction<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<Response[\"data\"], Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n path: Path,\n ...[init, options]: RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, Options?]\n : [InitWithUnknowns<Init>, Options?]\n) => NoInfer<\n Omit<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<Response[\"data\"], Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > & {\n queryKey: DataTag<QueryKey<Paths, Method, Path>, Response[\"data\"], Response[\"error\"]>;\n queryFn: Exclude<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<Response[\"data\"], Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >[\"queryFn\"],\n SkipToken | undefined\n >;\n }\n>;\n\nexport type UseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<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]: RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, Options?, QueryClient?]\n : [InitWithUnknowns<Init>, Options?, QueryClient?]\n) => UseQueryResult<InferSelectReturnType<Response[\"data\"], Options[\"select\"]>, Response[\"error\"]>;\n\nexport type UseInfiniteQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>,\n Options extends Omit<\n UseInfiniteQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<InfiniteData<Response[\"data\"]>, Options[\"select\"]>,\n InfiniteQueryKey<Paths, Method, Path>,\n unknown\n >,\n \"queryKey\" | \"queryFn\"\n > & {\n pageParamName?: string;\n },\n>(\n method: Method,\n url: Path,\n init: InitWithUnknowns<Init>,\n options: Options,\n queryClient?: QueryClient,\n) => UseInfiniteQueryResult<\n InferSelectReturnType<InfiniteData<Response[\"data\"]>, Options[\"select\"]>,\n Response[\"error\"]\n>;\n\nexport type UseSuspenseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseSuspenseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<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]: RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, Options?, QueryClient?]\n : [InitWithUnknowns<Init>, Options?, QueryClient?]\n) => UseSuspenseQueryResult<InferSelectReturnType<Response[\"data\"], Options[\"select\"]>, Response[\"error\"]>;\n\nexport type UseMutationMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], Response[\"error\"], Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], 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 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<infer Paths extends { [key: string]: any }, infer Media extends MediaType>\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response with\n * an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as `0`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined || !result.response.ok) {\n throw result.error;\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 readonly signal: AbortSignal;\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, signal }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, signal, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n// TODO: Add the ability to bring queryClient as argument\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n): OpenapiQueryClient<Paths, Media> {\n const queryFn = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>({\n queryKey: [method, path, init],\n signal,\n }: QueryFunctionContext<QueryKey<Paths, Method, Path>>) => {\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, { signal, ...(init as any) }); // TODO: find a way to avoid as any\n throwIfFailed(result);\n const { data, response } = result;\n if (response.status === 204 || response.headers.get(\"Content-Length\") === \"0\") {\n return data ?? null;\n }\n\n return data;\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => ({\n queryKey: (init === undefined ? ([method, path] as const) : ([method, path, init] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n any,\n any\n >,\n queryFn,\n ...options,\n });\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n useQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\n useInfiniteQuery: (method, path, init, options, queryClient) => {\n const { pageParamName = DEFAULT_PAGE_PARAM_NAME, ...restOptions } = options;\n const { queryKey } = queryOptions(method, path, init);\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // The request comes from the arguments; the key only identifies the cache entry.\n queryFn: async ({ pageParam, signal }) => {\n const result = await fn(path, pageInit(init, { pageParamName, pageParam, signal }) as any);\n throwIfFailed(result);\n return result.data;\n },\n ...restOptions,\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 const { data } = result;\n\n return data as Exclude<typeof data, undefined>;\n },\n ...options,\n },\n queryClient,\n ),\n };\n}\n"],"names":["useQuery","useSuspenseQuery","useInfiniteQuery","useMutation"],"mappings":";;;;AA8CA,MAAM,yBAAA,GAA4B,UAAA;AAmKlC,SAAS,cAAc,MAAA,EAAuD;AAC5E,EAAA,IAAI,OAAO,KAAA,KAAU,MAAA,IAAa,CAAC,MAAA,CAAO,SAAS,EAAA,EAAI;AACrD,IAAA,MAAM,MAAA,CAAO,KAAA;AAAA,EACf;AACF;AAGA,MAAM,uBAAA,GAA0B,QAAA;AAahC,SAAS,SAAS,IAAA,EAAe,EAAE,aAAA,EAAe,SAAA,EAAW,QAAO,EAAgB;AAClF,EAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAK,GAAK,QAAQ,EAAC;AACtC,EAAA,MAAM,IAAA,GAAO,cAAc,MAAA,GAAY,KAAK,EAAE,CAAC,aAAa,GAAG,SAAA,EAAU;AACzE,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,EAAE,GAAG,MAAA,EAAQ,KAAA,EAAO,EAAE,GAAG,MAAA,EAAQ,KAAA,EAAO,GAAG,IAAA,IAAO,EAAE;AACxF;AAGA,SAAwB,aACtB,MAAA,EACkC;AAClC,EAAA,MAAM,UAAU,OAA+E;AAAA,IAC7F,QAAA,EAAU,CAAC,MAAA,EAAQ,IAAA,EAAM,IAAI,CAAA;AAAA,IAC7B;AAAA,GACF,KAA2D;AACzD,IAAA,MAAM,GAAA,GAAM,OAAO,WAAA,EAAY;AAC/B,IAAA,MAAM,EAAA,GAAK,OAAO,GAAG,CAAA;AACrB,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,IAAA,EAAM,EAAE,MAAA,EAAQ,GAAI,MAAc,CAAA;AAC1D,IAAA,aAAA,CAAc,MAAM,CAAA;AACpB,IAAA,MAAM,EAAE,IAAA,EAAM,QAAA,EAAS,GAAI,MAAA;AAC3B,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,IAAO,QAAA,CAAS,QAAQ,GAAA,CAAI,gBAAgB,MAAM,GAAA,EAAK;AAC7E,MAAA,OAAO,IAAA,IAAQ,IAAA;AAAA,IACjB;AAEA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,eAAmD,CAAC,MAAA,EAAQ,SAAS,CAAC,IAAA,EAAM,OAAO,CAAA,MAAO;AAAA,IAC9F,QAAA,EAAW,IAAA,KAAS,MAAA,GAAa,CAAC,MAAA,EAAQ,IAAI,CAAA,GAAe,CAAC,MAAA,EAAQ,IAAA,EAAM,IAAI,CAAA;AAAA,IAKhF,OAAA;AAAA,IACA,GAAG;AAAA,GACL,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,YAAA;AAAA,IACA,UAAU,CAAC,MAAA,EAAQ,IAAA,EAAA,GAAS,CAAC,MAAM,OAAA,EAAS,WAAW,CAAA,KACrDA,mBAAA,CAAS,aAAa,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAuC,OAAO,GAAG,WAAW,CAAA;AAAA,IAClG,kBAAkB,CAAC,MAAA,EAAQ,IAAA,EAAA,GAAS,CAAC,MAAM,OAAA,EAAS,WAAW,CAAA,KAC7DC,2BAAA,CAAiB,aAAa,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAuC,OAAO,GAAG,WAAW,CAAA;AAAA,IAC1G,kBAAkB,CAAC,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,SAAS,WAAA,KAAgB;AAC9D,MAAA,MAAM,EAAE,aAAA,GAAgB,uBAAA,EAAyB,GAAG,aAAY,GAAI,OAAA;AACpE,MAAA,MAAM,EAAE,QAAA,EAAS,GAAI,YAAA,CAAa,MAAA,EAAQ,MAAM,IAAI,CAAA;AACpD,MAAA,MAAM,GAAA,GAAM,OAAO,WAAA,EAAY;AAC/B,MAAA,MAAM,EAAA,GAAK,OAAO,GAAG,CAAA;AACrB,MAAA,OAAOC,2BAAA;AAAA,QACL;AAAA,UACE,QAAA,EAAU,CAAC,GAAG,QAAA,EAAU,yBAAyB,CAAA;AAAA;AAAA,UAEjD,OAAA,EAAS,OAAO,EAAE,SAAA,EAAW,QAAO,KAAM;AACxC,YAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,IAAA,EAAM,QAAA,CAAS,IAAA,EAAM,EAAE,aAAA,EAAe,SAAA,EAAW,MAAA,EAAQ,CAAQ,CAAA;AACzF,YAAA,aAAA,CAAc,MAAM,CAAA;AACpB,YAAA,OAAO,MAAA,CAAO,IAAA;AAAA,UAChB,CAAA;AAAA,UACA,GAAG;AAAA,SACL;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IACA,WAAA,EAAa,CAAC,MAAA,EAAQ,IAAA,EAAM,SAAS,WAAA,KACnCC,sBAAA;AAAA,MACE;AAAA,QACE,WAAA,EAAa,CAAC,MAAA,EAAQ,IAAI,CAAA;AAAA,QAC1B,UAAA,EAAY,OAAO,IAAA,KAAS;AAC1B,UAAA,MAAM,GAAA,GAAM,OAAO,WAAA,EAAY;AAC/B,UAAA,MAAM,EAAA,GAAK,OAAO,GAAG,CAAA;AACrB,UAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,IAAA,EAAM,IAAqC,CAAA;AACnE,UAAA,aAAA,CAAc,MAAM,CAAA;AACpB,UAAA,MAAM,EAAE,MAAK,GAAI,MAAA;AAEjB,UAAA,OAAO,IAAA;AAAA,QACT,CAAA;AAAA,QACA,GAAG;AAAA,OACL;AAAA,MACA;AAAA;AACF,GACJ;AACF;;"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import {\n type DataTag,\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 IsInitOptional,\n MaybeOptionalInit,\n PathOperation,\n} from \"openapi-typesafe-fetch\";\nimport type { HttpMethod, MediaType, PathsWithMethod } from \"openapi-typesafe-helpers\";\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\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`. `IsInitOptional` keeps the init optional in\n * `Parameters<typeof $api.queryOptions>`, where it is the union of all inits (upstream #2178).\n */\ntype InitArguments<Init, Rest extends unknown[]> =\n IsInitOptional<Init> extends true ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];\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: a runtime\n * named export next to the default export would change what `require()` returns.\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\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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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 Response[\"error\"],\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > & {\n queryKey: DataTag<QueryKey<Paths, Method, Path>, QueryData<Response[\"data\"]>, Response[\"error\"]>;\n queryFn: Exclude<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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) => UseQueryResult<InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>, Response[\"error\"]>;\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 Response[\"error\"],\n InferSelectReturnType<InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>, Options[\"select\"]>,\n InfiniteQueryKey<Paths, Method, Path>,\n PageParam<Initial, Next, Previous>\n >,\n \"queryKey\" | \"queryFn\" | \"placeholderData\"\n > & {\n placeholderData?: InfinitePlaceholderData<Response[\"data\"], Response[\"error\"], Paths, Method, Path>;\n pageParamName?: string;\n },\n Initial = unknown,\n Next = never,\n Previous = NoPreviousPageParam,\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<InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>, Options[\"select\"]>,\n 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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseSuspenseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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<InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>, Response[\"error\"]>;\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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], Response[\"error\"], Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], 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 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<infer Paths extends { [key: string]: any }, infer Media extends MediaType>\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response with\n * an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as `0`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined || !result.response.ok) {\n throw result.error;\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 readonly signal: AbortSignal;\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, signal }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, signal, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n// TODO: Add the ability to bring queryClient as argument\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n): OpenapiQueryClient<Paths, Media> {\n const queryFn = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>({\n queryKey,\n signal,\n }: QueryFunctionContext<QueryKey<Paths, Method, Path>>) => {\n // While `Path` is generic, TypeScript cannot work out that the key is a tuple: the init is a\n // conditional type per operation (`MaybeOptionalInit`), and the key's type waits for it.\n const [method, path, init] = queryKey as readonly [Method, Path, unknown?];\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, { signal, ...(init as any) }); // TODO: find a way to avoid as any\n throwIfFailed(result);\n // TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for every\n // success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD request\n // (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.\n return result.data ?? null;\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => ({\n queryKey: (init === undefined ? ([method, path] as const) : ([method, path, init] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n any,\n any\n >,\n queryFn,\n ...options,\n });\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n useQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\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 const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // The request comes from the arguments; the key only identifies the cache entry.\n queryFn: async ({ pageParam, signal }) => {\n const result = await fn(path, pageInit(init, { pageParamName, pageParam, signal }) as any);\n throwIfFailed(result);\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 return result.data;\n },\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 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.d.cts
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
import { UseQueryOptions, DataTag, SkipToken, QueryClient, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
2
|
-
import { MaybeOptionalInit, FetchResponse, Client } from 'openapi-typesafe-fetch';
|
|
3
|
-
import { HttpMethod, PathsWithMethod, MediaType
|
|
2
|
+
import { MaybeOptionalInit, FetchResponse, PathOperation, IsInitOptional, Client } from 'openapi-typesafe-fetch';
|
|
3
|
+
import { HttpMethod, PathsWithMethod, MediaType } from 'openapi-typesafe-helpers';
|
|
4
4
|
|
|
5
5
|
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;
|
|
6
|
+
type QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;
|
|
6
7
|
type InitWithUnknowns<Init> = Init & {
|
|
7
8
|
[key: string]: unknown;
|
|
8
9
|
};
|
|
9
|
-
type
|
|
10
|
+
type InitArguments<Init, Rest extends unknown[]> = IsInitOptional<Init> extends true ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];
|
|
11
|
+
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];
|
|
10
12
|
declare const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
11
|
-
type InfiniteQueryKey<Paths extends
|
|
12
|
-
type QueryOptionsFunction<Paths extends
|
|
13
|
-
queryKey: DataTag<QueryKey<Paths, Method, Path>, Response["data"]
|
|
14
|
-
queryFn: Exclude<UseQueryOptions<Response["data"]
|
|
13
|
+
type InfiniteQueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];
|
|
14
|
+
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"]>, 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"]>, Response["error"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryFn" | "queryKey"> & {
|
|
15
|
+
queryKey: DataTag<QueryKey<Paths, Method, Path>, QueryData<Response["data"]>, Response["error"]>;
|
|
16
|
+
queryFn: Exclude<UseQueryOptions<QueryData<Response["data"]>, Response["error"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>["queryFn"], SkipToken | undefined>;
|
|
15
17
|
}>;
|
|
16
|
-
type UseQueryMethod<Paths extends
|
|
17
|
-
type
|
|
18
|
+
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"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => UseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, Response["error"]>;
|
|
19
|
+
type PageParam<Initial, Next, Previous> = IsUntyped<Next> extends true ? unknown : [Previous] extends [NoPreviousPageParam] ? NullishToUnknown<Initial | NonNullable<Next>> : IsUntyped<Previous> extends true ? unknown : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;
|
|
20
|
+
declare const NO_PREVIOUS_PAGE_PARAM: unique symbol;
|
|
21
|
+
type NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;
|
|
22
|
+
type IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;
|
|
23
|
+
type NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;
|
|
24
|
+
type PageParamFunction<Result> = (...args: never) => Result;
|
|
25
|
+
interface PageParamSources<Initial, Next, Previous> {
|
|
26
|
+
initialPageParam: Initial;
|
|
27
|
+
getNextPageParam: PageParamFunction<Next>;
|
|
28
|
+
getPreviousPageParam?: PageParamFunction<Previous>;
|
|
29
|
+
}
|
|
30
|
+
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"];
|
|
31
|
+
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"], InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, InfiniteQueryKey<Paths, Method, Path>, PageParam<Initial, Next, Previous>>, "queryKey" | "queryFn" | "placeholderData"> & {
|
|
32
|
+
placeholderData?: InfinitePlaceholderData<Response["data"], Response["error"], Paths, Method, Path>;
|
|
18
33
|
pageParamName?: string;
|
|
19
|
-
}>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"]
|
|
20
|
-
type UseSuspenseQueryMethod<Paths extends
|
|
21
|
-
type UseMutationMethod<Paths extends
|
|
34
|
+
}, 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"]>;
|
|
35
|
+
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"], 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"]>, Response["error"]>;
|
|
36
|
+
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"], Init, TOnMutateResult>, "mutationKey" | "mutationFn">, queryClient?: QueryClient) => UseMutationResult<Response["data"], Response["error"], Init, TOnMutateResult>;
|
|
22
37
|
interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
23
38
|
queryOptions: QueryOptionsFunction<Paths, Media>;
|
|
24
39
|
useQuery: UseQueryMethod<Paths, Media>;
|
|
@@ -31,5 +46,7 @@ type MethodResponse<CreatedClient extends OpenapiQueryClient<any, any>, Method e
|
|
|
31
46
|
}, infer Media extends MediaType> ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>["data"]> : never;
|
|
32
47
|
declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media>): OpenapiQueryClient<Paths, Media>;
|
|
33
48
|
|
|
49
|
+
declare namespace createClient {
|
|
50
|
+
export { InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryKey, QueryOptionsFunction, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
|
51
|
+
}
|
|
34
52
|
export = createClient;
|
|
35
|
-
export type { InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryKey, QueryOptionsFunction, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
import { UseQueryOptions, DataTag, SkipToken, QueryClient, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
2
|
-
import { MaybeOptionalInit, FetchResponse, Client } from 'openapi-typesafe-fetch';
|
|
3
|
-
import { HttpMethod, PathsWithMethod, MediaType
|
|
2
|
+
import { MaybeOptionalInit, FetchResponse, PathOperation, IsInitOptional, Client } from 'openapi-typesafe-fetch';
|
|
3
|
+
import { HttpMethod, PathsWithMethod, MediaType } from 'openapi-typesafe-helpers';
|
|
4
4
|
|
|
5
5
|
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;
|
|
6
|
+
type QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;
|
|
6
7
|
type InitWithUnknowns<Init> = Init & {
|
|
7
8
|
[key: string]: unknown;
|
|
8
9
|
};
|
|
9
|
-
type
|
|
10
|
+
type InitArguments<Init, Rest extends unknown[]> = IsInitOptional<Init> extends true ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];
|
|
11
|
+
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];
|
|
10
12
|
declare const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
11
|
-
type InfiniteQueryKey<Paths extends
|
|
12
|
-
type QueryOptionsFunction<Paths extends
|
|
13
|
-
queryKey: DataTag<QueryKey<Paths, Method, Path>, Response["data"]
|
|
14
|
-
queryFn: Exclude<UseQueryOptions<Response["data"]
|
|
13
|
+
type InfiniteQueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];
|
|
14
|
+
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"]>, 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"]>, Response["error"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryFn" | "queryKey"> & {
|
|
15
|
+
queryKey: DataTag<QueryKey<Paths, Method, Path>, QueryData<Response["data"]>, Response["error"]>;
|
|
16
|
+
queryFn: Exclude<UseQueryOptions<QueryData<Response["data"]>, Response["error"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>["queryFn"], SkipToken | undefined>;
|
|
15
17
|
}>;
|
|
16
|
-
type UseQueryMethod<Paths extends
|
|
17
|
-
type
|
|
18
|
+
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"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => UseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, Response["error"]>;
|
|
19
|
+
type PageParam<Initial, Next, Previous> = IsUntyped<Next> extends true ? unknown : [Previous] extends [NoPreviousPageParam] ? NullishToUnknown<Initial | NonNullable<Next>> : IsUntyped<Previous> extends true ? unknown : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;
|
|
20
|
+
declare const NO_PREVIOUS_PAGE_PARAM: unique symbol;
|
|
21
|
+
type NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;
|
|
22
|
+
type IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;
|
|
23
|
+
type NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;
|
|
24
|
+
type PageParamFunction<Result> = (...args: never) => Result;
|
|
25
|
+
interface PageParamSources<Initial, Next, Previous> {
|
|
26
|
+
initialPageParam: Initial;
|
|
27
|
+
getNextPageParam: PageParamFunction<Next>;
|
|
28
|
+
getPreviousPageParam?: PageParamFunction<Previous>;
|
|
29
|
+
}
|
|
30
|
+
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"];
|
|
31
|
+
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"], InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, InfiniteQueryKey<Paths, Method, Path>, PageParam<Initial, Next, Previous>>, "queryKey" | "queryFn" | "placeholderData"> & {
|
|
32
|
+
placeholderData?: InfinitePlaceholderData<Response["data"], Response["error"], Paths, Method, Path>;
|
|
18
33
|
pageParamName?: string;
|
|
19
|
-
}>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"]
|
|
20
|
-
type UseSuspenseQueryMethod<Paths extends
|
|
21
|
-
type UseMutationMethod<Paths extends
|
|
34
|
+
}, 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"]>;
|
|
35
|
+
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"], 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"]>, Response["error"]>;
|
|
36
|
+
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"], Init, TOnMutateResult>, "mutationKey" | "mutationFn">, queryClient?: QueryClient) => UseMutationResult<Response["data"], Response["error"], Init, TOnMutateResult>;
|
|
22
37
|
interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
23
38
|
queryOptions: QueryOptionsFunction<Paths, Media>;
|
|
24
39
|
useQuery: UseQueryMethod<Paths, Media>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
import { UseQueryOptions, DataTag, SkipToken, QueryClient, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult, UseInfiniteQueryOptions, InfiniteData, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
|
|
2
|
-
import { MaybeOptionalInit, FetchResponse, Client } from 'openapi-typesafe-fetch';
|
|
3
|
-
import { HttpMethod, PathsWithMethod, MediaType
|
|
2
|
+
import { MaybeOptionalInit, FetchResponse, PathOperation, IsInitOptional, Client } from 'openapi-typesafe-fetch';
|
|
3
|
+
import { HttpMethod, PathsWithMethod, MediaType } from 'openapi-typesafe-helpers';
|
|
4
4
|
|
|
5
5
|
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;
|
|
6
|
+
type QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;
|
|
6
7
|
type InitWithUnknowns<Init> = Init & {
|
|
7
8
|
[key: string]: unknown;
|
|
8
9
|
};
|
|
9
|
-
type
|
|
10
|
+
type InitArguments<Init, Rest extends unknown[]> = IsInitOptional<Init> extends true ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];
|
|
11
|
+
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];
|
|
10
12
|
declare const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
11
|
-
type InfiniteQueryKey<Paths extends
|
|
12
|
-
type QueryOptionsFunction<Paths extends
|
|
13
|
-
queryKey: DataTag<QueryKey<Paths, Method, Path>, Response["data"]
|
|
14
|
-
queryFn: Exclude<UseQueryOptions<Response["data"]
|
|
13
|
+
type InfiniteQueryKey<Paths extends {}, Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];
|
|
14
|
+
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"]>, 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"]>, Response["error"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryFn" | "queryKey"> & {
|
|
15
|
+
queryKey: DataTag<QueryKey<Paths, Method, Path>, QueryData<Response["data"]>, Response["error"]>;
|
|
16
|
+
queryFn: Exclude<UseQueryOptions<QueryData<Response["data"]>, Response["error"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>["queryFn"], SkipToken | undefined>;
|
|
15
17
|
}>;
|
|
16
|
-
type UseQueryMethod<Paths extends
|
|
17
|
-
type
|
|
18
|
+
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"], InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, QueryKey<Paths, Method, Path>>, "queryKey" | "queryFn">>(method: Method, url: Path, ...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>) => UseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, Response["error"]>;
|
|
19
|
+
type PageParam<Initial, Next, Previous> = IsUntyped<Next> extends true ? unknown : [Previous] extends [NoPreviousPageParam] ? NullishToUnknown<Initial | NonNullable<Next>> : IsUntyped<Previous> extends true ? unknown : NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;
|
|
20
|
+
declare const NO_PREVIOUS_PAGE_PARAM: unique symbol;
|
|
21
|
+
type NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;
|
|
22
|
+
type IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;
|
|
23
|
+
type NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;
|
|
24
|
+
type PageParamFunction<Result> = (...args: never) => Result;
|
|
25
|
+
interface PageParamSources<Initial, Next, Previous> {
|
|
26
|
+
initialPageParam: Initial;
|
|
27
|
+
getNextPageParam: PageParamFunction<Next>;
|
|
28
|
+
getPreviousPageParam?: PageParamFunction<Previous>;
|
|
29
|
+
}
|
|
30
|
+
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"];
|
|
31
|
+
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"], InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>, InfiniteQueryKey<Paths, Method, Path>, PageParam<Initial, Next, Previous>>, "queryKey" | "queryFn" | "placeholderData"> & {
|
|
32
|
+
placeholderData?: InfinitePlaceholderData<Response["data"], Response["error"], Paths, Method, Path>;
|
|
18
33
|
pageParamName?: string;
|
|
19
|
-
}>(method: Method, url: Path, init: InitWithUnknowns<Init>, options: Options, queryClient?: QueryClient) => UseInfiniteQueryResult<InferSelectReturnType<InfiniteData<Response["data"]
|
|
20
|
-
type UseSuspenseQueryMethod<Paths extends
|
|
21
|
-
type UseMutationMethod<Paths extends
|
|
34
|
+
}, 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"]>;
|
|
35
|
+
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"], 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"]>, Response["error"]>;
|
|
36
|
+
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"], Init, TOnMutateResult>, "mutationKey" | "mutationFn">, queryClient?: QueryClient) => UseMutationResult<Response["data"], Response["error"], Init, TOnMutateResult>;
|
|
22
37
|
interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {
|
|
23
38
|
queryOptions: QueryOptionsFunction<Paths, Media>;
|
|
24
39
|
useQuery: UseQueryMethod<Paths, Media>;
|
|
@@ -31,5 +46,5 @@ type MethodResponse<CreatedClient extends OpenapiQueryClient<any, any>, Method e
|
|
|
31
46
|
}, infer Media extends MediaType> ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>["data"]> : never;
|
|
32
47
|
declare function createClient<Paths extends {}, Media extends MediaType = MediaType>(client: Client<Paths, Media>): OpenapiQueryClient<Paths, Media>;
|
|
33
48
|
|
|
34
|
-
export
|
|
49
|
+
export { createClient as default };
|
|
35
50
|
export type { InfiniteQueryKey, MethodResponse, OpenapiQueryClient, QueryKey, QueryOptionsFunction, UseInfiniteQueryMethod, UseMutationMethod, UseQueryMethod, UseSuspenseQueryMethod };
|
package/dist/index.mjs
CHANGED
|
@@ -14,18 +14,15 @@ function pageInit(init, { pageParamName, pageParam, signal }) {
|
|
|
14
14
|
}
|
|
15
15
|
function createClient(client) {
|
|
16
16
|
const queryFn = async ({
|
|
17
|
-
queryKey
|
|
17
|
+
queryKey,
|
|
18
18
|
signal
|
|
19
19
|
}) => {
|
|
20
|
+
const [method, path, init] = queryKey;
|
|
20
21
|
const mth = method.toUpperCase();
|
|
21
22
|
const fn = client[mth];
|
|
22
23
|
const result = await fn(path, { signal, ...init });
|
|
23
24
|
throwIfFailed(result);
|
|
24
|
-
|
|
25
|
-
if (response.status === 204 || response.headers.get("Content-Length") === "0") {
|
|
26
|
-
return data ?? null;
|
|
27
|
-
}
|
|
28
|
-
return data;
|
|
25
|
+
return result.data ?? null;
|
|
29
26
|
};
|
|
30
27
|
const queryOptions = (method, path, ...[init, options]) => ({
|
|
31
28
|
queryKey: init === void 0 ? [method, path] : [method, path, init],
|
|
@@ -37,7 +34,7 @@ function createClient(client) {
|
|
|
37
34
|
useQuery: (method, path, ...[init, options, queryClient]) => useQuery(queryOptions(method, path, init, options), queryClient),
|
|
38
35
|
useSuspenseQuery: (method, path, ...[init, options, queryClient]) => useSuspenseQuery(queryOptions(method, path, init, options), queryClient),
|
|
39
36
|
useInfiniteQuery: (method, path, init, options, queryClient) => {
|
|
40
|
-
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, ...restOptions } = options;
|
|
37
|
+
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;
|
|
41
38
|
const { queryKey } = queryOptions(method, path, init);
|
|
42
39
|
const mth = method.toUpperCase();
|
|
43
40
|
const fn = client[mth];
|
|
@@ -50,7 +47,10 @@ function createClient(client) {
|
|
|
50
47
|
throwIfFailed(result);
|
|
51
48
|
return result.data;
|
|
52
49
|
},
|
|
53
|
-
...restOptions
|
|
50
|
+
...restOptions,
|
|
51
|
+
// Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack
|
|
52
|
+
// passes the previous data of this query, with its own page params, and takes it back.
|
|
53
|
+
placeholderData
|
|
54
54
|
},
|
|
55
55
|
queryClient
|
|
56
56
|
);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import {\n type DataTag,\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} from \"openapi-typesafe-fetch\";\nimport type { HttpMethod, MediaType, PathsWithMethod, RequiredKeysOf } from \"openapi-typesafe-helpers\";\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\ntype InitWithUnknowns<Init> = Init & { [key: string]: unknown };\n\nexport type QueryKey<\n Paths extends Record<string, Record<HttpMethod, {}>>,\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: a runtime\n * named export next to the default export would change what `require()` returns.\n */\nconst INFINITE_QUERY_KEY_MARKER = \"infinite\";\n\nexport type InfiniteQueryKey<\n Paths extends Record<string, Record<HttpMethod, {}>>,\n Method extends HttpMethod,\n Path extends PathsWithMethod<Paths, Method>,\n> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];\n\nexport type QueryOptionsFunction<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<Response[\"data\"], Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryKey\" | \"queryFn\"\n >,\n>(\n method: Method,\n path: Path,\n ...[init, options]: RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, Options?]\n : [InitWithUnknowns<Init>, Options?]\n) => NoInfer<\n Omit<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<Response[\"data\"], Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > & {\n queryKey: DataTag<QueryKey<Paths, Method, Path>, Response[\"data\"], Response[\"error\"]>;\n queryFn: Exclude<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<Response[\"data\"], Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >[\"queryFn\"],\n SkipToken | undefined\n >;\n }\n>;\n\nexport type UseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<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]: RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, Options?, QueryClient?]\n : [InitWithUnknowns<Init>, Options?, QueryClient?]\n) => UseQueryResult<InferSelectReturnType<Response[\"data\"], Options[\"select\"]>, Response[\"error\"]>;\n\nexport type UseInfiniteQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>,\n Options extends Omit<\n UseInfiniteQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<InfiniteData<Response[\"data\"]>, Options[\"select\"]>,\n InfiniteQueryKey<Paths, Method, Path>,\n unknown\n >,\n \"queryKey\" | \"queryFn\"\n > & {\n pageParamName?: string;\n },\n>(\n method: Method,\n url: Path,\n init: InitWithUnknowns<Init>,\n options: Options,\n queryClient?: QueryClient,\n) => UseInfiniteQueryResult<\n InferSelectReturnType<InfiniteData<Response[\"data\"]>, Options[\"select\"]>,\n Response[\"error\"]\n>;\n\nexport type UseSuspenseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseSuspenseQueryOptions<\n Response[\"data\"],\n Response[\"error\"],\n InferSelectReturnType<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]: RequiredKeysOf<Init> extends never\n ? [InitWithUnknowns<Init>?, Options?, QueryClient?]\n : [InitWithUnknowns<Init>, Options?, QueryClient?]\n) => UseSuspenseQueryResult<InferSelectReturnType<Response[\"data\"], Options[\"select\"]>, Response[\"error\"]>;\n\nexport type UseMutationMethod<Paths extends Record<string, Record<HttpMethod, {}>>, 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<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], Response[\"error\"], Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], 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 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<infer Paths extends { [key: string]: any }, infer Media extends MediaType>\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response with\n * an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as `0`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined || !result.response.ok) {\n throw result.error;\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 readonly signal: AbortSignal;\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, signal }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, signal, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n// TODO: Add the ability to bring queryClient as argument\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n): OpenapiQueryClient<Paths, Media> {\n const queryFn = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>({\n queryKey: [method, path, init],\n signal,\n }: QueryFunctionContext<QueryKey<Paths, Method, Path>>) => {\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, { signal, ...(init as any) }); // TODO: find a way to avoid as any\n throwIfFailed(result);\n const { data, response } = result;\n if (response.status === 204 || response.headers.get(\"Content-Length\") === \"0\") {\n return data ?? null;\n }\n\n return data;\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => ({\n queryKey: (init === undefined ? ([method, path] as const) : ([method, path, init] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n any,\n any\n >,\n queryFn,\n ...options,\n });\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n useQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\n useInfiniteQuery: (method, path, init, options, queryClient) => {\n const { pageParamName = DEFAULT_PAGE_PARAM_NAME, ...restOptions } = options;\n const { queryKey } = queryOptions(method, path, init);\n const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // The request comes from the arguments; the key only identifies the cache entry.\n queryFn: async ({ pageParam, signal }) => {\n const result = await fn(path, pageInit(init, { pageParamName, pageParam, signal }) as any);\n throwIfFailed(result);\n return result.data;\n },\n ...restOptions,\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 const { data } = result;\n\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/index.ts"],"sourcesContent":["import {\n type DataTag,\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 IsInitOptional,\n MaybeOptionalInit,\n PathOperation,\n} from \"openapi-typesafe-fetch\";\nimport type { HttpMethod, MediaType, PathsWithMethod } from \"openapi-typesafe-helpers\";\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\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`. `IsInitOptional` keeps the init optional in\n * `Parameters<typeof $api.queryOptions>`, where it is the union of all inits (upstream #2178).\n */\ntype InitArguments<Init, Rest extends unknown[]> =\n IsInitOptional<Init> extends true ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];\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: a runtime\n * named export next to the default export would change what `require()` returns.\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\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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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 Response[\"error\"],\n InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>,\n QueryKey<Paths, Method, Path>\n >,\n \"queryFn\" | \"queryKey\"\n > & {\n queryKey: DataTag<QueryKey<Paths, Method, Path>, QueryData<Response[\"data\"]>, Response[\"error\"]>;\n queryFn: Exclude<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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) => UseQueryResult<InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>, Response[\"error\"]>;\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 Response[\"error\"],\n InferSelectReturnType<InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>, Options[\"select\"]>,\n InfiniteQueryKey<Paths, Method, Path>,\n PageParam<Initial, Next, Previous>\n >,\n \"queryKey\" | \"queryFn\" | \"placeholderData\"\n > & {\n placeholderData?: InfinitePlaceholderData<Response[\"data\"], Response[\"error\"], Paths, Method, Path>;\n pageParamName?: string;\n },\n Initial = unknown,\n Next = never,\n Previous = NoPreviousPageParam,\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<InfiniteData<Response[\"data\"], PageParam<Initial, Next, Previous>>, Options[\"select\"]>,\n 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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n Options extends Omit<\n UseSuspenseQueryOptions<\n QueryData<Response[\"data\"]>,\n 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<InferSelectReturnType<QueryData<Response[\"data\"]>, Options[\"select\"]>, Response[\"error\"]>;\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 Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types\n TOnMutateResult = unknown,\n>(\n method: Method,\n url: Path,\n options?: Omit<\n UseMutationOptions<Response[\"data\"], Response[\"error\"], Init, TOnMutateResult>,\n \"mutationKey\" | \"mutationFn\"\n >,\n queryClient?: QueryClient,\n) => UseMutationResult<Response[\"data\"], 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 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<infer Paths extends { [key: string]: any }, infer Media extends MediaType>\n ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>[\"data\"]>\n : never;\n\n/**\n * Throw the error of a failed fetch result. `if (error)` missed two failures: a non-OK response with\n * an empty body (`error` is `undefined`, upstream #2070, #2829) and a falsy error body such as `0`.\n */\nfunction throwIfFailed(result: { error?: unknown; response: Response }): void {\n if (result.error !== undefined || !result.response.ok) {\n throw result.error;\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 readonly signal: AbortSignal;\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, signal }: PageRequest) {\n const { params, ...rest } = (init ?? {}) as { params?: { query?: DefaultParamsOption } };\n const page = pageParam === undefined ? {} : { [pageParamName]: pageParam };\n return { ...rest, signal, params: { ...params, query: { ...params?.query, ...page } } };\n}\n\n// TODO: Add the ability to bring queryClient as argument\nexport default function createClient<Paths extends {}, Media extends MediaType = MediaType>(\n client: FetchClient<Paths, Media>,\n): OpenapiQueryClient<Paths, Media> {\n const queryFn = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>({\n queryKey,\n signal,\n }: QueryFunctionContext<QueryKey<Paths, Method, Path>>) => {\n // While `Path` is generic, TypeScript cannot work out that the key is a tuple: the init is a\n // conditional type per operation (`MaybeOptionalInit`), and the key's type waits for it.\n const [method, path, init] = queryKey as readonly [Method, Path, unknown?];\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, { signal, ...(init as any) }); // TODO: find a way to avoid as any\n throwIfFailed(result);\n // TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for every\n // success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD request\n // (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.\n return result.data ?? null;\n };\n\n const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => ({\n queryKey: (init === undefined ? ([method, path] as const) : ([method, path, init] as const)) as DataTag<\n QueryKey<Paths, typeof method, typeof path>,\n any,\n any\n >,\n queryFn,\n ...options,\n });\n\n return {\n queryOptions,\n useQuery: (method, path, ...[init, options, queryClient]) =>\n useQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\n useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>\n useSuspenseQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),\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 const mth = method.toUpperCase() as Uppercase<typeof method>;\n const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;\n return useInfiniteQuery(\n {\n queryKey: [...queryKey, INFINITE_QUERY_KEY_MARKER] as const,\n // The request comes from the arguments; the key only identifies the cache entry.\n queryFn: async ({ pageParam, signal }) => {\n const result = await fn(path, pageInit(init, { pageParamName, pageParam, signal }) as any);\n throwIfFailed(result);\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 return result.data;\n },\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 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.
|
|
4
|
+
"version": "1.0.0-rc.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Fedor Chishchin",
|
|
7
7
|
"url": "https://github.com/fedorello"
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"tanstack"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"openapi-typesafe-helpers": "^1.0.0-rc.
|
|
53
|
+
"openapi-typesafe-helpers": "^1.0.0-rc.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@tanstack/react-query": "5.105.1",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"execa": "^10.2.1",
|
|
62
62
|
"jsdom": "30.1.3",
|
|
63
63
|
"msw": "3.0.3",
|
|
64
|
-
"openapi-typesafe": "^1.0.0-rc.
|
|
65
|
-
"openapi-typesafe-fetch": "^1.0.0-rc.
|
|
64
|
+
"openapi-typesafe": "^1.0.0-rc.1",
|
|
65
|
+
"openapi-typesafe-fetch": "^1.0.0-rc.1",
|
|
66
66
|
"react": "19.3.1",
|
|
67
67
|
"react-dom": "19.3.1",
|
|
68
68
|
"react-error-boundary": "6.1.6"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@tanstack/react-query": "^5.80.0",
|
|
72
|
-
"openapi-typesafe-fetch": "^1.0.0-rc.
|
|
72
|
+
"openapi-typesafe-fetch": "^1.0.0-rc.1"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": ">=22"
|
package/src/index.ts
CHANGED
|
@@ -22,17 +22,33 @@ import type {
|
|
|
22
22
|
DefaultParamsOption,
|
|
23
23
|
Client as FetchClient,
|
|
24
24
|
FetchResponse,
|
|
25
|
+
IsInitOptional,
|
|
25
26
|
MaybeOptionalInit,
|
|
27
|
+
PathOperation,
|
|
26
28
|
} from "openapi-typesafe-fetch";
|
|
27
|
-
import type { HttpMethod, MediaType, PathsWithMethod
|
|
29
|
+
import type { HttpMethod, MediaType, PathsWithMethod } from "openapi-typesafe-helpers";
|
|
28
30
|
|
|
29
31
|
// Helper type to dynamically infer the type from the `select` property
|
|
30
32
|
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;
|
|
31
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Query data of a response type: a success without a body is `undefined` in the fetch client and
|
|
36
|
+
* `null` in the query, as `queryFn` resolves it (upstream #2234, #2464).
|
|
37
|
+
*/
|
|
38
|
+
type QueryData<Data> = undefined extends Data ? Exclude<Data, undefined> | null : Data;
|
|
39
|
+
|
|
32
40
|
type InitWithUnknowns<Init> = Init & { [key: string]: unknown };
|
|
33
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The arguments after the path: the init, required when the operation requires a parameter or a
|
|
44
|
+
* body, then `Rest`. `IsInitOptional` keeps the init optional in
|
|
45
|
+
* `Parameters<typeof $api.queryOptions>`, where it is the union of all inits (upstream #2178).
|
|
46
|
+
*/
|
|
47
|
+
type InitArguments<Init, Rest extends unknown[]> =
|
|
48
|
+
IsInitOptional<Init> extends true ? [InitWithUnknowns<Init>?, ...Rest] : [InitWithUnknowns<Init>, ...Rest];
|
|
49
|
+
|
|
34
50
|
export type QueryKey<
|
|
35
|
-
Paths extends
|
|
51
|
+
Paths extends {},
|
|
36
52
|
Method extends HttpMethod,
|
|
37
53
|
Path extends PathsWithMethod<Paths, Method>,
|
|
38
54
|
Init = MaybeOptionalInit<Paths[Path], Method>,
|
|
@@ -47,21 +63,21 @@ export type QueryKey<
|
|
|
47
63
|
const INFINITE_QUERY_KEY_MARKER = "infinite";
|
|
48
64
|
|
|
49
65
|
export type InfiniteQueryKey<
|
|
50
|
-
Paths extends
|
|
66
|
+
Paths extends {},
|
|
51
67
|
Method extends HttpMethod,
|
|
52
68
|
Path extends PathsWithMethod<Paths, Method>,
|
|
53
69
|
> = readonly [...QueryKey<Paths, Method, Path>, typeof INFINITE_QUERY_KEY_MARKER];
|
|
54
70
|
|
|
55
|
-
export type QueryOptionsFunction<Paths extends
|
|
71
|
+
export type QueryOptionsFunction<Paths extends {}, Media extends MediaType> = <
|
|
56
72
|
Method extends HttpMethod,
|
|
57
73
|
Path extends PathsWithMethod<Paths, Method>,
|
|
58
74
|
Init extends MaybeOptionalInit<Paths[Path], Method>,
|
|
59
|
-
Response extends Required<FetchResponse<Paths
|
|
75
|
+
Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
|
|
60
76
|
Options extends Omit<
|
|
61
77
|
UseQueryOptions<
|
|
62
|
-
Response["data"]
|
|
78
|
+
QueryData<Response["data"]>,
|
|
63
79
|
Response["error"],
|
|
64
|
-
InferSelectReturnType<Response["data"]
|
|
80
|
+
InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>,
|
|
65
81
|
QueryKey<Paths, Method, Path>
|
|
66
82
|
>,
|
|
67
83
|
"queryKey" | "queryFn"
|
|
@@ -69,25 +85,23 @@ export type QueryOptionsFunction<Paths extends Record<string, Record<HttpMethod,
|
|
|
69
85
|
>(
|
|
70
86
|
method: Method,
|
|
71
87
|
path: Path,
|
|
72
|
-
...[init, options]:
|
|
73
|
-
? [InitWithUnknowns<Init>?, Options?]
|
|
74
|
-
: [InitWithUnknowns<Init>, Options?]
|
|
88
|
+
...[init, options]: InitArguments<Init, [Options?]>
|
|
75
89
|
) => NoInfer<
|
|
76
90
|
Omit<
|
|
77
91
|
UseQueryOptions<
|
|
78
|
-
Response["data"]
|
|
92
|
+
QueryData<Response["data"]>,
|
|
79
93
|
Response["error"],
|
|
80
|
-
InferSelectReturnType<Response["data"]
|
|
94
|
+
InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>,
|
|
81
95
|
QueryKey<Paths, Method, Path>
|
|
82
96
|
>,
|
|
83
97
|
"queryFn" | "queryKey"
|
|
84
98
|
> & {
|
|
85
|
-
queryKey: DataTag<QueryKey<Paths, Method, Path>, Response["data"]
|
|
99
|
+
queryKey: DataTag<QueryKey<Paths, Method, Path>, QueryData<Response["data"]>, Response["error"]>;
|
|
86
100
|
queryFn: Exclude<
|
|
87
101
|
UseQueryOptions<
|
|
88
|
-
Response["data"]
|
|
102
|
+
QueryData<Response["data"]>,
|
|
89
103
|
Response["error"],
|
|
90
|
-
InferSelectReturnType<Response["data"]
|
|
104
|
+
InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>,
|
|
91
105
|
QueryKey<Paths, Method, Path>
|
|
92
106
|
>["queryFn"],
|
|
93
107
|
SkipToken | undefined
|
|
@@ -95,16 +109,16 @@ export type QueryOptionsFunction<Paths extends Record<string, Record<HttpMethod,
|
|
|
95
109
|
}
|
|
96
110
|
>;
|
|
97
111
|
|
|
98
|
-
export type UseQueryMethod<Paths extends
|
|
112
|
+
export type UseQueryMethod<Paths extends {}, Media extends MediaType> = <
|
|
99
113
|
Method extends HttpMethod,
|
|
100
114
|
Path extends PathsWithMethod<Paths, Method>,
|
|
101
115
|
Init extends MaybeOptionalInit<Paths[Path], Method>,
|
|
102
|
-
Response extends Required<FetchResponse<Paths
|
|
116
|
+
Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
|
|
103
117
|
Options extends Omit<
|
|
104
118
|
UseQueryOptions<
|
|
105
|
-
Response["data"]
|
|
119
|
+
QueryData<Response["data"]>,
|
|
106
120
|
Response["error"],
|
|
107
|
-
InferSelectReturnType<Response["data"]
|
|
121
|
+
InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>,
|
|
108
122
|
QueryKey<Paths, Method, Path>
|
|
109
123
|
>,
|
|
110
124
|
"queryKey" | "queryFn"
|
|
@@ -112,49 +126,108 @@ export type UseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>,
|
|
|
112
126
|
>(
|
|
113
127
|
method: Method,
|
|
114
128
|
url: Path,
|
|
115
|
-
...[init, options, queryClient]:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
129
|
+
...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>
|
|
130
|
+
) => UseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, Response["error"]>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The type of the page params: the initial one and the ones `getNextPageParam` and
|
|
134
|
+
* `getPreviousPageParam` return (upstream #2458). It was `unknown`. It stays `unknown` when a
|
|
135
|
+
* return type is untyped, so code that compiled still compiles (roadmap §3): TypeScript cannot
|
|
136
|
+
* infer the return type of a callback that computes it from an unannotated `lastPageParam`,
|
|
137
|
+
* whose type depends on that return type, and gives `never` or `unknown`.
|
|
138
|
+
*/
|
|
139
|
+
type PageParam<Initial, Next, Previous> =
|
|
140
|
+
IsUntyped<Next> extends true
|
|
141
|
+
? unknown
|
|
142
|
+
: [Previous] extends [NoPreviousPageParam]
|
|
143
|
+
? NullishToUnknown<Initial | NonNullable<Next>>
|
|
144
|
+
: IsUntyped<Previous> extends true
|
|
145
|
+
? unknown
|
|
146
|
+
: NullishToUnknown<Initial | NonNullable<Next> | NonNullable<Previous>>;
|
|
147
|
+
|
|
148
|
+
/** The `Previous` type parameter when the options have no `getPreviousPageParam`. */
|
|
149
|
+
declare const NO_PREVIOUS_PAGE_PARAM: unique symbol;
|
|
150
|
+
type NoPreviousPageParam = typeof NO_PREVIOUS_PAGE_PARAM;
|
|
151
|
+
|
|
152
|
+
type IsUntyped<T> = [T] extends [never] ? true : unknown extends T ? true : false;
|
|
153
|
+
|
|
154
|
+
/** Only `undefined` or `null` names no type: a cursor API's `initialPageParam: undefined`. */
|
|
155
|
+
type NullishToUnknown<T> = [T] extends [undefined | null] ? unknown : T;
|
|
119
156
|
|
|
120
|
-
|
|
157
|
+
/** Read only for the return type; `never` arguments add no inference for TanStack's page param. */
|
|
158
|
+
type PageParamFunction<Result> = (...args: never) => Result;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Inference sites of the page param types. Intersected before `Options`, so TanStack's own
|
|
162
|
+
* inference in the implementation reads the full signatures of `Options`.
|
|
163
|
+
*/
|
|
164
|
+
interface PageParamSources<Initial, Next, Previous> {
|
|
165
|
+
initialPageParam: Initial;
|
|
166
|
+
getNextPageParam: PageParamFunction<Next>;
|
|
167
|
+
getPreviousPageParam?: PageParamFunction<Previous>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* `placeholderData` of `useInfiniteQuery`, with an `unknown` page param as before: TypeScript types
|
|
172
|
+
* a `(previousData) => previousData` callback while it still infers the page param, so it got
|
|
173
|
+
* `unknown` there and failed against the typed page param.
|
|
174
|
+
*/
|
|
175
|
+
type InfinitePlaceholderData<
|
|
176
|
+
Data,
|
|
177
|
+
Error,
|
|
178
|
+
Paths extends {},
|
|
179
|
+
Method extends HttpMethod,
|
|
180
|
+
Path extends PathsWithMethod<Paths, Method>,
|
|
181
|
+
> = UseInfiniteQueryOptions<
|
|
182
|
+
Data,
|
|
183
|
+
Error,
|
|
184
|
+
InfiniteData<Data, unknown>,
|
|
185
|
+
InfiniteQueryKey<Paths, Method, Path>,
|
|
186
|
+
unknown
|
|
187
|
+
>["placeholderData"];
|
|
188
|
+
|
|
189
|
+
export type UseInfiniteQueryMethod<Paths extends {}, Media extends MediaType> = <
|
|
121
190
|
Method extends HttpMethod,
|
|
122
191
|
Path extends PathsWithMethod<Paths, Method>,
|
|
123
192
|
Init extends MaybeOptionalInit<Paths[Path], Method>,
|
|
124
|
-
Response extends Required<FetchResponse<Paths
|
|
193
|
+
Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>,
|
|
125
194
|
Options extends Omit<
|
|
126
195
|
UseInfiniteQueryOptions<
|
|
127
196
|
Response["data"],
|
|
128
197
|
Response["error"],
|
|
129
|
-
InferSelectReturnType<InfiniteData<Response["data"]
|
|
198
|
+
InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>,
|
|
130
199
|
InfiniteQueryKey<Paths, Method, Path>,
|
|
131
|
-
|
|
200
|
+
PageParam<Initial, Next, Previous>
|
|
132
201
|
>,
|
|
133
|
-
"queryKey" | "queryFn"
|
|
202
|
+
"queryKey" | "queryFn" | "placeholderData"
|
|
134
203
|
> & {
|
|
204
|
+
placeholderData?: InfinitePlaceholderData<Response["data"], Response["error"], Paths, Method, Path>;
|
|
135
205
|
pageParamName?: string;
|
|
136
206
|
},
|
|
207
|
+
Initial = unknown,
|
|
208
|
+
Next = never,
|
|
209
|
+
Previous = NoPreviousPageParam,
|
|
137
210
|
>(
|
|
138
211
|
method: Method,
|
|
139
212
|
url: Path,
|
|
140
213
|
init: InitWithUnknowns<Init>,
|
|
141
|
-
options: Options,
|
|
214
|
+
options: PageParamSources<Initial, Next, Previous> & Options,
|
|
142
215
|
queryClient?: QueryClient,
|
|
143
216
|
) => UseInfiniteQueryResult<
|
|
144
|
-
InferSelectReturnType<InfiniteData<Response["data"]
|
|
217
|
+
InferSelectReturnType<InfiniteData<Response["data"], PageParam<Initial, Next, Previous>>, Options["select"]>,
|
|
145
218
|
Response["error"]
|
|
146
219
|
>;
|
|
147
220
|
|
|
148
|
-
export type UseSuspenseQueryMethod<Paths extends
|
|
221
|
+
export type UseSuspenseQueryMethod<Paths extends {}, Media extends MediaType> = <
|
|
149
222
|
Method extends HttpMethod,
|
|
150
223
|
Path extends PathsWithMethod<Paths, Method>,
|
|
151
224
|
Init extends MaybeOptionalInit<Paths[Path], Method>,
|
|
152
|
-
Response extends Required<FetchResponse<Paths
|
|
225
|
+
Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
|
|
153
226
|
Options extends Omit<
|
|
154
227
|
UseSuspenseQueryOptions<
|
|
155
|
-
Response["data"]
|
|
228
|
+
QueryData<Response["data"]>,
|
|
156
229
|
Response["error"],
|
|
157
|
-
InferSelectReturnType<Response["data"]
|
|
230
|
+
InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>,
|
|
158
231
|
QueryKey<Paths, Method, Path>
|
|
159
232
|
>,
|
|
160
233
|
"queryKey" | "queryFn"
|
|
@@ -162,16 +235,14 @@ export type UseSuspenseQueryMethod<Paths extends Record<string, Record<HttpMetho
|
|
|
162
235
|
>(
|
|
163
236
|
method: Method,
|
|
164
237
|
url: Path,
|
|
165
|
-
...[init, options, queryClient]:
|
|
166
|
-
|
|
167
|
-
: [InitWithUnknowns<Init>, Options?, QueryClient?]
|
|
168
|
-
) => UseSuspenseQueryResult<InferSelectReturnType<Response["data"], Options["select"]>, Response["error"]>;
|
|
238
|
+
...[init, options, queryClient]: InitArguments<Init, [Options?, QueryClient?]>
|
|
239
|
+
) => UseSuspenseQueryResult<InferSelectReturnType<QueryData<Response["data"]>, Options["select"]>, Response["error"]>;
|
|
169
240
|
|
|
170
|
-
export type UseMutationMethod<Paths extends
|
|
241
|
+
export type UseMutationMethod<Paths extends {}, Media extends MediaType> = <
|
|
171
242
|
Method extends HttpMethod,
|
|
172
243
|
Path extends PathsWithMethod<Paths, Method>,
|
|
173
244
|
Init extends MaybeOptionalInit<Paths[Path], Method>,
|
|
174
|
-
Response extends Required<FetchResponse<Paths
|
|
245
|
+
Response extends Required<FetchResponse<PathOperation<Paths, Path, Method>, Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
|
|
175
246
|
TOnMutateResult = unknown,
|
|
176
247
|
>(
|
|
177
248
|
method: Method,
|
|
@@ -238,19 +309,20 @@ export default function createClient<Paths extends {}, Media extends MediaType =
|
|
|
238
309
|
client: FetchClient<Paths, Media>,
|
|
239
310
|
): OpenapiQueryClient<Paths, Media> {
|
|
240
311
|
const queryFn = async <Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>>({
|
|
241
|
-
queryKey
|
|
312
|
+
queryKey,
|
|
242
313
|
signal,
|
|
243
314
|
}: QueryFunctionContext<QueryKey<Paths, Method, Path>>) => {
|
|
315
|
+
// While `Path` is generic, TypeScript cannot work out that the key is a tuple: the init is a
|
|
316
|
+
// conditional type per operation (`MaybeOptionalInit`), and the key's type waits for it.
|
|
317
|
+
const [method, path, init] = queryKey as readonly [Method, Path, unknown?];
|
|
244
318
|
const mth = method.toUpperCase() as Uppercase<typeof method>;
|
|
245
319
|
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
|
|
246
320
|
const result = await fn(path, { signal, ...(init as any) }); // TODO: find a way to avoid as any
|
|
247
321
|
throwIfFailed(result);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return data;
|
|
322
|
+
// TanStack Query rejects `undefined` query data. The fetch client gives `undefined` for every
|
|
323
|
+
// success without a body: a 204, `Content-Length: 0`, an empty chunked body, a HEAD request
|
|
324
|
+
// (upstream #2234). A parsed body is never `undefined`, so this changes nothing else.
|
|
325
|
+
return result.data ?? null;
|
|
254
326
|
};
|
|
255
327
|
|
|
256
328
|
const queryOptions: QueryOptionsFunction<Paths, Media> = (method, path, ...[init, options]) => ({
|
|
@@ -270,7 +342,7 @@ export default function createClient<Paths extends {}, Media extends MediaType =
|
|
|
270
342
|
useSuspenseQuery: (method, path, ...[init, options, queryClient]) =>
|
|
271
343
|
useSuspenseQuery(queryOptions(method, path, init as InitWithUnknowns<typeof init>, options), queryClient),
|
|
272
344
|
useInfiniteQuery: (method, path, init, options, queryClient) => {
|
|
273
|
-
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, ...restOptions } = options;
|
|
345
|
+
const { pageParamName = DEFAULT_PAGE_PARAM_NAME, placeholderData, ...restOptions } = options;
|
|
274
346
|
const { queryKey } = queryOptions(method, path, init);
|
|
275
347
|
const mth = method.toUpperCase() as Uppercase<typeof method>;
|
|
276
348
|
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
|
|
@@ -281,9 +353,14 @@ export default function createClient<Paths extends {}, Media extends MediaType =
|
|
|
281
353
|
queryFn: async ({ pageParam, signal }) => {
|
|
282
354
|
const result = await fn(path, pageInit(init, { pageParamName, pageParam, signal }) as any);
|
|
283
355
|
throwIfFailed(result);
|
|
356
|
+
// An empty page stays `undefined`, as in upstream: TanStack Query rejects only
|
|
357
|
+
// `undefined` query data, and the infinite query data is the `{ pages }` object.
|
|
284
358
|
return result.data;
|
|
285
359
|
},
|
|
286
360
|
...restOptions,
|
|
361
|
+
// Typed with an `unknown` page param for the caller (`InfinitePlaceholderData`). TanStack
|
|
362
|
+
// passes the previous data of this query, with its own page params, and takes it back.
|
|
363
|
+
placeholderData: placeholderData as any,
|
|
287
364
|
},
|
|
288
365
|
queryClient,
|
|
289
366
|
);
|
|
@@ -297,8 +374,11 @@ export default function createClient<Paths extends {}, Media extends MediaType =
|
|
|
297
374
|
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
|
|
298
375
|
const result = await fn(path, init as InitWithUnknowns<typeof init>);
|
|
299
376
|
throwIfFailed(result);
|
|
377
|
+
// TanStack Query accepts `undefined` mutation data, so a success without a body stays
|
|
378
|
+
// `undefined`, as in upstream; only query data needs `null` (upstream #2234). The cast
|
|
379
|
+
// only bridges the generic types: `Response["data"]` still has `undefined` for an
|
|
380
|
+
// operation with a response without a body.
|
|
300
381
|
const { data } = result;
|
|
301
|
-
|
|
302
382
|
return data as Exclude<typeof data, undefined>;
|
|
303
383
|
},
|
|
304
384
|
...options,
|