@openapi-qraft/react 1.0.9 → 1.1.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/QraftContext.d.ts +3 -0
  3. package/dist/QraftContext.d.ts.map +1 -1
  4. package/dist/QraftContext.js.map +1 -1
  5. package/dist/ServiceOperation.d.ts +98 -22
  6. package/dist/ServiceOperation.d.ts.map +1 -1
  7. package/dist/callbacks/getInfiniteQueryData.d.ts.map +1 -1
  8. package/dist/callbacks/getInfiniteQueryData.js +4 -4
  9. package/dist/callbacks/getInfiniteQueryData.js.map +1 -1
  10. package/dist/callbacks/getInfiniteQueryKey.d.ts +1 -5
  11. package/dist/callbacks/getInfiniteQueryKey.d.ts.map +1 -1
  12. package/dist/callbacks/getInfiniteQueryKey.js +2 -4
  13. package/dist/callbacks/getInfiniteQueryKey.js.map +1 -1
  14. package/dist/callbacks/getQueryData.d.ts.map +1 -1
  15. package/dist/callbacks/getQueryData.js +2 -4
  16. package/dist/callbacks/getQueryData.js.map +1 -1
  17. package/dist/callbacks/getQueryKey.d.ts +1 -4
  18. package/dist/callbacks/getQueryKey.d.ts.map +1 -1
  19. package/dist/callbacks/getQueryKey.js +2 -4
  20. package/dist/callbacks/getQueryKey.js.map +1 -1
  21. package/dist/callbacks/invalidateQueries.d.ts +5 -0
  22. package/dist/callbacks/invalidateQueries.d.ts.map +1 -0
  23. package/dist/callbacks/invalidateQueries.js +36 -0
  24. package/dist/callbacks/invalidateQueries.js.map +1 -0
  25. package/dist/callbacks/setInfiniteQueryData.d.ts.map +1 -1
  26. package/dist/callbacks/setInfiniteQueryData.js +4 -1
  27. package/dist/callbacks/setInfiniteQueryData.js.map +1 -1
  28. package/dist/callbacks/setQueryData.d.ts.map +1 -1
  29. package/dist/callbacks/setQueryData.js +4 -4
  30. package/dist/callbacks/setQueryData.js.map +1 -1
  31. package/dist/callbacks/useInfiniteQuery.d.ts.map +1 -1
  32. package/dist/callbacks/useInfiniteQuery.js +9 -9
  33. package/dist/callbacks/useInfiniteQuery.js.map +1 -1
  34. package/dist/callbacks/useMutation.d.ts +1 -1
  35. package/dist/callbacks/useMutation.d.ts.map +1 -1
  36. package/dist/callbacks/useMutation.js +4 -5
  37. package/dist/callbacks/useMutation.js.map +1 -1
  38. package/dist/callbacks/useMutationState.d.ts +1 -1
  39. package/dist/callbacks/useMutationState.d.ts.map +1 -1
  40. package/dist/callbacks/useMutationState.js +4 -5
  41. package/dist/callbacks/useMutationState.js.map +1 -1
  42. package/dist/callbacks/useQueries.d.ts.map +1 -1
  43. package/dist/callbacks/useQueries.js +27 -20
  44. package/dist/callbacks/useQueries.js.map +1 -1
  45. package/dist/callbacks/useQuery.d.ts +2 -2
  46. package/dist/callbacks/useQuery.d.ts.map +1 -1
  47. package/dist/callbacks/useQuery.js +9 -10
  48. package/dist/callbacks/useQuery.js.map +1 -1
  49. package/dist/callbacks/useSuspenseInfiniteQuery.d.ts.map +1 -1
  50. package/dist/callbacks/useSuspenseInfiniteQuery.js +9 -9
  51. package/dist/callbacks/useSuspenseInfiniteQuery.js.map +1 -1
  52. package/dist/callbacks/useSuspenseQueries.d.ts.map +1 -1
  53. package/dist/callbacks/useSuspenseQueries.js +27 -20
  54. package/dist/callbacks/useSuspenseQueries.js.map +1 -1
  55. package/dist/callbacks/useSuspenseQuery.d.ts.map +1 -1
  56. package/dist/callbacks/useSuspenseQuery.js +8 -9
  57. package/dist/callbacks/useSuspenseQuery.js.map +1 -1
  58. package/dist/lib/composeInfiniteQueryKey.d.ts +4 -0
  59. package/dist/lib/composeInfiniteQueryKey.d.ts.map +1 -0
  60. package/dist/lib/composeInfiniteQueryKey.js +4 -0
  61. package/dist/lib/composeInfiniteQueryKey.js.map +1 -0
  62. package/dist/lib/composeQueryKey.d.ts +4 -0
  63. package/dist/lib/composeQueryKey.d.ts.map +1 -0
  64. package/dist/lib/composeQueryKey.js +4 -0
  65. package/dist/lib/composeQueryKey.js.map +1 -0
  66. package/dist/lib/createRecursiveProxy.d.ts +7 -5
  67. package/dist/lib/createRecursiveProxy.d.ts.map +1 -1
  68. package/dist/lib/createRecursiveProxy.js +14 -9
  69. package/dist/lib/createRecursiveProxy.js.map +1 -1
  70. package/dist/lib/request.d.ts.map +1 -1
  71. package/dist/lib/request.js +15 -3
  72. package/dist/lib/request.js.map +1 -1
  73. package/dist/qraftAPIClient.d.ts.map +1 -1
  74. package/dist/qraftAPIClient.js +16 -7
  75. package/dist/qraftAPIClient.js.map +1 -1
  76. package/package.json +3 -2
  77. package/src/QraftContext.ts +4 -0
  78. package/src/ServiceOperation.ts +152 -25
  79. package/src/callbacks/getInfiniteQueryData.ts +6 -4
  80. package/src/callbacks/getInfiniteQueryKey.ts +3 -8
  81. package/src/callbacks/getQueryData.ts +5 -8
  82. package/src/callbacks/getQueryKey.ts +3 -8
  83. package/src/callbacks/invalidateQueries.ts +70 -0
  84. package/src/callbacks/setInfiniteQueryData.ts +4 -1
  85. package/src/callbacks/setQueryData.ts +5 -4
  86. package/src/callbacks/useInfiniteQuery.ts +18 -9
  87. package/src/callbacks/useMutation.ts +9 -6
  88. package/src/callbacks/useMutationState.ts +9 -6
  89. package/src/callbacks/useQueries.ts +35 -24
  90. package/src/callbacks/useQuery.ts +16 -16
  91. package/src/callbacks/useSuspenseInfiniteQuery.ts +15 -9
  92. package/src/callbacks/useSuspenseQueries.ts +35 -24
  93. package/src/callbacks/useSuspenseQuery.ts +10 -8
  94. package/src/lib/composeInfiniteQueryKey.ts +12 -0
  95. package/src/lib/composeQueryKey.ts +9 -0
  96. package/src/lib/createRecursiveProxy.ts +32 -11
  97. package/src/lib/request.ts +20 -2
  98. package/src/qraftAPIClient.ts +25 -13
  99. package/dist/lib/createCallbackProxyDecoration.d.ts +0 -5
  100. package/dist/lib/createCallbackProxyDecoration.d.ts.map +0 -1
  101. package/dist/lib/createCallbackProxyDecoration.js +0 -21
  102. package/dist/lib/createCallbackProxyDecoration.js.map +0 -1
  103. package/src/lib/createCallbackProxyDecoration.ts +0 -34
@@ -6,13 +6,18 @@ import type { DefaultError, InfiniteData } from '@tanstack/query-core';
6
6
  import {
7
7
  useInfiniteQuery as useInfiniteQueryBase,
8
8
  UseInfiniteQueryResult,
9
+ useQueryClient,
9
10
  } from '@tanstack/react-query';
10
11
 
12
+ import { composeInfiniteQueryKey } from '../lib/composeInfiniteQueryKey.js';
11
13
  import { shelfMerge } from '../lib/shelfMerge.js';
12
14
  import type { QraftClientOptions } from '../qraftAPIClient.js';
13
15
  import { QraftContext } from '../QraftContext.js';
14
16
  import type { RequestClientSchema } from '../RequestClient.js';
15
- import { ServiceOperationQuery } from '../ServiceOperation.js';
17
+ import {
18
+ ServiceOperationInfiniteQueryKey,
19
+ ServiceOperationQuery,
20
+ } from '../ServiceOperation.js';
16
21
 
17
22
  export const useInfiniteQuery: <
18
23
  TQueryFnData,
@@ -29,20 +34,24 @@ export const useInfiniteQuery: <
29
34
  >['useInfiniteQuery']
30
35
  >
31
36
  ) => UseInfiniteQueryResult<TData, TError> = (qraftOptions, schema, args) => {
32
- const [parameters, options, ...restArgs] = args;
37
+ const [parameters, options, queryClientByArg] = args;
33
38
 
34
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
35
- ?.requestClient;
39
+ const { requestClient, queryClient: queryClientByContext } =
40
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
36
41
 
37
42
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
38
43
 
44
+ const queryKey: ServiceOperationInfiniteQueryKey<
45
+ RequestClientSchema,
46
+ unknown
47
+ > = Array.isArray(parameters)
48
+ ? (parameters as never)
49
+ : composeInfiniteQueryKey(schema, parameters);
50
+
39
51
  return useInfiniteQueryBase(
40
52
  {
41
53
  ...options,
42
- queryKey: [
43
- { url: schema.url, method: schema.method, infinite: true },
44
- parameters as never,
45
- ] as const,
54
+ queryKey,
46
55
  queryFn:
47
56
  options?.queryFn ??
48
57
  function ({ queryKey: [, queryParams], signal, meta, pageParam }) {
@@ -53,6 +62,6 @@ export const useInfiniteQuery: <
53
62
  });
54
63
  },
55
64
  },
56
- ...restArgs
65
+ useQueryClient(queryClientByArg ?? queryClientByContext)
57
66
  ) as never;
58
67
  };
@@ -3,8 +3,11 @@
3
3
  import { useContext } from 'react';
4
4
 
5
5
  import type { DefaultError } from '@tanstack/query-core';
6
- import type { UseMutationResult } from '@tanstack/react-query';
7
- import { useMutation as useMutationBase } from '@tanstack/react-query';
6
+ import {
7
+ useMutation as useMutationBase,
8
+ UseMutationResult,
9
+ useQueryClient,
10
+ } from '@tanstack/react-query';
8
11
 
9
12
  import { composeMutationKey } from '../lib/composeMutationKey.js';
10
13
  import type { QraftClientOptions } from '../qraftAPIClient.js';
@@ -36,7 +39,7 @@ export const useMutation: <
36
39
  schema,
37
40
  args
38
41
  ) => {
39
- const [parameters, options, ...restArgs] = args;
42
+ const [parameters, options, queryClientByArg] = args;
40
43
 
41
44
  if (
42
45
  parameters &&
@@ -48,8 +51,8 @@ export const useMutation: <
48
51
  `'useMutation': parameters and 'options.mutationKey' cannot be used together`
49
52
  );
50
53
 
51
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
52
- ?.requestClient;
54
+ const { requestClient, queryClient: queryClientByContext } =
55
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
53
56
 
54
57
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
55
58
 
@@ -85,6 +88,6 @@ export const useMutation: <
85
88
  } as never);
86
89
  }),
87
90
  },
88
- ...restArgs
91
+ useQueryClient(queryClientByArg ?? queryClientByContext)
89
92
  ) as never;
90
93
  };
@@ -3,8 +3,11 @@
3
3
  import { useContext } from 'react';
4
4
 
5
5
  import type { DefaultError } from '@tanstack/query-core';
6
- import type { UseMutationResult } from '@tanstack/react-query';
7
- import { useMutationState as useMutationStateTanstack } from '@tanstack/react-query';
6
+ import {
7
+ UseMutationResult,
8
+ useMutationState as useMutationStateTanstack,
9
+ useQueryClient,
10
+ } from '@tanstack/react-query';
8
11
 
9
12
  import { composeMutationKey } from '../lib/composeMutationKey.js';
10
13
  import type { QraftClientOptions } from '../qraftAPIClient.js';
@@ -33,7 +36,7 @@ export const useMutationState: <
33
36
  schema,
34
37
  args
35
38
  ) => {
36
- const [options, ...restArgs] = args;
39
+ const [options, queryClientByArg] = args;
37
40
 
38
41
  if (
39
42
  options?.filters &&
@@ -45,8 +48,8 @@ export const useMutationState: <
45
48
  );
46
49
  }
47
50
 
48
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
49
- ?.requestClient;
51
+ const { requestClient, queryClient: queryClientByContext } =
52
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
50
53
 
51
54
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
52
55
 
@@ -68,6 +71,6 @@ export const useMutationState: <
68
71
  ),
69
72
  },
70
73
  } as never,
71
- ...restArgs
74
+ useQueryClient(queryClientByArg ?? queryClientByContext)
72
75
  ) as never;
73
76
  };
@@ -5,15 +5,14 @@ import { useContext } from 'react';
5
5
  import {
6
6
  QueriesResults,
7
7
  useQueries as useQueriesTanstack,
8
+ useQueryClient,
8
9
  } from '@tanstack/react-query';
9
10
 
11
+ import { composeQueryKey } from '../lib/composeQueryKey.js';
10
12
  import type { QraftClientOptions } from '../qraftAPIClient.js';
11
13
  import { QraftContext } from '../QraftContext.js';
12
14
  import type { RequestClientSchema } from '../RequestClient.js';
13
- import {
14
- ServiceOperationQuery,
15
- ServiceOperationQueryKey,
16
- } from '../ServiceOperation.js';
15
+ import { ServiceOperationQuery } from '../ServiceOperation.js';
17
16
 
18
17
  export const useQueries: (
19
18
  qraftOptions: QraftClientOptions | undefined,
@@ -22,33 +21,45 @@ export const useQueries: (
22
21
  ServiceOperationQuery<RequestClientSchema, unknown, unknown>['useQueries']
23
22
  >
24
23
  ) => QueriesResults<never> = (qraftOptions, schema, args) => {
25
- const [options, ...restArgs] = args;
24
+ const [options, queryClientByArg] = args;
26
25
 
27
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
28
- ?.requestClient;
26
+ const { requestClient, queryClient: queryClientByContext } =
27
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
29
28
 
30
29
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
31
30
 
32
31
  return useQueriesTanstack(
33
32
  {
34
33
  ...options,
35
- queries: options.queries.map(({ parameters, ...queryOptions }) => ({
36
- ...queryOptions,
37
- queryKey: [
38
- { url: schema.url, method: schema.method },
39
- parameters,
40
- ] satisfies ServiceOperationQueryKey<RequestClientSchema, unknown>,
41
- queryFn:
42
- queryOptions.queryFn ??
43
- function ({ queryKey: [, queryParams], signal, meta }) {
44
- return requestClient(schema, {
45
- parameters: queryParams as never,
46
- signal,
47
- meta,
48
- });
49
- },
50
- })),
34
+ queries: options.queries.map((queryOptions) => {
35
+ const optionsWithQueryKey =
36
+ 'parameters' in queryOptions
37
+ ? (() => {
38
+ const queryOptionsCopy = Object.assign(
39
+ {
40
+ queryKey: composeQueryKey(schema, queryOptions.parameters),
41
+ },
42
+ queryOptions
43
+ );
44
+ delete queryOptionsCopy.parameters;
45
+ return queryOptionsCopy;
46
+ })()
47
+ : queryOptions;
48
+
49
+ return {
50
+ ...optionsWithQueryKey,
51
+ queryFn:
52
+ optionsWithQueryKey.queryFn ??
53
+ function ({ queryKey: [, queryParams], signal, meta }) {
54
+ return requestClient(schema, {
55
+ parameters: queryParams as never,
56
+ signal,
57
+ meta,
58
+ });
59
+ },
60
+ };
61
+ }),
51
62
  },
52
- ...restArgs
63
+ useQueryClient(queryClientByArg ?? queryClientByContext)
53
64
  ) as never;
54
65
  };
@@ -3,9 +3,13 @@
3
3
  import { useContext } from 'react';
4
4
 
5
5
  import type { DefaultError } from '@tanstack/query-core';
6
- import type { UseQueryResult } from '@tanstack/react-query';
7
- import { useQuery as useQueryBase } from '@tanstack/react-query';
6
+ import {
7
+ useQuery as useQueryTanstack,
8
+ useQueryClient,
9
+ UseQueryResult,
10
+ } from '@tanstack/react-query';
8
11
 
12
+ import { composeQueryKey } from '../lib/composeQueryKey.js';
9
13
  import type { QraftClientOptions } from '../qraftAPIClient.js';
10
14
  import { QraftContext } from '../QraftContext.js';
11
15
  import type { RequestClientSchema } from '../RequestClient.js';
@@ -14,30 +18,26 @@ import {
14
18
  ServiceOperationQueryKey,
15
19
  } from '../ServiceOperation.js';
16
20
 
17
- export const useQuery: <
18
- TQueryFnData = unknown,
19
- TError = DefaultError,
20
- TData = TQueryFnData,
21
- >(
21
+ export const useQuery: <TData = unknown, TError = DefaultError>(
22
22
  qraftOptions: QraftClientOptions | undefined,
23
23
  schema: RequestClientSchema,
24
24
  args: Parameters<
25
25
  ServiceOperationQuery<RequestClientSchema, unknown, unknown>['useQuery']
26
26
  >
27
27
  ) => UseQueryResult<TData, TError> = (qraftOptions, schema, args) => {
28
- const [parameters, options, ...restArgs] = args;
28
+ const [parameters, options, queryClientByArg] = args;
29
29
 
30
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
31
- ?.requestClient;
30
+ const { requestClient, queryClient: queryClientByContext } =
31
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
32
32
 
33
33
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
34
34
 
35
- const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> = [
36
- { url: schema.url, method: schema.method },
37
- parameters,
38
- ];
35
+ const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> =
36
+ Array.isArray(parameters)
37
+ ? (parameters as ServiceOperationQueryKey<RequestClientSchema, unknown>)
38
+ : composeQueryKey(schema, parameters);
39
39
 
40
- return useQueryBase(
40
+ return useQueryTanstack(
41
41
  {
42
42
  ...options,
43
43
  queryKey,
@@ -51,6 +51,6 @@ export const useQuery: <
51
51
  });
52
52
  },
53
53
  },
54
- ...restArgs
54
+ useQueryClient(queryClientByArg ?? queryClientByContext)
55
55
  ) as never;
56
56
  };
@@ -4,17 +4,19 @@ import { useContext } from 'react';
4
4
 
5
5
  import type { DefaultError, InfiniteData } from '@tanstack/query-core';
6
6
  import {
7
+ useQueryClient,
7
8
  useSuspenseInfiniteQuery as useSuspenseInfiniteQueryTanstack,
8
9
  UseSuspenseInfiniteQueryResult,
9
10
  } from '@tanstack/react-query';
10
11
 
12
+ import { composeInfiniteQueryKey } from '../lib/composeInfiniteQueryKey.js';
11
13
  import { shelfMerge } from '../lib/shelfMerge.js';
12
14
  import type { QraftClientOptions } from '../qraftAPIClient.js';
13
15
  import { QraftContext } from '../QraftContext.js';
14
16
  import type { RequestClientSchema } from '../RequestClient.js';
15
17
  import {
18
+ ServiceOperationInfiniteQueryKey,
16
19
  ServiceOperationQuery,
17
- ServiceOperationQueryKey,
18
20
  } from '../ServiceOperation.js';
19
21
 
20
22
  export const useSuspenseInfiniteQuery: <
@@ -36,20 +38,24 @@ export const useSuspenseInfiniteQuery: <
36
38
  schema,
37
39
  args
38
40
  ) => {
39
- const [parameters, options, ...restArgs] = args;
41
+ const [parameters, options, queryClientByArg] = args;
40
42
 
41
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
42
- ?.requestClient;
43
+ const { requestClient, queryClient: queryClientByContext } =
44
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
43
45
 
44
46
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
45
47
 
48
+ const queryKey: ServiceOperationInfiniteQueryKey<
49
+ RequestClientSchema,
50
+ unknown
51
+ > = Array.isArray(parameters)
52
+ ? (parameters as never)
53
+ : composeInfiniteQueryKey(schema, parameters);
54
+
46
55
  return useSuspenseInfiniteQueryTanstack(
47
56
  {
48
57
  ...options,
49
- queryKey: [
50
- { url: schema.url, method: schema.method, infinite: true },
51
- parameters as never,
52
- ] as const,
58
+ queryKey,
53
59
  queryFn:
54
60
  options?.queryFn ??
55
61
  function ({ queryKey: [, queryParams], signal, meta, pageParam }) {
@@ -60,6 +66,6 @@ export const useSuspenseInfiniteQuery: <
60
66
  });
61
67
  },
62
68
  },
63
- ...restArgs
69
+ useQueryClient(queryClientByArg ?? queryClientByContext)
64
70
  ) as never;
65
71
  };
@@ -4,16 +4,15 @@ import { useContext } from 'react';
4
4
 
5
5
  import {
6
6
  SuspenseQueriesResults,
7
+ useQueryClient,
7
8
  useSuspenseQueries as useSuspenseQueriesTanstack,
8
9
  } from '@tanstack/react-query';
9
10
 
11
+ import { composeQueryKey } from '../lib/composeQueryKey.js';
10
12
  import type { QraftClientOptions } from '../qraftAPIClient.js';
11
13
  import { QraftContext } from '../QraftContext.js';
12
14
  import type { RequestClientSchema } from '../RequestClient.js';
13
- import {
14
- ServiceOperationQuery,
15
- ServiceOperationQueryKey,
16
- } from '../ServiceOperation.js';
15
+ import { ServiceOperationQuery } from '../ServiceOperation.js';
17
16
 
18
17
  export const useSuspenseQueries: (
19
18
  qraftOptions: QraftClientOptions | undefined,
@@ -26,33 +25,45 @@ export const useSuspenseQueries: (
26
25
  >['useSuspenseQueries']
27
26
  >
28
27
  ) => SuspenseQueriesResults<never> = (qraftOptions, schema, args) => {
29
- const [options, ...restArgs] = args;
28
+ const [options, queryClientByArg] = args;
30
29
 
31
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
32
- ?.requestClient;
30
+ const { requestClient, queryClient: queryClientByContext } =
31
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
33
32
 
34
33
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
35
34
 
36
35
  return useSuspenseQueriesTanstack(
37
36
  {
38
37
  ...options,
39
- queries: options.queries.map(({ parameters, ...queryOptions }) => ({
40
- ...queryOptions,
41
- queryKey: [
42
- { url: schema.url, method: schema.method },
43
- parameters,
44
- ] satisfies ServiceOperationQueryKey<RequestClientSchema, unknown>,
45
- queryFn:
46
- queryOptions.queryFn ??
47
- function ({ queryKey: [, queryParams], signal, meta }) {
48
- return requestClient(schema, {
49
- parameters: queryParams as never,
50
- signal,
51
- meta,
52
- });
53
- },
54
- })),
38
+ queries: options.queries.map((queryOptions) => {
39
+ const optionsWithQueryKey =
40
+ 'parameters' in queryOptions
41
+ ? (() => {
42
+ const queryOptionsCopy = Object.assign(
43
+ {
44
+ queryKey: composeQueryKey(schema, queryOptions.parameters),
45
+ },
46
+ queryOptions
47
+ );
48
+ delete queryOptionsCopy.parameters;
49
+ return queryOptionsCopy;
50
+ })()
51
+ : queryOptions;
52
+
53
+ return {
54
+ ...optionsWithQueryKey,
55
+ queryFn:
56
+ optionsWithQueryKey.queryFn ??
57
+ function ({ queryKey: [, queryParams], signal, meta }) {
58
+ return requestClient(schema, {
59
+ parameters: queryParams as never,
60
+ signal,
61
+ meta,
62
+ });
63
+ },
64
+ };
65
+ }),
55
66
  },
56
- ...restArgs
67
+ useQueryClient(queryClientByArg ?? queryClientByContext)
57
68
  ) as never;
58
69
  };
@@ -4,10 +4,12 @@ import { useContext } from 'react';
4
4
 
5
5
  import type { DefaultError } from '@tanstack/query-core';
6
6
  import {
7
+ useQueryClient,
7
8
  UseQueryResult,
8
9
  useSuspenseQuery as useSuspenseQueryTanstack,
9
10
  } from '@tanstack/react-query';
10
11
 
12
+ import { composeQueryKey } from '../lib/composeQueryKey.js';
11
13
  import type { QraftClientOptions } from '../qraftAPIClient.js';
12
14
  import { QraftContext } from '../QraftContext.js';
13
15
  import type { RequestClientSchema } from '../RequestClient.js';
@@ -31,17 +33,17 @@ export const useSuspenseQuery: <
31
33
  >['useSuspenseQuery']
32
34
  >
33
35
  ) => UseQueryResult<TData, TError> = (qraftOptions, schema, args) => {
34
- const [parameters, options, ...restArgs] = args;
36
+ const [parameters, options, queryClientByArg] = args;
35
37
 
36
- const requestClient = useContext(qraftOptions?.context ?? QraftContext)
37
- ?.requestClient;
38
+ const { requestClient, queryClient: queryClientByContext } =
39
+ useContext(qraftOptions?.context ?? QraftContext) ?? {};
38
40
 
39
41
  if (!requestClient) throw new Error(`QraftContext.requestClient not found`);
40
42
 
41
- const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> = [
42
- { url: schema.url, method: schema.method },
43
- parameters,
44
- ];
43
+ const queryKey: ServiceOperationQueryKey<RequestClientSchema, unknown> =
44
+ Array.isArray(parameters)
45
+ ? (parameters as never)
46
+ : composeQueryKey(schema, parameters);
45
47
 
46
48
  return useSuspenseQueryTanstack(
47
49
  {
@@ -57,6 +59,6 @@ export const useSuspenseQuery: <
57
59
  });
58
60
  },
59
61
  },
60
- ...restArgs
62
+ useQueryClient(queryClientByArg ?? queryClientByContext)
61
63
  ) as never;
62
64
  };
@@ -0,0 +1,12 @@
1
+ import type { RequestClientSchema } from '../RequestClient.js';
2
+ import { ServiceOperationInfiniteQueryKey } from '../ServiceOperation.js';
3
+
4
+ export function composeInfiniteQueryKey<
5
+ TSchema extends RequestClientSchema,
6
+ TParams,
7
+ >(
8
+ schema: TSchema,
9
+ parameters: TParams | undefined
10
+ ): ServiceOperationInfiniteQueryKey<TSchema, TParams> {
11
+ return [{ ...schema, infinite: true }, parameters ?? ({} as TParams)];
12
+ }
@@ -0,0 +1,9 @@
1
+ import type { RequestClientSchema } from '../RequestClient.js';
2
+ import { ServiceOperationQueryKey } from '../ServiceOperation.js';
3
+
4
+ export function composeQueryKey<TSchema extends RequestClientSchema, TParams>(
5
+ schema: TSchema,
6
+ parameters: TParams | undefined
7
+ ): ServiceOperationQueryKey<TSchema, TParams> {
8
+ return [schema, parameters ?? ({} as TParams)];
9
+ }
@@ -1,25 +1,46 @@
1
- type ProxyCallback = (opts: { path: string[]; args: unknown[] }) => unknown;
1
+ type ProxyApplyCallback = (path: string[], args: unknown[]) => unknown;
2
+ /**
3
+ * @internal
4
+ * If returns `undefined | null`, the proxy will continue to create a new proxy for the next key.
5
+ */
6
+ type ProxyGetCallback = (path: string[], key: string) => unknown | undefined;
2
7
 
3
- export function createRecursiveProxy(callback: ProxyCallback, path: string[]) {
4
- const proxy: unknown = new Proxy(noop, {
8
+ export function createRecursiveProxy(
9
+ getCallback: ProxyGetCallback,
10
+ applyCallback: ProxyApplyCallback,
11
+ path: string[]
12
+ ): unknown {
13
+ return new Proxy(noop, {
5
14
  get(_obj, key) {
6
15
  if (typeof key !== 'string' || key === 'then') {
7
16
  // special case for if the proxy is accidentally treated
8
17
  // like a PromiseLike (like in `Promise.resolve(proxy)`)
9
18
  return undefined;
10
19
  }
11
- return createRecursiveProxy(callback, [...path, key]);
20
+
21
+ return (
22
+ getCallback(path, key) ??
23
+ createRecursiveProxy(getCallback, applyCallback, [...path, key])
24
+ );
12
25
  },
13
26
  apply(_1, _2, args) {
14
- const isApply = path[path.length - 1] === 'apply';
15
- return callback({
16
- args: isApply ? (args.length >= 2 ? args[1] : []) : args,
17
- path: isApply ? path.slice(0, -1) : path,
18
- });
27
+ const functionName = path[path.length - 1];
28
+
29
+ const isCall = functionName === 'call';
30
+ const isApply = isCall ? false : functionName === 'apply';
31
+
32
+ return applyCallback(
33
+ isApply || isCall ? path.slice(0, -1) : path,
34
+ isApply
35
+ ? args.length >= 2
36
+ ? args[1]
37
+ : []
38
+ : isCall
39
+ ? args.slice(1)
40
+ : args
41
+ );
19
42
  },
20
43
  });
21
-
22
- return proxy;
23
44
  }
24
45
 
25
46
  function noop() {
@@ -218,8 +218,26 @@ async function getResponseBody<T>(response: Response): Promise<T | undefined> {
218
218
  const isJSON =
219
219
  contentType?.includes('/json') || contentType?.includes('+json');
220
220
 
221
- // parse response (falling back to .text() when necessary)
222
- if (isJSON) return response.json();
221
+ if (isJSON) {
222
+ // attempt to parse JSON for successful responses, otherwise fail
223
+ if (response.ok) return response.json();
224
+
225
+ const errorFallbackResponse = response.clone(); // clone to allow multiple reads
226
+
227
+ return response.json().catch(() => {
228
+ if (
229
+ typeof process !== 'undefined' &&
230
+ typeof process.env !== 'undefined' &&
231
+ process.env.NODE_ENV === 'development'
232
+ ) {
233
+ console.warn(
234
+ 'Failed to parse response body as JSON. Falling back to .text()'
235
+ );
236
+ }
237
+ // falling back to .text() when necessary for error messages
238
+ return errorFallbackResponse.text();
239
+ });
240
+ }
223
241
 
224
242
  return response.text() as Promise<T>;
225
243
  }
@@ -1,6 +1,6 @@
1
1
  import { Context } from 'react';
2
2
 
3
- import { createCallbackProxyDecoration } from './lib/createCallbackProxyDecoration.js';
3
+ import { createRecursiveProxy } from './lib/createRecursiveProxy.js';
4
4
  import { QraftContextValue } from './QraftContext.js';
5
5
  import type { RequestClientSchema } from './RequestClient.js';
6
6
 
@@ -16,23 +16,35 @@ export const qraftAPIClient = <
16
16
  callbacks: Callbacks,
17
17
  options?: QraftClientOptions
18
18
  ): ServicesCallbacksFilter<Services, keyof Callbacks> => {
19
- return createCallbackProxyDecoration(
20
- Object.keys(callbacks),
21
- (path, functionName, args) => {
19
+ return createRecursiveProxy(
20
+ (getPath, key) => {
21
+ if (getPath.length !== 2 || key !== 'schema') return;
22
+
23
+ const serviceOperation = getByPath(services, getPath);
24
+ if (!isServiceOperation(serviceOperation))
25
+ throw new Error(`Service operation not found: ${getPath.join('.')}`);
26
+ return serviceOperation.schema;
27
+ },
28
+ (applyPath, args) => {
29
+ const path = applyPath.slice(0, -1);
22
30
  const serviceOperation = getByPath(services, path);
31
+
23
32
  if (!isServiceOperation(serviceOperation))
24
33
  throw new Error(`Service operation not found: ${path.join('.')}`);
25
34
 
26
- if (functionName in callbacks) {
27
- return callbacks[functionName as keyof Callbacks](
28
- options,
29
- serviceOperation.schema,
30
- args
31
- );
32
- }
35
+ // The last arg is for instance `.useMutation` or `.useQuery()`
36
+ const functionName = applyPath[applyPath.length - 1];
33
37
 
34
- throw new Error(`Not supported API method: ${String(functionName)}`);
35
- }
38
+ if (!(functionName in callbacks))
39
+ throw new Error(`Function ${functionName} is not supported`);
40
+
41
+ return callbacks[functionName as keyof Callbacks](
42
+ options,
43
+ serviceOperation.schema,
44
+ args
45
+ );
46
+ },
47
+ []
36
48
  ) as never;
37
49
  };
38
50
 
@@ -1,5 +0,0 @@
1
- /**
2
- * Create proxy for decorating procedures
3
- */
4
- export declare function createCallbackProxyDecoration<Functions extends string[] | Readonly<string[]>>(functions: Functions, callback: (path: string[], functionName: Functions[number], args: unknown[]) => unknown): unknown;
5
- //# sourceMappingURL=createCallbackProxyDecoration.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createCallbackProxyDecoration.d.ts","sourceRoot":"","sources":["../../src/lib/createCallbackProxyDecoration.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,SAAS,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAE/C,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EAAE,EACd,YAAY,EAAE,SAAS,CAAC,MAAM,CAAC,EAC/B,IAAI,EAAE,OAAO,EAAE,KACZ,OAAO,WAoBb"}