@navios/react-query 0.7.1 → 1.0.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 +171 -1
- package/README.md +152 -4
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/client/declare-client.mts.html +1264 -0
- package/coverage/client/index.html +116 -0
- package/coverage/clover.xml +160 -0
- package/coverage/coverage-final.json +8 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +146 -0
- package/coverage/mutation/index.html +131 -0
- package/coverage/mutation/key-creator.mts.html +277 -0
- package/coverage/mutation/make-hook.mts.html +952 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/query/index.html +161 -0
- package/coverage/query/key-creator.mts.html +415 -0
- package/coverage/query/make-infinite-options.mts.html +601 -0
- package/coverage/query/make-options.mts.html +838 -0
- package/coverage/query/prefetch.mts.html +1063 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/src/__tests__/errorSchema.spec.d.mts +2 -0
- package/dist/src/__tests__/errorSchema.spec.d.mts.map +1 -0
- package/dist/src/__tests__/prefetch.spec.d.mts +2 -0
- package/dist/src/__tests__/prefetch.spec.d.mts.map +1 -0
- package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts +2 -0
- package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts.map +1 -0
- package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts +2 -0
- package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts.map +1 -0
- package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts +2 -0
- package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts.map +1 -0
- package/dist/src/client/__type-tests__/mutation.spec-d.d.mts +2 -0
- package/dist/src/client/__type-tests__/mutation.spec-d.d.mts.map +1 -0
- package/dist/src/client/__type-tests__/query.spec-d.d.mts +2 -0
- package/dist/src/client/__type-tests__/query.spec-d.d.mts.map +1 -0
- package/dist/src/client/declare-client.d.mts +15 -8
- package/dist/src/client/declare-client.d.mts.map +1 -1
- package/dist/src/client/types/from-endpoint.d.mts +130 -0
- package/dist/src/client/types/from-endpoint.d.mts.map +1 -0
- package/dist/src/client/types/helpers.d.mts +74 -0
- package/dist/src/client/types/helpers.d.mts.map +1 -0
- package/dist/src/client/types/index.d.mts +21 -0
- package/dist/src/client/types/index.d.mts.map +1 -0
- package/dist/src/client/types/infinite-query.d.mts +61 -0
- package/dist/src/client/types/infinite-query.d.mts.map +1 -0
- package/dist/src/client/types/multipart-mutation.d.mts +98 -0
- package/dist/src/client/types/multipart-mutation.d.mts.map +1 -0
- package/dist/src/client/types/mutation.d.mts +75 -0
- package/dist/src/client/types/mutation.d.mts.map +1 -0
- package/dist/src/client/types/query.d.mts +65 -0
- package/dist/src/client/types/query.d.mts.map +1 -0
- package/dist/src/client/types.d.mts +1 -608
- package/dist/src/client/types.d.mts.map +1 -1
- package/dist/src/common/types.d.mts +40 -3
- package/dist/src/common/types.d.mts.map +1 -1
- package/dist/src/mutation/index.d.mts +1 -0
- package/dist/src/mutation/index.d.mts.map +1 -1
- package/dist/src/mutation/make-hook.d.mts +42 -16
- package/dist/src/mutation/make-hook.d.mts.map +1 -1
- package/dist/src/mutation/optimistic.d.mts +172 -0
- package/dist/src/mutation/optimistic.d.mts.map +1 -0
- package/dist/src/mutation/types.d.mts +41 -20
- package/dist/src/mutation/types.d.mts.map +1 -1
- package/dist/src/query/index.d.mts +1 -0
- package/dist/src/query/index.d.mts.map +1 -1
- package/dist/src/query/key-creator.d.mts.map +1 -1
- package/dist/src/query/make-infinite-options.d.mts +3 -2
- package/dist/src/query/make-infinite-options.d.mts.map +1 -1
- package/dist/src/query/make-options.d.mts +42 -12
- package/dist/src/query/make-options.d.mts.map +1 -1
- package/dist/src/query/prefetch.d.mts +245 -0
- package/dist/src/query/prefetch.d.mts.map +1 -0
- package/dist/src/query/types.d.mts +25 -18
- package/dist/src/query/types.d.mts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/index.cjs +451 -28
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +1019 -600
- package/lib/index.d.cts.map +1 -1
- package/lib/index.d.mts +1016 -597
- package/lib/index.d.mts.map +1 -1
- package/lib/index.mjs +447 -29
- package/lib/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/declare-client.spec.mts +229 -2
- package/src/__tests__/errorSchema.spec.mts +391 -0
- package/src/__tests__/make-mutation.spec.mts +6 -5
- package/src/__tests__/makeDataTag.spec.mts +2 -1
- package/src/__tests__/makeQueryOptions.spec.mts +2 -1
- package/src/__tests__/prefetch.spec.mts +310 -0
- package/src/client/__type-tests__/from-endpoint.spec-d.mts +550 -0
- package/src/client/__type-tests__/infinite-query.spec-d.mts +648 -0
- package/src/client/__type-tests__/multipart-mutation.spec-d.mts +725 -0
- package/src/client/__type-tests__/mutation.spec-d.mts +757 -0
- package/src/client/__type-tests__/query.spec-d.mts +701 -0
- package/src/client/declare-client.mts +59 -34
- package/src/client/types/from-endpoint.mts +344 -0
- package/src/client/types/helpers.mts +140 -0
- package/src/client/types/index.mts +26 -0
- package/src/client/types/infinite-query.mts +133 -0
- package/src/client/types/multipart-mutation.mts +264 -0
- package/src/client/types/mutation.mts +176 -0
- package/src/client/types/query.mts +132 -0
- package/src/client/types.mts +1 -1935
- package/src/common/types.mts +67 -3
- package/src/mutation/index.mts +1 -0
- package/src/mutation/make-hook.mts +171 -63
- package/src/mutation/optimistic.mts +300 -0
- package/src/mutation/types.mts +87 -30
- package/src/query/index.mts +1 -0
- package/src/query/key-creator.mts +24 -13
- package/src/query/make-infinite-options.mts +53 -10
- package/src/query/make-options.mts +184 -43
- package/src/query/prefetch.mts +326 -0
- package/src/query/types.mts +56 -17
- package/src/client/__type-tests__/client-instance.spec-d.mts +0 -852
|
@@ -1,34 +1,83 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
EndpointHandler,
|
|
3
|
+
EndpointOptions,
|
|
4
|
+
InferEndpointReturn,
|
|
5
|
+
Simplify,
|
|
6
|
+
} from '@navios/builder'
|
|
2
7
|
import type {
|
|
3
8
|
DataTag,
|
|
4
9
|
QueryClient,
|
|
5
10
|
UseQueryOptions,
|
|
6
11
|
UseSuspenseQueryOptions,
|
|
7
12
|
} from '@tanstack/react-query'
|
|
13
|
+
import type { ZodObject, ZodType } from 'zod/v4'
|
|
8
14
|
|
|
9
15
|
import { queryOptions, useQuery, useSuspenseQuery } from '@tanstack/react-query'
|
|
10
16
|
|
|
11
17
|
import type { Split } from '../common/types.mjs'
|
|
12
|
-
import type { QueryArgs,
|
|
18
|
+
import type { QueryArgs, QueryHelpers, QueryResult } from './types.mjs'
|
|
13
19
|
|
|
14
20
|
import { createQueryKey } from './key-creator.mjs'
|
|
15
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Options for makeQueryOptions.
|
|
24
|
+
*/
|
|
25
|
+
export interface MakeQueryOptionsParams<
|
|
26
|
+
Options extends EndpointOptions,
|
|
27
|
+
UseDiscriminator extends boolean = false,
|
|
28
|
+
Result = QueryResult<Options, UseDiscriminator>,
|
|
29
|
+
> {
|
|
30
|
+
keyPrefix?: string[]
|
|
31
|
+
keySuffix?: string[]
|
|
32
|
+
onFail?: (err: unknown) => void
|
|
33
|
+
processResponse: (
|
|
34
|
+
data: InferEndpointReturn<Options, UseDiscriminator>,
|
|
35
|
+
) => Result
|
|
36
|
+
}
|
|
37
|
+
|
|
16
38
|
/**
|
|
17
39
|
* Creates query options for a given endpoint.
|
|
18
40
|
*
|
|
19
41
|
* Returns a function that generates TanStack Query options when called with params.
|
|
20
42
|
* The returned function also has helper methods attached (use, useSuspense, invalidate, etc.)
|
|
21
43
|
*
|
|
22
|
-
*
|
|
44
|
+
* Uses const generics pattern to automatically infer types from the endpoint configuration.
|
|
45
|
+
*
|
|
46
|
+
* @param endpoint - The navios endpoint handler (from builder's declareEndpoint)
|
|
23
47
|
* @param options - Query configuration including processResponse
|
|
24
48
|
* @param baseQuery - Optional base query options to merge
|
|
25
49
|
* @returns A function that generates query options with attached helpers
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const getUser = api.declareEndpoint({
|
|
54
|
+
* method: 'GET',
|
|
55
|
+
* url: '/users/$userId',
|
|
56
|
+
* responseSchema: userSchema,
|
|
57
|
+
* })
|
|
58
|
+
*
|
|
59
|
+
* const queryOptions = makeQueryOptions(getUser, {
|
|
60
|
+
* processResponse: (data) => data,
|
|
61
|
+
* })
|
|
62
|
+
*
|
|
63
|
+
* const { data } = queryOptions.useSuspense({ urlParams: { userId: '123' } })
|
|
64
|
+
* ```
|
|
26
65
|
*/
|
|
27
66
|
export function makeQueryOptions<
|
|
28
|
-
|
|
29
|
-
|
|
67
|
+
const Options extends EndpointOptions,
|
|
68
|
+
UseDiscriminator extends boolean = false,
|
|
69
|
+
Result = QueryResult<Options, UseDiscriminator>,
|
|
30
70
|
BaseQuery extends Omit<
|
|
31
|
-
UseQueryOptions<
|
|
71
|
+
UseQueryOptions<Result, Error, any>,
|
|
72
|
+
| 'queryKey'
|
|
73
|
+
| 'queryFn'
|
|
74
|
+
| 'getNextPageParam'
|
|
75
|
+
| 'initialPageParam'
|
|
76
|
+
| 'enabled'
|
|
77
|
+
| 'throwOnError'
|
|
78
|
+
| 'placeholderData'
|
|
79
|
+
> = Omit<
|
|
80
|
+
UseQueryOptions<Result, Error, any>,
|
|
32
81
|
| 'queryKey'
|
|
33
82
|
| 'queryFn'
|
|
34
83
|
| 'getNextPageParam'
|
|
@@ -38,34 +87,58 @@ export function makeQueryOptions<
|
|
|
38
87
|
| 'placeholderData'
|
|
39
88
|
>,
|
|
40
89
|
>(
|
|
41
|
-
endpoint:
|
|
42
|
-
options: Options,
|
|
43
|
-
baseQuery
|
|
44
|
-
)
|
|
90
|
+
endpoint: EndpointHandler<Options, UseDiscriminator>,
|
|
91
|
+
options: MakeQueryOptionsParams<Options, UseDiscriminator, Result>,
|
|
92
|
+
baseQuery?: BaseQuery,
|
|
93
|
+
): ((
|
|
94
|
+
params: Simplify<
|
|
95
|
+
QueryArgs<
|
|
96
|
+
Options['url'],
|
|
97
|
+
Options extends { querySchema: infer Q extends ZodObject }
|
|
98
|
+
? Q
|
|
99
|
+
: undefined,
|
|
100
|
+
Options extends { requestSchema: infer R extends ZodType } ? R : undefined
|
|
101
|
+
>
|
|
102
|
+
>,
|
|
103
|
+
) => UseSuspenseQueryOptions<
|
|
104
|
+
Result,
|
|
105
|
+
Error,
|
|
106
|
+
BaseQuery extends { select: (...args: any[]) => infer T } ? T : Result,
|
|
107
|
+
DataTag<Split<Options['url'], '/'>, Result, Error>
|
|
108
|
+
>) &
|
|
109
|
+
QueryHelpers<
|
|
110
|
+
Options['url'],
|
|
111
|
+
Options extends { querySchema: infer Q extends ZodObject } ? Q : undefined,
|
|
112
|
+
Result,
|
|
113
|
+
false,
|
|
114
|
+
Options extends { requestSchema: infer R extends ZodType } ? R : undefined
|
|
115
|
+
> {
|
|
45
116
|
const config = endpoint.config
|
|
46
|
-
const queryKey = createQueryKey(config, options, false)
|
|
117
|
+
const queryKey = createQueryKey(config as any, options as any, false)
|
|
47
118
|
const processResponse = options.processResponse
|
|
48
119
|
|
|
49
120
|
const result = (
|
|
50
|
-
params:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
121
|
+
params: Simplify<
|
|
122
|
+
QueryArgs<
|
|
123
|
+
Options['url'],
|
|
124
|
+
Options extends { querySchema: infer Q extends ZodObject }
|
|
125
|
+
? Q
|
|
126
|
+
: undefined,
|
|
127
|
+
Options extends { requestSchema: infer R extends ZodType }
|
|
128
|
+
? R
|
|
129
|
+
: undefined
|
|
57
130
|
>
|
|
58
|
-
|
|
59
|
-
|
|
131
|
+
>,
|
|
132
|
+
): any => {
|
|
60
133
|
return queryOptions({
|
|
61
|
-
queryKey: queryKey.dataTag(params),
|
|
62
|
-
queryFn: async ({ signal }): Promise<
|
|
134
|
+
queryKey: queryKey.dataTag(params as any),
|
|
135
|
+
queryFn: async ({ signal }): Promise<Result> => {
|
|
63
136
|
let result
|
|
64
137
|
try {
|
|
65
138
|
result = await endpoint({
|
|
66
139
|
signal,
|
|
67
140
|
...params,
|
|
68
|
-
})
|
|
141
|
+
} as any)
|
|
69
142
|
} catch (err) {
|
|
70
143
|
if (options.onFail) {
|
|
71
144
|
options.onFail(err)
|
|
@@ -73,38 +146,106 @@ export function makeQueryOptions<
|
|
|
73
146
|
throw err
|
|
74
147
|
}
|
|
75
148
|
|
|
76
|
-
return processResponse(result)
|
|
149
|
+
return processResponse(result)
|
|
77
150
|
},
|
|
78
151
|
...baseQuery,
|
|
79
152
|
})
|
|
80
153
|
}
|
|
81
|
-
|
|
82
|
-
|
|
154
|
+
|
|
155
|
+
/** The query key creator for this endpoint */
|
|
156
|
+
result.queryKey = queryKey as any
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* React hook that executes the query.
|
|
160
|
+
* Uses `useQuery` from TanStack Query internally.
|
|
161
|
+
*
|
|
162
|
+
* @param params - URL parameters, query parameters, and request body
|
|
163
|
+
* @returns Query result with data, isLoading, error, etc.
|
|
164
|
+
*/
|
|
165
|
+
result.use = (params: any) => {
|
|
83
166
|
return useQuery(result(params))
|
|
84
167
|
}
|
|
85
168
|
|
|
86
|
-
|
|
169
|
+
/**
|
|
170
|
+
* React hook that executes the query with Suspense support.
|
|
171
|
+
* Uses `useSuspenseQuery` from TanStack Query internally.
|
|
172
|
+
* The component will suspend while loading and throw on error.
|
|
173
|
+
*
|
|
174
|
+
* @param params - URL parameters, query parameters, and request body
|
|
175
|
+
* @returns Query result with data guaranteed to be defined
|
|
176
|
+
*/
|
|
177
|
+
result.useSuspense = (params: any) => {
|
|
87
178
|
return useSuspenseQuery(result(params))
|
|
88
179
|
}
|
|
89
180
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Creates a function that invalidates a specific query in the cache.
|
|
183
|
+
* Call the returned function to trigger the invalidation.
|
|
184
|
+
*
|
|
185
|
+
* @param queryClient - The TanStack Query client instance
|
|
186
|
+
* @param params - The exact parameters used for this query
|
|
187
|
+
* @returns A function that when called invalidates the query
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* const invalidate = getUser.invalidate(queryClient, { urlParams: { userId: '123' } })
|
|
192
|
+
* await invalidate() // Invalidates this specific query
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
result.invalidate = (queryClient: QueryClient, params: any) => {
|
|
196
|
+
return () =>
|
|
197
|
+
queryClient.invalidateQueries({
|
|
198
|
+
queryKey: result.queryKey.dataTag(params),
|
|
199
|
+
})
|
|
97
200
|
}
|
|
98
201
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Creates a function that invalidates all queries matching the URL pattern.
|
|
204
|
+
* Useful for invalidating all queries for a resource regardless of query params.
|
|
205
|
+
*
|
|
206
|
+
* @param queryClient - The TanStack Query client instance
|
|
207
|
+
* @param params - URL parameters only (query params are ignored for matching)
|
|
208
|
+
* @returns A function that when called invalidates all matching queries
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* const invalidateAll = getUserPosts.invalidateAll(queryClient, { urlParams: { userId: '123' } })
|
|
213
|
+
* await invalidateAll() // Invalidates all getUserPosts queries for user 123
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
result.invalidateAll = (queryClient: QueryClient, params: any) => {
|
|
217
|
+
return () =>
|
|
218
|
+
queryClient.invalidateQueries({
|
|
219
|
+
queryKey: result.queryKey.filterKey(params),
|
|
220
|
+
exact: false,
|
|
221
|
+
})
|
|
107
222
|
}
|
|
108
223
|
|
|
109
|
-
return result
|
|
224
|
+
return result as unknown as ((
|
|
225
|
+
params: Simplify<
|
|
226
|
+
QueryArgs<
|
|
227
|
+
Options['url'],
|
|
228
|
+
Options extends { querySchema: infer Q extends ZodObject }
|
|
229
|
+
? Q
|
|
230
|
+
: undefined,
|
|
231
|
+
Options extends { requestSchema: infer R extends ZodType }
|
|
232
|
+
? R
|
|
233
|
+
: undefined
|
|
234
|
+
>
|
|
235
|
+
>,
|
|
236
|
+
) => UseSuspenseQueryOptions<
|
|
237
|
+
Result,
|
|
238
|
+
Error,
|
|
239
|
+
BaseQuery extends { select: (...args: any[]) => infer T } ? T : Result,
|
|
240
|
+
DataTag<Split<Options['url'], '/'>, Result, Error>
|
|
241
|
+
>) &
|
|
242
|
+
QueryHelpers<
|
|
243
|
+
Options['url'],
|
|
244
|
+
Options extends { querySchema: infer Q extends ZodObject }
|
|
245
|
+
? Q
|
|
246
|
+
: undefined,
|
|
247
|
+
Result,
|
|
248
|
+
false,
|
|
249
|
+
Options extends { requestSchema: infer R extends ZodType } ? R : undefined
|
|
250
|
+
>
|
|
110
251
|
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FetchQueryOptions,
|
|
3
|
+
QueryClient,
|
|
4
|
+
QueryKey,
|
|
5
|
+
} from '@tanstack/react-query'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Type for a query options creator function that returns TanStack Query options.
|
|
9
|
+
*
|
|
10
|
+
* This matches the return type of `client.query()` from the navios react-query client.
|
|
11
|
+
*/
|
|
12
|
+
export type QueryOptionsCreator<TParams, TData, TError = Error> = (
|
|
13
|
+
params: TParams,
|
|
14
|
+
) => FetchQueryOptions<TData, TError, TData, QueryKey>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Helper utilities for prefetching queries.
|
|
18
|
+
*
|
|
19
|
+
* @template TParams - The query parameters type
|
|
20
|
+
* @template TData - The query data type
|
|
21
|
+
* @template TError - The error type (defaults to Error)
|
|
22
|
+
*/
|
|
23
|
+
export interface PrefetchHelper<TParams, TData, TError = Error> {
|
|
24
|
+
/**
|
|
25
|
+
* Prefetch query data on the server.
|
|
26
|
+
*
|
|
27
|
+
* Use this in server components or getServerSideProps to
|
|
28
|
+
* prefetch data before rendering.
|
|
29
|
+
*
|
|
30
|
+
* @param queryClient - The QueryClient instance
|
|
31
|
+
* @param params - Parameters for the query
|
|
32
|
+
* @returns Promise that resolves when prefetch is complete
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* // In a Next.js Server Component
|
|
37
|
+
* const queryClient = new QueryClient()
|
|
38
|
+
* await prefetch.prefetch(queryClient, { urlParams: { userId: '1' } })
|
|
39
|
+
* return (
|
|
40
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
41
|
+
* <UserProfile userId="1" />
|
|
42
|
+
* </HydrationBoundary>
|
|
43
|
+
* )
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
prefetch: (queryClient: QueryClient, params: TParams) => Promise<void>
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Ensure query data exists in cache. Fetches only if not cached.
|
|
50
|
+
*
|
|
51
|
+
* Returns the cached or fetched data.
|
|
52
|
+
*
|
|
53
|
+
* @param queryClient - The QueryClient instance
|
|
54
|
+
* @param params - Parameters for the query
|
|
55
|
+
* @returns Promise that resolves to the query data
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* // Ensure data exists before rendering
|
|
60
|
+
* const userData = await prefetch.ensureData(queryClient, {
|
|
61
|
+
* urlParams: { userId: '1' },
|
|
62
|
+
* })
|
|
63
|
+
* console.log('User:', userData.name)
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
ensureData: (queryClient: QueryClient, params: TParams) => Promise<TData>
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get the query options for a given set of parameters.
|
|
70
|
+
*
|
|
71
|
+
* Useful for advanced use cases or when you need to
|
|
72
|
+
* customize the prefetch behavior.
|
|
73
|
+
*
|
|
74
|
+
* @param params - Parameters for the query
|
|
75
|
+
* @returns The query options object
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```tsx
|
|
79
|
+
* const options = prefetch.getQueryOptions({ urlParams: { userId: '1' } })
|
|
80
|
+
* await queryClient.prefetchQuery({
|
|
81
|
+
* ...options,
|
|
82
|
+
* staleTime: 60000, // Override stale time for prefetch
|
|
83
|
+
* })
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
getQueryOptions: (
|
|
87
|
+
params: TParams,
|
|
88
|
+
) => FetchQueryOptions<TData, TError, TData, QueryKey>
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Prefetch multiple queries in parallel.
|
|
92
|
+
*
|
|
93
|
+
* @param queryClient - The QueryClient instance
|
|
94
|
+
* @param paramsList - Array of parameters for multiple queries
|
|
95
|
+
* @returns Promise that resolves when all prefetches complete
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```tsx
|
|
99
|
+
* // Prefetch multiple users in parallel
|
|
100
|
+
* await prefetch.prefetchMany(queryClient, [
|
|
101
|
+
* { urlParams: { userId: '1' } },
|
|
102
|
+
* { urlParams: { userId: '2' } },
|
|
103
|
+
* { urlParams: { userId: '3' } },
|
|
104
|
+
* ])
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
prefetchMany: (
|
|
108
|
+
queryClient: QueryClient,
|
|
109
|
+
paramsList: TParams[],
|
|
110
|
+
) => Promise<void>
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Creates a type-safe prefetch helper for SSR/RSC.
|
|
115
|
+
*
|
|
116
|
+
* This utility wraps a query options creator to provide convenient
|
|
117
|
+
* methods for server-side data fetching and hydration.
|
|
118
|
+
*
|
|
119
|
+
* @param queryOptionsCreator - A function that creates query options (from client.query())
|
|
120
|
+
* @returns A prefetch helper object with prefetch, ensureData, and getQueryOptions methods
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* // 1. Create your query
|
|
125
|
+
* const getUserQuery = client.query({
|
|
126
|
+
* method: 'GET',
|
|
127
|
+
* url: '/users/$userId',
|
|
128
|
+
* responseSchema: userSchema,
|
|
129
|
+
* })
|
|
130
|
+
*
|
|
131
|
+
* // 2. Create prefetch helper
|
|
132
|
+
* const userPrefetch = createPrefetchHelper(getUserQuery)
|
|
133
|
+
*
|
|
134
|
+
* // 3. Use in server component
|
|
135
|
+
* async function UserPage({ userId }: { userId: string }) {
|
|
136
|
+
* const queryClient = new QueryClient()
|
|
137
|
+
*
|
|
138
|
+
* await userPrefetch.prefetch(queryClient, {
|
|
139
|
+
* urlParams: { userId },
|
|
140
|
+
* })
|
|
141
|
+
*
|
|
142
|
+
* return (
|
|
143
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
144
|
+
* <UserProfile userId={userId} />
|
|
145
|
+
* </HydrationBoundary>
|
|
146
|
+
* )
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```tsx
|
|
152
|
+
* // With Next.js App Router
|
|
153
|
+
* import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
|
|
154
|
+
* import { createPrefetchHelper } from '@navios/react-query'
|
|
155
|
+
*
|
|
156
|
+
* // Define queries
|
|
157
|
+
* const getPostsQuery = client.query({
|
|
158
|
+
* method: 'GET',
|
|
159
|
+
* url: '/posts',
|
|
160
|
+
* querySchema: z.object({ page: z.number() }),
|
|
161
|
+
* responseSchema: postsSchema,
|
|
162
|
+
* })
|
|
163
|
+
*
|
|
164
|
+
* const postsPrefetch = createPrefetchHelper(getPostsQuery)
|
|
165
|
+
*
|
|
166
|
+
* // Server Component
|
|
167
|
+
* export default async function PostsPage() {
|
|
168
|
+
* const queryClient = new QueryClient()
|
|
169
|
+
*
|
|
170
|
+
* await postsPrefetch.prefetch(queryClient, {
|
|
171
|
+
* params: { page: 1 },
|
|
172
|
+
* })
|
|
173
|
+
*
|
|
174
|
+
* return (
|
|
175
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
176
|
+
* <PostsList />
|
|
177
|
+
* </HydrationBoundary>
|
|
178
|
+
* )
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export function createPrefetchHelper<TParams, TData, TError = Error>(
|
|
183
|
+
queryOptionsCreator: QueryOptionsCreator<TParams, TData, TError>,
|
|
184
|
+
): PrefetchHelper<TParams, TData, TError> {
|
|
185
|
+
return {
|
|
186
|
+
prefetch: async (queryClient: QueryClient, params: TParams) => {
|
|
187
|
+
const options = queryOptionsCreator(params)
|
|
188
|
+
await queryClient.prefetchQuery(options)
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
ensureData: async (queryClient: QueryClient, params: TParams) => {
|
|
192
|
+
const options = queryOptionsCreator(params)
|
|
193
|
+
return queryClient.ensureQueryData(options)
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
getQueryOptions: (params: TParams) => {
|
|
197
|
+
return queryOptionsCreator(params)
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
prefetchMany: async (queryClient: QueryClient, paramsList: TParams[]) => {
|
|
201
|
+
await Promise.all(
|
|
202
|
+
paramsList.map((params) => {
|
|
203
|
+
const options = queryOptionsCreator(params)
|
|
204
|
+
return queryClient.prefetchQuery(options)
|
|
205
|
+
}),
|
|
206
|
+
)
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Creates multiple prefetch helpers from a record of query options creators.
|
|
213
|
+
*
|
|
214
|
+
* Useful when you have multiple queries that need to be prefetched together.
|
|
215
|
+
*
|
|
216
|
+
* @param queries - Record of query options creator functions
|
|
217
|
+
* @returns Record of prefetch helpers with the same keys
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```tsx
|
|
221
|
+
* // Define all your queries
|
|
222
|
+
* const queries = {
|
|
223
|
+
* user: client.query({
|
|
224
|
+
* method: 'GET',
|
|
225
|
+
* url: '/users/$userId',
|
|
226
|
+
* responseSchema: userSchema,
|
|
227
|
+
* }),
|
|
228
|
+
* posts: client.query({
|
|
229
|
+
* method: 'GET',
|
|
230
|
+
* url: '/users/$userId/posts',
|
|
231
|
+
* responseSchema: postsSchema,
|
|
232
|
+
* }),
|
|
233
|
+
* }
|
|
234
|
+
*
|
|
235
|
+
* // Create all prefetch helpers at once
|
|
236
|
+
* const prefetchers = createPrefetchHelpers(queries)
|
|
237
|
+
*
|
|
238
|
+
* // Use in server component
|
|
239
|
+
* async function UserPage({ userId }: { userId: string }) {
|
|
240
|
+
* const queryClient = new QueryClient()
|
|
241
|
+
*
|
|
242
|
+
* await Promise.all([
|
|
243
|
+
* prefetchers.user.prefetch(queryClient, { urlParams: { userId } }),
|
|
244
|
+
* prefetchers.posts.prefetch(queryClient, { urlParams: { userId } }),
|
|
245
|
+
* ])
|
|
246
|
+
*
|
|
247
|
+
* return (
|
|
248
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
249
|
+
* <UserProfileWithPosts userId={userId} />
|
|
250
|
+
* </HydrationBoundary>
|
|
251
|
+
* )
|
|
252
|
+
* }
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export function createPrefetchHelpers<
|
|
256
|
+
T extends Record<string, QueryOptionsCreator<any, any, any>>,
|
|
257
|
+
>(
|
|
258
|
+
queries: T,
|
|
259
|
+
): {
|
|
260
|
+
[K in keyof T]: T[K] extends QueryOptionsCreator<
|
|
261
|
+
infer TParams,
|
|
262
|
+
infer TData,
|
|
263
|
+
infer TError
|
|
264
|
+
>
|
|
265
|
+
? PrefetchHelper<TParams, TData, TError>
|
|
266
|
+
: never
|
|
267
|
+
} {
|
|
268
|
+
const result = {} as {
|
|
269
|
+
[K in keyof T]: T[K] extends QueryOptionsCreator<
|
|
270
|
+
infer TParams,
|
|
271
|
+
infer TData,
|
|
272
|
+
infer TError
|
|
273
|
+
>
|
|
274
|
+
? PrefetchHelper<TParams, TData, TError>
|
|
275
|
+
: never
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for (const key of Object.keys(queries) as Array<keyof T>) {
|
|
279
|
+
// @ts-expect-error - TypeScript can't infer this properly
|
|
280
|
+
result[key] = createPrefetchHelper(queries[key])
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return result
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Prefetch multiple queries from different query creators in parallel.
|
|
288
|
+
*
|
|
289
|
+
* @param queryClient - The QueryClient instance
|
|
290
|
+
* @param prefetches - Array of { helper, params } objects
|
|
291
|
+
* @returns Promise that resolves when all prefetches complete
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```tsx
|
|
295
|
+
* const userPrefetch = createPrefetchHelper(getUserQuery)
|
|
296
|
+
* const postsPrefetch = createPrefetchHelper(getPostsQuery)
|
|
297
|
+
*
|
|
298
|
+
* async function DashboardPage({ userId }: { userId: string }) {
|
|
299
|
+
* const queryClient = new QueryClient()
|
|
300
|
+
*
|
|
301
|
+
* await prefetchAll(queryClient, [
|
|
302
|
+
* { helper: userPrefetch, params: { urlParams: { userId } } },
|
|
303
|
+
* { helper: postsPrefetch, params: { urlParams: { userId }, params: { limit: 10 } } },
|
|
304
|
+
* ])
|
|
305
|
+
*
|
|
306
|
+
* return (
|
|
307
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
308
|
+
* <Dashboard userId={userId} />
|
|
309
|
+
* </HydrationBoundary>
|
|
310
|
+
* )
|
|
311
|
+
* }
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
export async function prefetchAll(
|
|
315
|
+
queryClient: QueryClient,
|
|
316
|
+
prefetches: Array<{
|
|
317
|
+
helper: PrefetchHelper<any, any, any>
|
|
318
|
+
params: unknown
|
|
319
|
+
}>,
|
|
320
|
+
): Promise<void> {
|
|
321
|
+
await Promise.all(
|
|
322
|
+
prefetches.map(({ helper, params }) =>
|
|
323
|
+
helper.prefetch(queryClient, params),
|
|
324
|
+
),
|
|
325
|
+
)
|
|
326
|
+
}
|