@openapi-qraft/react 1.1.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +41 -25
- package/dist/QraftContext.d.ts +16 -5
- package/dist/QraftContext.d.ts.map +1 -1
- package/dist/QraftContext.js.map +1 -1
- package/dist/RequestClient.d.ts +2 -18
- package/dist/RequestClient.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/getInfiniteQueryData.d.ts +2 -2
- package/dist/callbacks/getInfiniteQueryData.d.ts.map +1 -1
- 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 +2 -2
- package/dist/callbacks/getQueryData.d.ts.map +1 -1
- 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/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.map +1 -1
- package/dist/callbacks/setQueryData.d.ts +2 -2
- package/dist/callbacks/setQueryData.d.ts.map +1 -1
- package/dist/callbacks/setQueryData.js.map +1 -1
- package/dist/callbacks/useInfiniteQuery.d.ts +2 -2
- package/dist/callbacks/useInfiniteQuery.d.ts.map +1 -1
- package/dist/callbacks/useInfiniteQuery.js +7 -6
- 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 -5
- 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 +8 -7
- 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 +7 -6
- package/dist/callbacks/useQueries.js.map +1 -1
- package/dist/callbacks/useQuery.d.ts +3 -3
- package/dist/callbacks/useQuery.d.ts.map +1 -1
- package/dist/callbacks/useQuery.js +7 -6
- package/dist/callbacks/useQuery.js.map +1 -1
- package/dist/callbacks/useSuspenseInfiniteQuery.d.ts +2 -2
- package/dist/callbacks/useSuspenseInfiniteQuery.d.ts.map +1 -1
- package/dist/callbacks/useSuspenseInfiniteQuery.js +7 -6
- 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 +7 -6
- package/dist/callbacks/useSuspenseQueries.js.map +1 -1
- package/dist/callbacks/useSuspenseQuery.d.ts +2 -2
- package/dist/callbacks/useSuspenseQuery.d.ts.map +1 -1
- package/dist/callbacks/useSuspenseQuery.js +7 -6
- 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/callQueryClientMethodWithQueryFilters.d.ts +2 -2
- package/dist/lib/callQueryClientMethodWithQueryFilters.d.ts.map +1 -1
- package/dist/lib/callQueryClientMethodWithQueryFilters.js.map +1 -1
- 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/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/composeQueryKey.js.map +1 -1
- package/dist/lib/request.d.ts +50 -17
- package/dist/lib/request.d.ts.map +1 -1
- package/dist/lib/request.js +42 -31
- package/dist/lib/request.js.map +1 -1
- 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 +24 -9
- package/src/RequestClient.ts +10 -31
- package/src/callbacks/cancelQueries.ts +3 -3
- package/src/callbacks/getInfiniteQueryData.ts +3 -3
- package/src/callbacks/getInfiniteQueryKey.ts +3 -3
- package/src/callbacks/getMutationKey.ts +3 -3
- package/src/callbacks/getQueryData.ts +7 -3
- package/src/callbacks/getQueryKey.ts +7 -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/refetchQueries.ts +4 -4
- package/src/callbacks/resetQueries.ts +3 -3
- package/src/callbacks/setInfiniteQueryData.ts +4 -4
- package/src/callbacks/setQueryData.ts +8 -4
- package/src/callbacks/useInfiniteQuery.ts +17 -15
- package/src/callbacks/useIsFetching.ts +6 -14
- package/src/callbacks/useMutation.ts +23 -17
- package/src/callbacks/useMutationState.ts +5 -11
- package/src/callbacks/useQueries.ts +20 -14
- package/src/callbacks/useQuery.ts +22 -17
- package/src/callbacks/useSuspenseInfiniteQuery.ts +17 -15
- package/src/callbacks/useSuspenseQueries.ts +16 -14
- package/src/callbacks/useSuspenseQuery.ts +17 -15
- package/src/index.ts +12 -7
- package/src/lib/callQueryClientMethodWithQueryFilters.ts +2 -2
- package/src/lib/composeInfiniteQueryKey.ts +3 -3
- package/src/lib/composeMutationKey.ts +5 -5
- package/src/lib/composeQueryFilters.ts +2 -2
- package/src/lib/composeQueryKey.ts +6 -3
- package/src/lib/request.ts +136 -74
- package/src/lib/useQueryClient.ts +26 -0
- package/src/qraftAPIClient.ts +8 -8
|
@@ -4,15 +4,15 @@ import { useContext } from 'react';
|
|
|
4
4
|
|
|
5
5
|
import type { DefaultError } from '@tanstack/query-core';
|
|
6
6
|
import {
|
|
7
|
-
useQueryClient,
|
|
8
7
|
UseQueryResult,
|
|
9
8
|
useSuspenseQuery as useSuspenseQueryTanstack,
|
|
10
9
|
} from '@tanstack/react-query';
|
|
11
10
|
|
|
12
11
|
import { composeQueryKey } from '../lib/composeQueryKey.js';
|
|
12
|
+
import type { OperationRequestSchema } from '../lib/request.js';
|
|
13
|
+
import { useQueryClient } from '../lib/useQueryClient.js';
|
|
13
14
|
import type { QraftClientOptions } from '../qraftAPIClient.js';
|
|
14
15
|
import { QraftContext } from '../QraftContext.js';
|
|
15
|
-
import type { RequestClientSchema } from '../RequestClient.js';
|
|
16
16
|
import {
|
|
17
17
|
ServiceOperationQuery,
|
|
18
18
|
ServiceOperationQueryKey,
|
|
@@ -24,10 +24,10 @@ export const useSuspenseQuery: <
|
|
|
24
24
|
TData = TQueryFnData,
|
|
25
25
|
>(
|
|
26
26
|
qraftOptions: QraftClientOptions | undefined,
|
|
27
|
-
schema:
|
|
27
|
+
schema: OperationRequestSchema,
|
|
28
28
|
args: Parameters<
|
|
29
29
|
ServiceOperationQuery<
|
|
30
|
-
|
|
30
|
+
OperationRequestSchema,
|
|
31
31
|
unknown,
|
|
32
32
|
unknown
|
|
33
33
|
>['useSuspenseQuery']
|
|
@@ -35,12 +35,10 @@ export const useSuspenseQuery: <
|
|
|
35
35
|
) => UseQueryResult<TData, TError> = (qraftOptions, schema, args) => {
|
|
36
36
|
const [parameters, options, queryClientByArg] = args;
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
|
|
38
|
+
const contextValue = useContext(qraftOptions?.context ?? QraftContext);
|
|
39
|
+
if (!contextValue?.request) throw new Error(`QraftContext.request not found`);
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> =
|
|
41
|
+
const queryKey: ServiceOperationQueryKey<OperationRequestSchema, unknown> =
|
|
44
42
|
Array.isArray(parameters)
|
|
45
43
|
? (parameters as never)
|
|
46
44
|
: composeQueryKey(schema, parameters);
|
|
@@ -52,13 +50,17 @@ export const useSuspenseQuery: <
|
|
|
52
50
|
queryFn:
|
|
53
51
|
options?.queryFn ??
|
|
54
52
|
function ({ queryKey: [, queryParams], signal, meta }) {
|
|
55
|
-
return
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
return contextValue.request(
|
|
54
|
+
{ baseUrl: contextValue.baseUrl },
|
|
55
|
+
schema,
|
|
56
|
+
{
|
|
57
|
+
parameters: queryParams as never,
|
|
58
|
+
signal,
|
|
59
|
+
meta,
|
|
60
|
+
}
|
|
61
|
+
);
|
|
60
62
|
},
|
|
61
63
|
},
|
|
62
|
-
useQueryClient(queryClientByArg
|
|
64
|
+
useQueryClient(qraftOptions, queryClientByArg)
|
|
63
65
|
) as never;
|
|
64
66
|
};
|
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
|
+
request,
|
|
5
|
+
baseRequest,
|
|
6
|
+
urlSerializer,
|
|
7
|
+
bodySerializer,
|
|
8
|
+
type OperationRequestInfo,
|
|
9
|
+
type OperationRequestSchema,
|
|
10
|
+
type RequestOptions,
|
|
11
|
+
type HeadersOptions,
|
|
12
|
+
} from './lib/request.js';
|
|
7
13
|
export type {
|
|
8
14
|
ServiceOperationQuery,
|
|
9
15
|
ServiceOperationMutation,
|
|
10
16
|
} from './ServiceOperation.js';
|
|
11
|
-
export type { RequestClient } from './RequestClient.js';
|
|
@@ -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 { OperationRequestSchema } from './request.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Calls a query client method with query filters and options,
|
|
@@ -11,7 +11,7 @@ export function callQueryClientMethodWithQueryFilters<
|
|
|
11
11
|
QFMethod extends QueryFilterMethods,
|
|
12
12
|
>(
|
|
13
13
|
queryFilterMethod: QFMethod,
|
|
14
|
-
schema:
|
|
14
|
+
schema: OperationRequestSchema,
|
|
15
15
|
args: [QueryClient, ...Parameters<(typeof QueryClient.prototype)[QFMethod]>]
|
|
16
16
|
): ReturnType<(typeof QueryClient.prototype)[QFMethod]> {
|
|
17
17
|
const queryClient = (
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ServiceOperationInfiniteQueryKey } from '../ServiceOperation.js';
|
|
2
|
+
import type { OperationRequestSchema } from './request.js';
|
|
3
3
|
|
|
4
4
|
export function composeInfiniteQueryKey<
|
|
5
|
-
TSchema extends
|
|
5
|
+
TSchema extends OperationRequestSchema,
|
|
6
6
|
TParams,
|
|
7
7
|
>(
|
|
8
8
|
schema: TSchema,
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ServiceOperationMutationKey } from '../ServiceOperation.js';
|
|
2
|
+
import type { OperationRequestSchema } from './request.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 OperationRequestSchema,
|
|
10
10
|
TParams = undefined,
|
|
11
11
|
>(
|
|
12
12
|
schema: TSchema,
|
|
13
13
|
parameters: undefined
|
|
14
14
|
): ServiceOperationMutationKey<TSchema, undefined>;
|
|
15
15
|
export function composeMutationKey<
|
|
16
|
-
TSchema extends
|
|
16
|
+
TSchema extends OperationRequestSchema,
|
|
17
17
|
TParams,
|
|
18
18
|
>(
|
|
19
19
|
schema: TSchema,
|
|
20
20
|
parameters: TParams
|
|
21
21
|
): ServiceOperationMutationKey<TSchema, TParams>;
|
|
22
22
|
export function composeMutationKey<
|
|
23
|
-
TSchema extends
|
|
23
|
+
TSchema extends OperationRequestSchema,
|
|
24
24
|
TParams = unknown,
|
|
25
25
|
>(schema: TSchema, parameters: TParams | undefined) {
|
|
26
26
|
return parameters === undefined
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RequestClientSchema } from '../RequestClient.js';
|
|
2
1
|
import { composeQueryKey } from './composeQueryKey.js';
|
|
2
|
+
import type { OperationRequestSchema } from './request.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: OperationRequestSchema,
|
|
12
12
|
filters: Filters | undefined
|
|
13
13
|
) {
|
|
14
14
|
if (!filters) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ServiceOperationQueryKey } from '../ServiceOperation.js';
|
|
2
|
+
import type { OperationRequestSchema } from './request.js';
|
|
3
3
|
|
|
4
|
-
export function composeQueryKey<
|
|
4
|
+
export function composeQueryKey<
|
|
5
|
+
TSchema extends OperationRequestSchema,
|
|
6
|
+
TParams,
|
|
7
|
+
>(
|
|
5
8
|
schema: TSchema,
|
|
6
9
|
parameters: TParams | undefined
|
|
7
10
|
): ServiceOperationQueryKey<TSchema, TParams> {
|
package/src/lib/request.ts
CHANGED
|
@@ -2,49 +2,65 @@
|
|
|
2
2
|
* @throws {error: object|string, response: Response} if the request fails
|
|
3
3
|
*/
|
|
4
4
|
export async function request<T>(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
urlSerializer: urlSerializerFunc,
|
|
9
|
-
bodySerializer: bodySerializerFunc,
|
|
10
|
-
}: {
|
|
11
|
-
urlSerializer: typeof urlSerializer;
|
|
12
|
-
bodySerializer: typeof bodySerializer;
|
|
13
|
-
}
|
|
5
|
+
options: RequestOptions,
|
|
6
|
+
schema: OperationRequestSchema,
|
|
7
|
+
requestInfo: OperationRequestInfo
|
|
14
8
|
): Promise<T> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
mediaType,
|
|
28
|
-
body,
|
|
29
|
-
});
|
|
9
|
+
return baseRequest(
|
|
10
|
+
isRequiredRequestOptions(options)
|
|
11
|
+
? options
|
|
12
|
+
: {
|
|
13
|
+
urlSerializer,
|
|
14
|
+
bodySerializer,
|
|
15
|
+
...options,
|
|
16
|
+
},
|
|
17
|
+
schema,
|
|
18
|
+
requestInfo
|
|
19
|
+
);
|
|
20
|
+
}
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
22
|
+
export interface RequestOptions {
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
urlSerializer?: URLSerializer;
|
|
25
|
+
bodySerializer?: BodySerializer;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type URLSerializer = typeof urlSerializer;
|
|
29
|
+
type BodySerializer = typeof bodySerializer;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @throws {error: object|string, response: Response} if the request fails
|
|
33
|
+
*/
|
|
34
|
+
export async function baseRequest<T>(
|
|
35
|
+
options: Required<RequestOptions>,
|
|
36
|
+
schema: OperationRequestSchema,
|
|
37
|
+
requestInfo: OperationRequestInfo,
|
|
38
|
+
customFetch = fetch
|
|
39
|
+
): Promise<T> {
|
|
40
|
+
const { parameters, headers, body, ...requestInfoRest } = requestInfo;
|
|
41
|
+
|
|
42
|
+
const requestBody = options.bodySerializer(schema, requestInfo);
|
|
43
|
+
|
|
44
|
+
const response = await customFetch(
|
|
45
|
+
options.urlSerializer(options.baseUrl, schema, requestInfo),
|
|
46
|
+
{
|
|
47
|
+
method: schema.method.toUpperCase(),
|
|
48
|
+
body: requestBody,
|
|
49
|
+
headers: mergeHeaders(
|
|
50
|
+
{
|
|
51
|
+
Accept: 'application/json',
|
|
52
|
+
'Content-Type': schema.mediaType ?? getBodyContentType(body),
|
|
53
|
+
},
|
|
54
|
+
headers,
|
|
55
|
+
parameters?.header,
|
|
56
|
+
requestBody instanceof FormData
|
|
57
|
+
? // remove `Content-Type` if serialized body is FormData; browser will correctly set Content-Type & boundary expression
|
|
58
|
+
{ 'Content-Type': null }
|
|
59
|
+
: undefined
|
|
60
|
+
),
|
|
61
|
+
...requestInfoRest,
|
|
62
|
+
}
|
|
63
|
+
);
|
|
48
64
|
|
|
49
65
|
// clone response to allow multiple reads
|
|
50
66
|
const clonedResponse = response.clone();
|
|
@@ -57,21 +73,25 @@ export async function request<T>(
|
|
|
57
73
|
}
|
|
58
74
|
|
|
59
75
|
export function urlSerializer(
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
baseUrl: string,
|
|
77
|
+
schema: OperationRequestSchema,
|
|
78
|
+
info: OperationRequestInfo
|
|
62
79
|
): string {
|
|
63
|
-
const path = url.replace(
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
const path = schema.url.replace(
|
|
81
|
+
/{(.*?)}/g,
|
|
82
|
+
(substring: string, group: string) => {
|
|
83
|
+
if (info.parameters?.path?.hasOwnProperty(group)) {
|
|
84
|
+
return encodeURI(String(info.parameters?.path[group]));
|
|
85
|
+
}
|
|
86
|
+
return substring;
|
|
66
87
|
}
|
|
67
|
-
|
|
68
|
-
});
|
|
88
|
+
);
|
|
69
89
|
|
|
70
|
-
if (parameters?.query) {
|
|
71
|
-
return `${
|
|
90
|
+
if (info.parameters?.query) {
|
|
91
|
+
return `${baseUrl}${path}${getQueryString(info.parameters.query)}`;
|
|
72
92
|
}
|
|
73
93
|
|
|
74
|
-
return `${
|
|
94
|
+
return `${baseUrl}${path}`;
|
|
75
95
|
}
|
|
76
96
|
|
|
77
97
|
function getQueryString(params: Record<string, any>): string {
|
|
@@ -133,38 +153,37 @@ function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {
|
|
|
133
153
|
return headers;
|
|
134
154
|
}
|
|
135
155
|
|
|
136
|
-
export function bodySerializer(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (options.body === undefined) return;
|
|
156
|
+
export function bodySerializer(
|
|
157
|
+
schema: OperationRequestSchema,
|
|
158
|
+
info: OperationRequestInfo
|
|
159
|
+
) {
|
|
160
|
+
if (info.body === undefined) return;
|
|
142
161
|
|
|
143
162
|
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
schema.method === 'get' ||
|
|
164
|
+
schema.method === 'head' ||
|
|
165
|
+
schema.method === 'options'
|
|
147
166
|
)
|
|
148
167
|
return;
|
|
149
168
|
|
|
150
|
-
if (
|
|
151
|
-
return getRequestBodyFormData(
|
|
169
|
+
if (schema.mediaType?.includes('/form-data'))
|
|
170
|
+
return getRequestBodyFormData(info);
|
|
152
171
|
|
|
153
172
|
if (
|
|
154
|
-
!
|
|
155
|
-
(typeof
|
|
156
|
-
|
|
157
|
-
|
|
173
|
+
!schema.mediaType?.includes('/json') &&
|
|
174
|
+
(typeof info.body === 'string' ||
|
|
175
|
+
info.body instanceof Blob ||
|
|
176
|
+
info.body instanceof FormData)
|
|
158
177
|
) {
|
|
159
|
-
return
|
|
178
|
+
return info.body;
|
|
160
179
|
}
|
|
161
180
|
|
|
162
|
-
return JSON.stringify(
|
|
181
|
+
return JSON.stringify(info.body);
|
|
163
182
|
}
|
|
164
183
|
|
|
165
184
|
function getRequestBodyFormData({
|
|
166
185
|
body,
|
|
167
|
-
}: Pick<
|
|
186
|
+
}: Pick<OperationRequestInfo, 'body'>): FormData | undefined {
|
|
168
187
|
if (body instanceof FormData) return body;
|
|
169
188
|
if (body === null) return;
|
|
170
189
|
|
|
@@ -203,7 +222,7 @@ function getRequestBodyFormData({
|
|
|
203
222
|
return formData;
|
|
204
223
|
}
|
|
205
224
|
|
|
206
|
-
function getBodyContentType(body:
|
|
225
|
+
function getBodyContentType(body: OperationRequestInfo['body']) {
|
|
207
226
|
if (!body) return;
|
|
208
227
|
if (body instanceof Blob) return body.type || 'application/octet-stream';
|
|
209
228
|
if (typeof body === 'string') return 'text/plain';
|
|
@@ -242,12 +261,27 @@ async function getResponseBody<T>(response: Response): Promise<T | undefined> {
|
|
|
242
261
|
return response.text() as Promise<T>;
|
|
243
262
|
}
|
|
244
263
|
|
|
264
|
+
function isRequiredRequestOptions<T extends RequestOptions>(
|
|
265
|
+
options: RequestOptions
|
|
266
|
+
): options is Required<RequestOptions> {
|
|
267
|
+
return Boolean(options.urlSerializer && options.bodySerializer);
|
|
268
|
+
}
|
|
269
|
+
|
|
245
270
|
// To have definitely typed headers without a conversion to stings
|
|
246
271
|
export type HeadersOptions =
|
|
247
272
|
| HeadersInit
|
|
248
273
|
| Record<string, string | number | boolean | null | undefined>;
|
|
249
274
|
|
|
250
|
-
export
|
|
275
|
+
export interface OperationRequestSchema {
|
|
276
|
+
/**
|
|
277
|
+
* Operation path
|
|
278
|
+
* @example /user/{id}
|
|
279
|
+
*/
|
|
280
|
+
readonly url: string;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Operation method
|
|
284
|
+
*/
|
|
251
285
|
readonly method:
|
|
252
286
|
| 'get'
|
|
253
287
|
| 'put'
|
|
@@ -257,14 +291,42 @@ export type APIRequestInit = {
|
|
|
257
291
|
| 'options'
|
|
258
292
|
| 'head'
|
|
259
293
|
| 'trace';
|
|
260
|
-
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Media type of the request body
|
|
297
|
+
* @example application/json
|
|
298
|
+
*/
|
|
299
|
+
readonly mediaType?: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface OperationRequestInfo
|
|
303
|
+
extends Omit<RequestInit, 'headers' | 'method' | 'body'> {
|
|
304
|
+
/**
|
|
305
|
+
* OpenAPI parameters
|
|
306
|
+
* @example
|
|
307
|
+
* ```ts
|
|
308
|
+
* { path: {id: 1}, query: {search: 'hello'} }
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
261
311
|
readonly parameters?: {
|
|
262
312
|
readonly path?: Record<string, any>;
|
|
263
313
|
readonly cookie?: Record<string, any>;
|
|
264
314
|
readonly header?: Record<string, any>;
|
|
265
315
|
readonly query?: Record<string, any>;
|
|
266
316
|
};
|
|
317
|
+
/**
|
|
318
|
+
* Request body
|
|
319
|
+
* @example { name: 'John' }
|
|
320
|
+
*/
|
|
267
321
|
readonly body?: BodyInit | Record<string, unknown> | null;
|
|
268
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Request headers
|
|
324
|
+
* @example { 'X-Auth': '123' }
|
|
325
|
+
*/
|
|
269
326
|
readonly headers?: HeadersOptions;
|
|
270
|
-
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Tanstack Query Meta
|
|
330
|
+
*/
|
|
331
|
+
meta?: Record<string, unknown>;
|
|
332
|
+
}
|
|
@@ -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
|
+
}
|
package/src/qraftAPIClient.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Context } from 'react';
|
|
1
|
+
import type { Context } from 'react';
|
|
2
2
|
|
|
3
3
|
import { createRecursiveProxy } from './lib/createRecursiveProxy.js';
|
|
4
|
-
import {
|
|
5
|
-
import type {
|
|
4
|
+
import type { OperationRequestSchema } from './lib/request.js';
|
|
5
|
+
import type { QraftContextValue } from './QraftContext.js';
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export interface QraftClientOptions {
|
|
8
8
|
context?: Context<QraftContextValue>;
|
|
9
|
-
}
|
|
9
|
+
}
|
|
10
10
|
|
|
11
11
|
export const qraftAPIClient = <
|
|
12
12
|
Services extends ServicesOutput<Services>,
|
|
@@ -50,7 +50,7 @@ export const qraftAPIClient = <
|
|
|
50
50
|
|
|
51
51
|
function isServiceOperation(
|
|
52
52
|
input: unknown
|
|
53
|
-
): input is { schema:
|
|
53
|
+
): input is { schema: OperationRequestSchema } {
|
|
54
54
|
return input !== null && typeof input === 'object' && 'schema' in input;
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -63,7 +63,7 @@ function getByPath(obj: Record<string, unknown>, path: string[]) {
|
|
|
63
63
|
|
|
64
64
|
type ServicesOutput<Services> = {
|
|
65
65
|
[service in keyof Services]: {
|
|
66
|
-
[method in keyof Services[service]]: { schema:
|
|
66
|
+
[method in keyof Services[service]]: { schema: OperationRequestSchema };
|
|
67
67
|
};
|
|
68
68
|
};
|
|
69
69
|
|
|
@@ -82,7 +82,7 @@ type ServicesCallbacksFilter<
|
|
|
82
82
|
Callbacks,
|
|
83
83
|
> = Services extends {
|
|
84
84
|
[serviceName in keyof Services]: {
|
|
85
|
-
[method in keyof Services[serviceName]]: { schema:
|
|
85
|
+
[method in keyof Services[serviceName]]: { schema: OperationRequestSchema };
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
? {
|