@openapi-qraft/react 1.1.5 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +142 -46
- package/dist/QraftContext.d.ts +14 -5
- package/dist/QraftContext.d.ts.map +1 -1
- package/dist/QraftContext.js.map +1 -1
- package/dist/ServiceOperation.d.ts +112 -3
- package/dist/ServiceOperation.d.ts.map +1 -1
- package/dist/callbacks/cancelQueries.d.ts +2 -2
- package/dist/callbacks/cancelQueries.d.ts.map +1 -1
- package/dist/callbacks/cancelQueries.js.map +1 -1
- package/dist/callbacks/fetchInfiniteQuery.d.ts +7 -0
- package/dist/callbacks/fetchInfiniteQuery.d.ts.map +1 -0
- package/dist/callbacks/fetchInfiniteQuery.js +5 -0
- package/dist/callbacks/fetchInfiniteQuery.js.map +1 -0
- package/dist/callbacks/fetchQuery.d.ts +7 -0
- package/dist/callbacks/fetchQuery.d.ts.map +1 -0
- package/dist/callbacks/fetchQuery.js +5 -0
- package/dist/callbacks/fetchQuery.js.map +1 -0
- package/dist/callbacks/getInfiniteQueryData.d.ts +4 -4
- package/dist/callbacks/getInfiniteQueryData.d.ts.map +1 -1
- package/dist/callbacks/getInfiniteQueryData.js +3 -6
- package/dist/callbacks/getInfiniteQueryData.js.map +1 -1
- package/dist/callbacks/getInfiniteQueryKey.d.ts +2 -2
- package/dist/callbacks/getInfiniteQueryKey.d.ts.map +1 -1
- package/dist/callbacks/getInfiniteQueryKey.js.map +1 -1
- package/dist/callbacks/getMutationKey.d.ts +2 -2
- package/dist/callbacks/getMutationKey.d.ts.map +1 -1
- package/dist/callbacks/getMutationKey.js.map +1 -1
- package/dist/callbacks/getQueryData.d.ts +3 -3
- package/dist/callbacks/getQueryData.d.ts.map +1 -1
- package/dist/callbacks/getQueryData.js +3 -4
- package/dist/callbacks/getQueryData.js.map +1 -1
- package/dist/callbacks/getQueryKey.d.ts +2 -2
- package/dist/callbacks/getQueryKey.d.ts.map +1 -1
- package/dist/callbacks/getQueryKey.js.map +1 -1
- package/dist/callbacks/invalidateQueries.d.ts +2 -2
- package/dist/callbacks/invalidateQueries.d.ts.map +1 -1
- package/dist/callbacks/invalidateQueries.js.map +1 -1
- package/dist/callbacks/isFetching.d.ts +2 -2
- package/dist/callbacks/isFetching.d.ts.map +1 -1
- package/dist/callbacks/isFetching.js.map +1 -1
- package/dist/callbacks/mutationFn.d.ts +2 -2
- package/dist/callbacks/mutationFn.d.ts.map +1 -1
- package/dist/callbacks/mutationFn.js.map +1 -1
- package/dist/callbacks/prefetchInfiniteQuery.d.ts +7 -0
- package/dist/callbacks/prefetchInfiniteQuery.d.ts.map +1 -0
- package/dist/callbacks/prefetchInfiniteQuery.js +5 -0
- package/dist/callbacks/prefetchInfiniteQuery.js.map +1 -0
- package/dist/callbacks/prefetchQuery.d.ts +7 -0
- package/dist/callbacks/prefetchQuery.d.ts.map +1 -0
- package/dist/callbacks/prefetchQuery.js +5 -0
- package/dist/callbacks/prefetchQuery.js.map +1 -0
- package/dist/callbacks/queryFn.js.map +1 -1
- package/dist/callbacks/refetchQueries.d.ts +3 -3
- package/dist/callbacks/refetchQueries.d.ts.map +1 -1
- package/dist/callbacks/refetchQueries.js.map +1 -1
- package/dist/callbacks/resetQueries.d.ts +2 -2
- package/dist/callbacks/resetQueries.d.ts.map +1 -1
- package/dist/callbacks/resetQueries.js.map +1 -1
- package/dist/callbacks/setInfiniteQueryData.d.ts +2 -2
- package/dist/callbacks/setInfiniteQueryData.d.ts.map +1 -1
- package/dist/callbacks/setInfiniteQueryData.js +2 -6
- package/dist/callbacks/setInfiniteQueryData.js.map +1 -1
- package/dist/callbacks/setQueryData.d.ts +3 -3
- package/dist/callbacks/setQueryData.d.ts.map +1 -1
- package/dist/callbacks/setQueryData.js +3 -7
- package/dist/callbacks/setQueryData.js.map +1 -1
- package/dist/callbacks/useInfiniteQuery.d.ts +4 -4
- package/dist/callbacks/useInfiniteQuery.d.ts.map +1 -1
- package/dist/callbacks/useInfiniteQuery.js +5 -24
- package/dist/callbacks/useInfiniteQuery.js.map +1 -1
- package/dist/callbacks/useIsFetching.d.ts +2 -2
- package/dist/callbacks/useIsFetching.d.ts.map +1 -1
- package/dist/callbacks/useIsFetching.js +3 -8
- package/dist/callbacks/useIsFetching.js.map +1 -1
- package/dist/callbacks/useMutation.d.ts +2 -2
- package/dist/callbacks/useMutation.d.ts.map +1 -1
- package/dist/callbacks/useMutation.js +11 -8
- package/dist/callbacks/useMutation.js.map +1 -1
- package/dist/callbacks/useMutationState.d.ts +2 -2
- package/dist/callbacks/useMutationState.d.ts.map +1 -1
- package/dist/callbacks/useMutationState.js +3 -7
- package/dist/callbacks/useMutationState.js.map +1 -1
- package/dist/callbacks/useQueries.d.ts +2 -2
- package/dist/callbacks/useQueries.d.ts.map +1 -1
- package/dist/callbacks/useQueries.js +9 -6
- package/dist/callbacks/useQueries.js.map +1 -1
- package/dist/callbacks/useQuery.d.ts +4 -4
- package/dist/callbacks/useQuery.d.ts.map +1 -1
- package/dist/callbacks/useQuery.js +5 -23
- package/dist/callbacks/useQuery.js.map +1 -1
- package/dist/callbacks/useSuspenseInfiniteQuery.d.ts +4 -4
- package/dist/callbacks/useSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/callbacks/useSuspenseInfiniteQuery.js +5 -24
- package/dist/callbacks/useSuspenseInfiniteQuery.js.map +1 -1
- package/dist/callbacks/useSuspenseQueries.d.ts +2 -2
- package/dist/callbacks/useSuspenseQueries.d.ts.map +1 -1
- package/dist/callbacks/useSuspenseQueries.js +9 -6
- package/dist/callbacks/useSuspenseQueries.js.map +1 -1
- package/dist/callbacks/useSuspenseQuery.d.ts +4 -4
- package/dist/callbacks/useSuspenseQuery.d.ts.map +1 -1
- package/dist/callbacks/useSuspenseQuery.js +5 -23
- package/dist/callbacks/useSuspenseQuery.js.map +1 -1
- package/dist/index.d.ts +3 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/callQueryClientFetchMethod.d.ts +20 -0
- package/dist/lib/callQueryClientFetchMethod.d.ts.map +1 -0
- package/dist/lib/callQueryClientFetchMethod.js +48 -0
- package/dist/lib/callQueryClientFetchMethod.js.map +1 -0
- package/dist/lib/callQueryClientMethodWithQueryFilters.d.ts +2 -2
- package/dist/lib/callQueryClientMethodWithQueryFilters.d.ts.map +1 -1
- package/dist/lib/callQueryClientMethodWithQueryFilters.js +5 -13
- package/dist/lib/callQueryClientMethodWithQueryFilters.js.map +1 -1
- package/dist/lib/callQueryClientMethodWithQueryKey.d.ts +11 -0
- package/dist/lib/callQueryClientMethodWithQueryKey.d.ts.map +1 -0
- package/dist/lib/callQueryClientMethodWithQueryKey.js +22 -0
- package/dist/lib/callQueryClientMethodWithQueryKey.js.map +1 -0
- package/dist/lib/composeInfiniteQueryKey.d.ts +3 -3
- package/dist/lib/composeInfiniteQueryKey.d.ts.map +1 -1
- package/dist/lib/composeMutationKey.d.ts +4 -4
- package/dist/lib/composeMutationKey.d.ts.map +1 -1
- package/dist/lib/composeMutationKey.js.map +1 -1
- package/dist/lib/composeQueryFilters.d.ts +3 -3
- package/dist/lib/composeQueryFilters.d.ts.map +1 -1
- package/dist/lib/composeQueryFilters.js.map +1 -1
- package/dist/lib/composeQueryKey.d.ts +3 -3
- package/dist/lib/composeQueryKey.d.ts.map +1 -1
- package/dist/lib/requestFn.d.ts +75 -0
- package/dist/lib/requestFn.d.ts.map +1 -0
- package/dist/lib/{request.js → requestFn.js} +40 -34
- package/dist/lib/requestFn.js.map +1 -0
- package/dist/lib/useComposeUseQueryOptions.d.ts +16 -0
- package/dist/lib/useComposeUseQueryOptions.d.ts.map +1 -0
- package/dist/lib/useComposeUseQueryOptions.js +40 -0
- package/dist/lib/useComposeUseQueryOptions.js.map +1 -0
- package/dist/lib/useQueryClient.d.ts +9 -0
- package/dist/lib/useQueryClient.d.ts.map +1 -0
- package/dist/lib/useQueryClient.js +15 -0
- package/dist/lib/useQueryClient.js.map +1 -0
- package/dist/qraftAPIClient.d.ts +7 -7
- package/dist/qraftAPIClient.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/QraftContext.ts +22 -10
- package/src/ServiceOperation.ts +261 -4
- package/src/callbacks/cancelQueries.ts +3 -3
- package/src/callbacks/fetchInfiniteQuery.ts +22 -0
- package/src/callbacks/fetchQuery.ts +20 -0
- package/src/callbacks/getInfiniteQueryData.ts +13 -16
- package/src/callbacks/getInfiniteQueryKey.ts +3 -3
- package/src/callbacks/getMutationKey.ts +3 -3
- package/src/callbacks/getQueryData.ts +12 -10
- package/src/callbacks/getQueryKey.ts +3 -3
- package/src/callbacks/invalidateQueries.ts +3 -3
- package/src/callbacks/isFetching.ts +3 -3
- package/src/callbacks/mutationFn.ts +3 -3
- package/src/callbacks/prefetchInfiniteQuery.ts +22 -0
- package/src/callbacks/prefetchQuery.ts +22 -0
- package/src/callbacks/queryFn.ts +2 -2
- package/src/callbacks/refetchQueries.ts +4 -4
- package/src/callbacks/resetQueries.ts +3 -3
- package/src/callbacks/setInfiniteQueryData.ts +11 -18
- package/src/callbacks/setQueryData.ts +16 -17
- package/src/callbacks/useInfiniteQuery.ts +8 -46
- package/src/callbacks/useIsFetching.ts +6 -20
- package/src/callbacks/useMutation.ts +13 -12
- package/src/callbacks/useMutationState.ts +5 -11
- package/src/callbacks/useQueries.ts +11 -10
- package/src/callbacks/useQuery.ts +8 -39
- package/src/callbacks/useSuspenseInfiniteQuery.ts +8 -42
- package/src/callbacks/useSuspenseQueries.ts +11 -10
- package/src/callbacks/useSuspenseQuery.ts +8 -43
- package/src/index.ts +12 -7
- package/src/lib/callQueryClientFetchMethod.ts +90 -0
- package/src/lib/callQueryClientMethodWithQueryFilters.ts +10 -23
- package/src/lib/callQueryClientMethodWithQueryKey.ts +46 -0
- package/src/lib/composeInfiniteQueryKey.ts +3 -3
- package/src/lib/composeMutationKey.ts +5 -8
- package/src/lib/composeQueryFilters.ts +2 -2
- package/src/lib/composeQueryKey.ts +3 -3
- package/src/lib/{request.ts → requestFn.ts} +143 -79
- package/src/lib/useComposeUseQueryOptions.ts +64 -0
- package/src/lib/useQueryClient.ts +26 -0
- package/src/qraftAPIClient.ts +8 -8
- package/dist/RequestClient.d.ts +0 -19
- package/dist/RequestClient.d.ts.map +0 -1
- package/dist/RequestClient.js +0 -2
- package/dist/RequestClient.js.map +0 -1
- package/dist/lib/request.d.ts +0 -32
- package/dist/lib/request.d.ts.map +0 -1
- package/dist/lib/request.js.map +0 -1
- package/src/RequestClient.ts +0 -32
package/src/index.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
export { qraftAPIClient } from './qraftAPIClient.js';
|
|
2
|
-
export type
|
|
3
|
-
export {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
export { qraftAPIClient, type QraftClientOptions } from './qraftAPIClient.js';
|
|
2
|
+
export { QraftContext, type QraftContextValue } from './QraftContext.js';
|
|
3
|
+
export {
|
|
4
|
+
requestFn,
|
|
5
|
+
baseRequestFn,
|
|
6
|
+
urlSerializer,
|
|
7
|
+
bodySerializer,
|
|
8
|
+
type RequestFnPayload,
|
|
9
|
+
type OperationSchema,
|
|
10
|
+
type RequestFnOptions,
|
|
11
|
+
type HeadersOptions,
|
|
12
|
+
} from './lib/requestFn.js';
|
|
7
13
|
export type {
|
|
8
14
|
ServiceOperationQuery,
|
|
9
15
|
ServiceOperationMutation,
|
|
10
16
|
} from './ServiceOperation.js';
|
|
11
|
-
export type { RequestClient } from './RequestClient.js';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { QueryClient } from '@tanstack/query-core';
|
|
2
|
+
|
|
3
|
+
import { composeInfiniteQueryKey } from './composeInfiniteQueryKey.js';
|
|
4
|
+
import { composeQueryKey } from './composeQueryKey.js';
|
|
5
|
+
import type { OperationSchema, RequestFn } from './requestFn.js';
|
|
6
|
+
import { shelfMerge } from './shelfMerge.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calls a query client fetch method with parameters and options,
|
|
10
|
+
* and automatically composes the `QueryKey` based on the schema and parameters.
|
|
11
|
+
*/
|
|
12
|
+
export function callQueryClientMethodWithQueryKey<
|
|
13
|
+
QFMethod extends QueryKeyMethods,
|
|
14
|
+
>(
|
|
15
|
+
queryFilterMethod: QFMethod,
|
|
16
|
+
schema: OperationSchema,
|
|
17
|
+
infinite: boolean,
|
|
18
|
+
args: QueryClientMethodArgs<QFMethod>
|
|
19
|
+
): ReturnType<(typeof QueryClient.prototype)[QFMethod]> {
|
|
20
|
+
const [{ requestFn, baseUrl, parameters, ...options }, queryClient] = args;
|
|
21
|
+
|
|
22
|
+
if (!queryClient) throw new Error('queryClient is required');
|
|
23
|
+
if (!queryClient[queryFilterMethod])
|
|
24
|
+
throw new Error(
|
|
25
|
+
`queryClient is invalid, ${queryFilterMethod} method does not exist`
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
if (options.queryKey && parameters) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
'callQueryClientMethodWithQueryKey: options.queryKey and options.parameters are mutually exclusive'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (options.queryFn && requestFn) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
'callQueryClientMethodWithQueryKey: options.queryFn and requestFn are mutually exclusive'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const queryFn =
|
|
41
|
+
options.queryFn ??
|
|
42
|
+
(requestFn
|
|
43
|
+
? // @ts-expect-error
|
|
44
|
+
function ({ queryKey: [, queryParams], signal, meta, pageParam }) {
|
|
45
|
+
return requestFn(schema, {
|
|
46
|
+
parameters: infinite
|
|
47
|
+
? (shelfMerge(2, queryParams, pageParam) as never)
|
|
48
|
+
: queryParams,
|
|
49
|
+
baseUrl,
|
|
50
|
+
signal,
|
|
51
|
+
meta,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
: undefined);
|
|
55
|
+
|
|
56
|
+
if (parameters) {
|
|
57
|
+
// @ts-expect-error
|
|
58
|
+
return queryClient[queryFilterMethod]({
|
|
59
|
+
...options,
|
|
60
|
+
// Event if queryFn is undefined, it will override the default queryFn from `setQueryDefaults(...)`
|
|
61
|
+
...(queryFn ? { queryFn } : {}),
|
|
62
|
+
queryKey: infinite
|
|
63
|
+
? composeInfiniteQueryKey(schema, parameters)
|
|
64
|
+
: composeQueryKey(schema, parameters),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// @ts-expect-error
|
|
69
|
+
return queryClient[queryFilterMethod]({ ...options, queryFn });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type QueryClientMethodArgs<QMethod extends keyof QueryClientPrototype> = [
|
|
73
|
+
options: Parameters<QueryClientPrototype[QMethod]>[0] & {
|
|
74
|
+
parameters?: unknown;
|
|
75
|
+
baseUrl?: string;
|
|
76
|
+
requestFn?: RequestFn<unknown>;
|
|
77
|
+
},
|
|
78
|
+
queryClient: QueryClient,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
type QueryKeyMethods =
|
|
82
|
+
| QueryKeyMethod<'fetchQuery'>
|
|
83
|
+
| QueryKeyMethod<'prefetchQuery'>
|
|
84
|
+
| QueryKeyMethod<'fetchInfiniteQuery'>
|
|
85
|
+
| QueryKeyMethod<'prefetchInfiniteQuery'>;
|
|
86
|
+
|
|
87
|
+
type QueryClientPrototype = typeof QueryClient.prototype;
|
|
88
|
+
|
|
89
|
+
type QueryKeyMethod<QFMethod extends keyof typeof QueryClient.prototype> =
|
|
90
|
+
QFMethod;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { QueryClient } from '@tanstack/query-core';
|
|
2
2
|
|
|
3
|
-
import type { RequestClientSchema } from '../RequestClient.js';
|
|
4
3
|
import { composeQueryFilters } from './composeQueryFilters.js';
|
|
4
|
+
import type { OperationSchema } from './requestFn.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Calls a query client method with query filters and options,
|
|
@@ -11,24 +11,11 @@ export function callQueryClientMethodWithQueryFilters<
|
|
|
11
11
|
QFMethod extends QueryFilterMethods,
|
|
12
12
|
>(
|
|
13
13
|
queryFilterMethod: QFMethod,
|
|
14
|
-
schema:
|
|
15
|
-
args: [
|
|
14
|
+
schema: OperationSchema,
|
|
15
|
+
args: [...Parameters<(typeof QueryClient.prototype)[QFMethod]>, QueryClient]
|
|
16
16
|
): ReturnType<(typeof QueryClient.prototype)[QFMethod]> {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
? args[0]
|
|
20
|
-
: args.length === 2
|
|
21
|
-
? args[1]
|
|
22
|
-
: args.length === 3
|
|
23
|
-
? args[2]
|
|
24
|
-
: undefined
|
|
25
|
-
) as QueryClient | undefined;
|
|
26
|
-
|
|
27
|
-
const filters = composeQueryFilters(
|
|
28
|
-
schema,
|
|
29
|
-
args.length === 1 ? undefined : args[0]
|
|
30
|
-
);
|
|
31
|
-
const options = args.length === 3 ? args[1] : undefined;
|
|
17
|
+
const filters = args[0];
|
|
18
|
+
const queryClient = args[args.length - 1] as QueryClient | undefined;
|
|
32
19
|
|
|
33
20
|
if (!queryClient) throw new Error('queryClient is required');
|
|
34
21
|
if (!queryClient[queryFilterMethod])
|
|
@@ -36,12 +23,12 @@ export function callQueryClientMethodWithQueryFilters<
|
|
|
36
23
|
`queryClient is invalid, ${queryFilterMethod} method does not exist`
|
|
37
24
|
);
|
|
38
25
|
|
|
39
|
-
if (options)
|
|
40
|
-
// @ts-expect-error
|
|
41
|
-
return queryClient[queryFilterMethod](filters, options);
|
|
42
|
-
|
|
43
26
|
// @ts-expect-error
|
|
44
|
-
return queryClient[queryFilterMethod](
|
|
27
|
+
return queryClient[queryFilterMethod](
|
|
28
|
+
composeQueryFilters(schema, filters as never),
|
|
29
|
+
// @ts-expect-error
|
|
30
|
+
...args.slice(1, -1)
|
|
31
|
+
);
|
|
45
32
|
}
|
|
46
33
|
|
|
47
34
|
type QueryFiltersMethod<QFMethod extends keyof typeof QueryClient.prototype> =
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { QueryClient } from '@tanstack/query-core';
|
|
2
|
+
|
|
3
|
+
import { composeInfiniteQueryKey } from './composeInfiniteQueryKey.js';
|
|
4
|
+
import { composeQueryKey } from './composeQueryKey.js';
|
|
5
|
+
import type { OperationSchema } from './requestFn.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calls a query client method with parameters and options,
|
|
9
|
+
* and automatically composes the `QueryKey` based on the schema and parameters.
|
|
10
|
+
*/
|
|
11
|
+
export function callQueryClientMethodWithQueryKey<
|
|
12
|
+
QFMethod extends QueryKeyMethods,
|
|
13
|
+
>(
|
|
14
|
+
queryFilterMethod: QFMethod,
|
|
15
|
+
schema: OperationSchema,
|
|
16
|
+
infinite: boolean,
|
|
17
|
+
args: [...Parameters<(typeof QueryClient.prototype)[QFMethod]>, QueryClient]
|
|
18
|
+
): ReturnType<(typeof QueryClient.prototype)[QFMethod]> {
|
|
19
|
+
const parameters = args[0];
|
|
20
|
+
const queryClient = args[args.length - 1] as QueryClient | undefined;
|
|
21
|
+
|
|
22
|
+
if (!queryClient) throw new Error('queryClient is required');
|
|
23
|
+
if (!queryClient[queryFilterMethod])
|
|
24
|
+
throw new Error(
|
|
25
|
+
`queryClient is invalid, ${queryFilterMethod} method does not exist`
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const queryKey = Array.isArray(parameters)
|
|
29
|
+
? parameters
|
|
30
|
+
: infinite
|
|
31
|
+
? composeInfiniteQueryKey(schema, parameters)
|
|
32
|
+
: composeQueryKey(schema, parameters);
|
|
33
|
+
|
|
34
|
+
// @ts-expect-error
|
|
35
|
+
return queryClient[queryFilterMethod](queryKey, ...args.slice(1, -1));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type QueryKeyMethod<QFMethod extends keyof typeof QueryClient.prototype> =
|
|
39
|
+
QFMethod;
|
|
40
|
+
|
|
41
|
+
type QueryKeyMethods =
|
|
42
|
+
| QueryKeyMethod<'setQueryData'>
|
|
43
|
+
| QueryKeyMethod<'getQueryData'>
|
|
44
|
+
| QueryKeyMethod<'getQueryState'>
|
|
45
|
+
| QueryKeyMethod<'setQueryDefaults'>
|
|
46
|
+
| QueryKeyMethod<'getQueryDefaults'>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ServiceOperationInfiniteQueryKey } from '../ServiceOperation.js';
|
|
2
|
+
import type { OperationSchema } from './requestFn.js';
|
|
3
3
|
|
|
4
4
|
export function composeInfiniteQueryKey<
|
|
5
|
-
TSchema extends
|
|
5
|
+
TSchema extends OperationSchema,
|
|
6
6
|
TParams,
|
|
7
7
|
>(
|
|
8
8
|
schema: TSchema,
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ServiceOperationMutationKey } from '../ServiceOperation.js';
|
|
2
|
+
import type { OperationSchema } from './requestFn.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Omit `body` or `requestBody` from mutation parameters if exists
|
|
6
6
|
* and return the rest of the parameters
|
|
7
7
|
*/
|
|
8
8
|
export function composeMutationKey<
|
|
9
|
-
TSchema extends
|
|
9
|
+
TSchema extends OperationSchema,
|
|
10
10
|
TParams = undefined,
|
|
11
11
|
>(
|
|
12
12
|
schema: TSchema,
|
|
13
13
|
parameters: undefined
|
|
14
14
|
): ServiceOperationMutationKey<TSchema, undefined>;
|
|
15
|
-
export function composeMutationKey<
|
|
16
|
-
TSchema extends RequestClientSchema,
|
|
17
|
-
TParams,
|
|
18
|
-
>(
|
|
15
|
+
export function composeMutationKey<TSchema extends OperationSchema, TParams>(
|
|
19
16
|
schema: TSchema,
|
|
20
17
|
parameters: TParams
|
|
21
18
|
): ServiceOperationMutationKey<TSchema, TParams>;
|
|
22
19
|
export function composeMutationKey<
|
|
23
|
-
TSchema extends
|
|
20
|
+
TSchema extends OperationSchema,
|
|
24
21
|
TParams = unknown,
|
|
25
22
|
>(schema: TSchema, parameters: TParams | undefined) {
|
|
26
23
|
return parameters === undefined
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RequestClientSchema } from '../RequestClient.js';
|
|
2
1
|
import { composeQueryKey } from './composeQueryKey.js';
|
|
2
|
+
import type { OperationSchema } from './requestFn.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Replaces the `parameters` field in the filters with a `queryKey` field based on the schema.
|
|
@@ -8,7 +8,7 @@ import { composeQueryKey } from './composeQueryKey.js';
|
|
|
8
8
|
* @param filters
|
|
9
9
|
*/
|
|
10
10
|
export function composeQueryFilters<Filters extends object>(
|
|
11
|
-
schema:
|
|
11
|
+
schema: OperationSchema,
|
|
12
12
|
filters: Filters | undefined
|
|
13
13
|
) {
|
|
14
14
|
if (!filters) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ServiceOperationQueryKey } from '../ServiceOperation.js';
|
|
2
|
+
import type { OperationSchema } from './requestFn.js';
|
|
3
3
|
|
|
4
|
-
export function composeQueryKey<TSchema extends
|
|
4
|
+
export function composeQueryKey<TSchema extends OperationSchema, TParams>(
|
|
5
5
|
schema: TSchema,
|
|
6
6
|
parameters: TParams | undefined
|
|
7
7
|
): ServiceOperationQueryKey<TSchema, TParams> {
|
|
@@ -1,50 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @throws {error: object|string, response: Response} if the request fails
|
|
3
3
|
*/
|
|
4
|
-
export async function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
urlSerializer: urlSerializerFunc,
|
|
9
|
-
bodySerializer: bodySerializerFunc,
|
|
10
|
-
}: {
|
|
11
|
-
urlSerializer: typeof urlSerializer;
|
|
12
|
-
bodySerializer: typeof bodySerializer;
|
|
13
|
-
}
|
|
4
|
+
export async function requestFn<T>(
|
|
5
|
+
schema: OperationSchema,
|
|
6
|
+
requestInfo: RequestFnInfo,
|
|
7
|
+
options?: RequestFnOptions
|
|
14
8
|
): Promise<T> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
mediaType,
|
|
20
|
-
headers,
|
|
21
|
-
body,
|
|
22
|
-
...requestInitRest
|
|
23
|
-
} = requestInit;
|
|
24
|
-
|
|
25
|
-
const requestBody = bodySerializerFunc({
|
|
26
|
-
method,
|
|
27
|
-
mediaType,
|
|
28
|
-
body,
|
|
9
|
+
return baseRequestFn(schema, requestInfo, {
|
|
10
|
+
urlSerializer,
|
|
11
|
+
bodySerializer,
|
|
12
|
+
...options,
|
|
29
13
|
});
|
|
14
|
+
}
|
|
30
15
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
16
|
+
/**
|
|
17
|
+
* @throws {error: object|string, response: Response} if the request fails
|
|
18
|
+
*/
|
|
19
|
+
export async function baseRequestFn<T>(
|
|
20
|
+
requestSchema: OperationSchema,
|
|
21
|
+
requestInfo: RequestFnInfo,
|
|
22
|
+
options: WithRequired<RequestFnOptions, 'urlSerializer' | 'bodySerializer'>
|
|
23
|
+
): Promise<T> {
|
|
24
|
+
const { parameters, headers, body, ...requestInfoRest } = requestInfo;
|
|
25
|
+
|
|
26
|
+
const requestBody = options.bodySerializer(requestSchema, requestInfo);
|
|
27
|
+
|
|
28
|
+
const baseFetch = options.fetch ?? fetch;
|
|
29
|
+
|
|
30
|
+
const response = await baseFetch(
|
|
31
|
+
options.urlSerializer(requestSchema, requestInfo),
|
|
32
|
+
{
|
|
33
|
+
method: requestSchema.method.toUpperCase(),
|
|
34
|
+
body: requestBody,
|
|
35
|
+
headers: mergeHeaders(
|
|
36
|
+
{
|
|
37
|
+
Accept: 'application/json',
|
|
38
|
+
'Content-Type': requestSchema.mediaType ?? getBodyContentType(body),
|
|
39
|
+
},
|
|
40
|
+
headers,
|
|
41
|
+
parameters?.header,
|
|
42
|
+
requestBody instanceof FormData
|
|
43
|
+
? // remove `Content-Type` if serialized body is FormData; browser will correctly set Content-Type & boundary expression
|
|
44
|
+
{ 'Content-Type': null }
|
|
45
|
+
: undefined
|
|
46
|
+
),
|
|
47
|
+
...requestInfoRest,
|
|
48
|
+
}
|
|
49
|
+
);
|
|
48
50
|
|
|
49
51
|
// clone response to allow multiple reads
|
|
50
52
|
const clonedResponse = response.clone();
|
|
@@ -57,21 +59,26 @@ export async function request<T>(
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export function urlSerializer(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
schema: OperationSchema,
|
|
63
|
+
info: RequestFnPayload
|
|
62
64
|
): string {
|
|
63
|
-
const path = url.replace(
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
const path = schema.url.replace(
|
|
66
|
+
/{(.*?)}/g,
|
|
67
|
+
(substring: string, group: string) => {
|
|
68
|
+
if (info.parameters?.path?.hasOwnProperty(group)) {
|
|
69
|
+
return encodeURI(String(info.parameters?.path[group]));
|
|
70
|
+
}
|
|
71
|
+
return substring;
|
|
66
72
|
}
|
|
67
|
-
|
|
68
|
-
});
|
|
73
|
+
);
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
const baseUrl = info.baseUrl ?? '';
|
|
76
|
+
|
|
77
|
+
if (info.parameters?.query) {
|
|
78
|
+
return `${baseUrl}${path}${getQueryString(info.parameters.query)}`;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
|
-
return `${
|
|
81
|
+
return `${baseUrl}${path}`;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
function getQueryString(params: Record<string, any>): string {
|
|
@@ -133,38 +140,37 @@ function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {
|
|
|
133
140
|
return headers;
|
|
134
141
|
}
|
|
135
142
|
|
|
136
|
-
export function bodySerializer(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (options.body === undefined) return;
|
|
143
|
+
export function bodySerializer(
|
|
144
|
+
schema: OperationSchema,
|
|
145
|
+
info: RequestFnPayload
|
|
146
|
+
) {
|
|
147
|
+
if (info.body === undefined) return;
|
|
142
148
|
|
|
143
149
|
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
150
|
+
schema.method === 'get' ||
|
|
151
|
+
schema.method === 'head' ||
|
|
152
|
+
schema.method === 'options'
|
|
147
153
|
)
|
|
148
154
|
return;
|
|
149
155
|
|
|
150
|
-
if (
|
|
151
|
-
return getRequestBodyFormData(
|
|
156
|
+
if (schema.mediaType?.includes('/form-data'))
|
|
157
|
+
return getRequestBodyFormData(info);
|
|
152
158
|
|
|
153
159
|
if (
|
|
154
|
-
!
|
|
155
|
-
(typeof
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
!schema.mediaType?.includes('/json') &&
|
|
161
|
+
(typeof info.body === 'string' ||
|
|
162
|
+
info.body instanceof Blob ||
|
|
163
|
+
info.body instanceof FormData)
|
|
158
164
|
) {
|
|
159
|
-
return
|
|
165
|
+
return info.body;
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
return JSON.stringify(
|
|
168
|
+
return JSON.stringify(info.body);
|
|
163
169
|
}
|
|
164
170
|
|
|
165
171
|
function getRequestBodyFormData({
|
|
166
172
|
body,
|
|
167
|
-
}: Pick<
|
|
173
|
+
}: Pick<RequestFnPayload, 'body'>): FormData | undefined {
|
|
168
174
|
if (body instanceof FormData) return body;
|
|
169
175
|
if (body === null) return;
|
|
170
176
|
|
|
@@ -203,7 +209,7 @@ function getRequestBodyFormData({
|
|
|
203
209
|
return formData;
|
|
204
210
|
}
|
|
205
211
|
|
|
206
|
-
function getBodyContentType(body:
|
|
212
|
+
function getBodyContentType(body: RequestFnPayload['body']) {
|
|
207
213
|
if (!body) return;
|
|
208
214
|
if (body instanceof Blob) return body.type || 'application/octet-stream';
|
|
209
215
|
if (typeof body === 'string') return 'text/plain';
|
|
@@ -225,11 +231,7 @@ async function getResponseBody<T>(response: Response): Promise<T | undefined> {
|
|
|
225
231
|
const errorFallbackResponse = response.clone(); // clone to allow multiple reads
|
|
226
232
|
|
|
227
233
|
return response.json().catch(() => {
|
|
228
|
-
if (
|
|
229
|
-
typeof process !== 'undefined' &&
|
|
230
|
-
typeof process.env !== 'undefined' &&
|
|
231
|
-
process.env.NODE_ENV === 'development'
|
|
232
|
-
) {
|
|
234
|
+
if (process.env.NODE_ENV === 'development') {
|
|
233
235
|
console.warn(
|
|
234
236
|
'Failed to parse response body as JSON. Falling back to .text()'
|
|
235
237
|
);
|
|
@@ -247,7 +249,16 @@ export type HeadersOptions =
|
|
|
247
249
|
| HeadersInit
|
|
248
250
|
| Record<string, string | number | boolean | null | undefined>;
|
|
249
251
|
|
|
250
|
-
export
|
|
252
|
+
export interface OperationSchema {
|
|
253
|
+
/**
|
|
254
|
+
* Operation path
|
|
255
|
+
* @example /user/{id}
|
|
256
|
+
*/
|
|
257
|
+
readonly url: string;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Operation method
|
|
261
|
+
*/
|
|
251
262
|
readonly method:
|
|
252
263
|
| 'get'
|
|
253
264
|
| 'put'
|
|
@@ -257,14 +268,67 @@ export type APIRequestInit = {
|
|
|
257
268
|
| 'options'
|
|
258
269
|
| 'head'
|
|
259
270
|
| 'trace';
|
|
260
|
-
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Media type of the request body
|
|
274
|
+
* @example application/json
|
|
275
|
+
*/
|
|
276
|
+
readonly mediaType?: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface RequestFnPayload {
|
|
280
|
+
/**
|
|
281
|
+
* Base URL to use for the request
|
|
282
|
+
*/
|
|
283
|
+
baseUrl: string | undefined;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* OpenAPI parameters
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* { path: {id: 1}, query: {search: 'hello'} }
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
261
292
|
readonly parameters?: {
|
|
262
293
|
readonly path?: Record<string, any>;
|
|
263
294
|
readonly cookie?: Record<string, any>;
|
|
264
295
|
readonly header?: Record<string, any>;
|
|
265
296
|
readonly query?: Record<string, any>;
|
|
266
297
|
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Request body
|
|
301
|
+
* @example { name: 'John' }
|
|
302
|
+
*/
|
|
267
303
|
readonly body?: BodyInit | Record<string, unknown> | null;
|
|
268
|
-
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Tanstack Query Meta
|
|
307
|
+
*/
|
|
308
|
+
meta?: Record<string, unknown>;
|
|
309
|
+
|
|
310
|
+
/** An AbortSignal to set request's signal. */
|
|
311
|
+
signal?: AbortSignal | null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
interface RequestFnInfo
|
|
315
|
+
extends RequestFnPayload,
|
|
316
|
+
Omit<RequestInit, 'headers' | 'method' | 'body' | 'signal'> {
|
|
317
|
+
/**
|
|
318
|
+
* Request headers
|
|
319
|
+
* @example { 'X-Auth': '123' }
|
|
320
|
+
*/
|
|
269
321
|
readonly headers?: HeadersOptions;
|
|
270
|
-
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export interface RequestFnOptions {
|
|
325
|
+
urlSerializer?: typeof urlSerializer;
|
|
326
|
+
bodySerializer?: typeof bodySerializer;
|
|
327
|
+
fetch?: typeof fetch;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export type RequestFn<T> = typeof requestFn<T>;
|
|
331
|
+
|
|
332
|
+
type WithRequired<T, K extends keyof T> = T & {
|
|
333
|
+
[_ in K]: {};
|
|
334
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useContext } from 'react';
|
|
4
|
+
|
|
5
|
+
import type { QueryClient } from '@tanstack/query-core';
|
|
6
|
+
import type { UseQueryOptions } from '@tanstack/react-query';
|
|
7
|
+
|
|
8
|
+
import type { QraftClientOptions } from '../qraftAPIClient.js';
|
|
9
|
+
import { QraftContext } from '../QraftContext.js';
|
|
10
|
+
import type { ServiceOperationQueryKey } from '../ServiceOperation.js';
|
|
11
|
+
import { composeInfiniteQueryKey } from './composeInfiniteQueryKey.js';
|
|
12
|
+
import { composeQueryKey } from './composeQueryKey.js';
|
|
13
|
+
import type { OperationSchema } from './requestFn.js';
|
|
14
|
+
import { shelfMerge } from './shelfMerge.js';
|
|
15
|
+
import { useQueryClient } from './useQueryClient.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Composes the options for useQuery, useInfiniteQuery, useSuspenseQuery, and useSuspenseQueries.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export function useComposeUseQueryOptions(
|
|
22
|
+
qraftOptions: QraftClientOptions | undefined,
|
|
23
|
+
schema: OperationSchema,
|
|
24
|
+
args: UseQueryOptionsArgs,
|
|
25
|
+
infinite: boolean
|
|
26
|
+
): never {
|
|
27
|
+
const [parameters, options, queryClient] = args;
|
|
28
|
+
|
|
29
|
+
const contextValue = useContext(qraftOptions?.context ?? QraftContext);
|
|
30
|
+
if (!contextValue?.requestFn)
|
|
31
|
+
throw new Error(`QraftContext.requestFn not found`);
|
|
32
|
+
|
|
33
|
+
const queryFn =
|
|
34
|
+
options?.queryFn ??
|
|
35
|
+
// @ts-expect-error
|
|
36
|
+
function ({ queryKey: [, queryParams], signal, meta, pageParam }) {
|
|
37
|
+
return contextValue.requestFn(schema, {
|
|
38
|
+
// @ts-expect-error
|
|
39
|
+
parameters: infinite
|
|
40
|
+
? (shelfMerge(2, queryParams, pageParam) as never)
|
|
41
|
+
: queryParams,
|
|
42
|
+
baseUrl: contextValue.baseUrl,
|
|
43
|
+
signal,
|
|
44
|
+
meta,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const queryKey = Array.isArray(parameters)
|
|
49
|
+
? (parameters as ServiceOperationQueryKey<OperationSchema, unknown>)
|
|
50
|
+
: infinite
|
|
51
|
+
? composeInfiniteQueryKey(schema, parameters)
|
|
52
|
+
: composeQueryKey(schema, parameters);
|
|
53
|
+
|
|
54
|
+
return [
|
|
55
|
+
{ ...options, queryFn, queryKey },
|
|
56
|
+
useQueryClient(qraftOptions, queryClient),
|
|
57
|
+
] as never;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type UseQueryOptionsArgs = [
|
|
61
|
+
parameters: unknown,
|
|
62
|
+
options?: UseQueryOptions,
|
|
63
|
+
queryClient?: QueryClient,
|
|
64
|
+
];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useContext } from 'react';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
QueryClient,
|
|
7
|
+
useQueryClient as useQueryClientTanstack,
|
|
8
|
+
} from '@tanstack/react-query';
|
|
9
|
+
|
|
10
|
+
import type { QraftClientOptions } from '../qraftAPIClient.js';
|
|
11
|
+
import { QraftContext } from '../QraftContext.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the QueryClient from the QraftContext or the provided QueryClient argument.
|
|
15
|
+
* @param qraftOptions if `queryClient` is not provided, will be taken from context
|
|
16
|
+
* @param queryClient If not provided, will be taken this instance
|
|
17
|
+
*/
|
|
18
|
+
export function useQueryClient(
|
|
19
|
+
qraftOptions: QraftClientOptions | undefined,
|
|
20
|
+
queryClient: QueryClient | undefined
|
|
21
|
+
) {
|
|
22
|
+
const queryClientByContext = useContext(qraftOptions?.context ?? QraftContext)
|
|
23
|
+
?.queryClient;
|
|
24
|
+
|
|
25
|
+
return useQueryClientTanstack(queryClient ?? queryClientByContext);
|
|
26
|
+
}
|