@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
package/lib/index.mjs
CHANGED
|
@@ -15,27 +15,28 @@ import { infiniteQueryOptions, queryOptions, useInfiniteQuery, useIsMutating, us
|
|
|
15
15
|
*/
|
|
16
16
|
function createQueryKey(config, options, _isInfinite) {
|
|
17
17
|
const url = config.url;
|
|
18
|
-
const urlParts = url.split("/").filter(Boolean);
|
|
19
18
|
return {
|
|
20
|
-
template:
|
|
19
|
+
template: url.split("/").filter(Boolean),
|
|
21
20
|
dataTag: (params) => {
|
|
22
21
|
const queryParams = params && "querySchema" in config && "params" in params ? config.querySchema?.parse(params.params) : [];
|
|
22
|
+
const boundUrlParts = bindUrlParams(url, params && "urlParams" in params ? params : {}, config.urlParamsSchema).split("/").filter(Boolean);
|
|
23
23
|
return [
|
|
24
24
|
...options.keyPrefix ?? [],
|
|
25
|
-
...
|
|
25
|
+
...boundUrlParts,
|
|
26
26
|
...options.keySuffix ?? [],
|
|
27
27
|
queryParams ?? []
|
|
28
28
|
];
|
|
29
29
|
},
|
|
30
30
|
filterKey: (params) => {
|
|
31
|
+
const boundUrlParts = bindUrlParams(url, params && "urlParams" in params ? params : {}, config.urlParamsSchema).split("/").filter(Boolean);
|
|
31
32
|
return [
|
|
32
33
|
...options.keyPrefix ?? [],
|
|
33
|
-
...
|
|
34
|
+
...boundUrlParts,
|
|
34
35
|
...options.keySuffix ?? []
|
|
35
36
|
];
|
|
36
37
|
},
|
|
37
38
|
bindToUrl: (params) => {
|
|
38
|
-
return bindUrlParams(url, params
|
|
39
|
+
return bindUrlParams(url, params && "urlParams" in params ? params : {}, config.urlParamsSchema);
|
|
39
40
|
}
|
|
40
41
|
};
|
|
41
42
|
}
|
|
@@ -50,12 +51,29 @@ const queryKeyCreator = createQueryKey;
|
|
|
50
51
|
* Returns a function that generates TanStack Query options when called with params.
|
|
51
52
|
* The returned function also has helper methods attached (use, useSuspense, invalidate, etc.)
|
|
52
53
|
*
|
|
53
|
-
*
|
|
54
|
+
* Uses const generics pattern to automatically infer types from the endpoint configuration.
|
|
55
|
+
*
|
|
56
|
+
* @param endpoint - The navios endpoint handler (from builder's declareEndpoint)
|
|
54
57
|
* @param options - Query configuration including processResponse
|
|
55
58
|
* @param baseQuery - Optional base query options to merge
|
|
56
59
|
* @returns A function that generates query options with attached helpers
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const getUser = api.declareEndpoint({
|
|
64
|
+
* method: 'GET',
|
|
65
|
+
* url: '/users/$userId',
|
|
66
|
+
* responseSchema: userSchema,
|
|
67
|
+
* })
|
|
68
|
+
*
|
|
69
|
+
* const queryOptions = makeQueryOptions(getUser, {
|
|
70
|
+
* processResponse: (data) => data,
|
|
71
|
+
* })
|
|
72
|
+
*
|
|
73
|
+
* const { data } = queryOptions.useSuspense({ urlParams: { userId: '123' } })
|
|
74
|
+
* ```
|
|
57
75
|
*/
|
|
58
|
-
function makeQueryOptions(endpoint, options, baseQuery
|
|
76
|
+
function makeQueryOptions(endpoint, options, baseQuery) {
|
|
59
77
|
const config = endpoint.config;
|
|
60
78
|
const queryKey = createQueryKey(config, options, false);
|
|
61
79
|
const processResponse = options.processResponse;
|
|
@@ -78,18 +96,62 @@ function makeQueryOptions(endpoint, options, baseQuery = {}) {
|
|
|
78
96
|
...baseQuery
|
|
79
97
|
});
|
|
80
98
|
};
|
|
99
|
+
/** The query key creator for this endpoint */
|
|
81
100
|
result.queryKey = queryKey;
|
|
101
|
+
/**
|
|
102
|
+
* React hook that executes the query.
|
|
103
|
+
* Uses `useQuery` from TanStack Query internally.
|
|
104
|
+
*
|
|
105
|
+
* @param params - URL parameters, query parameters, and request body
|
|
106
|
+
* @returns Query result with data, isLoading, error, etc.
|
|
107
|
+
*/
|
|
82
108
|
result.use = (params) => {
|
|
83
109
|
return useQuery(result(params));
|
|
84
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* React hook that executes the query with Suspense support.
|
|
113
|
+
* Uses `useSuspenseQuery` from TanStack Query internally.
|
|
114
|
+
* The component will suspend while loading and throw on error.
|
|
115
|
+
*
|
|
116
|
+
* @param params - URL parameters, query parameters, and request body
|
|
117
|
+
* @returns Query result with data guaranteed to be defined
|
|
118
|
+
*/
|
|
85
119
|
result.useSuspense = (params) => {
|
|
86
120
|
return useSuspenseQuery(result(params));
|
|
87
121
|
};
|
|
122
|
+
/**
|
|
123
|
+
* Creates a function that invalidates a specific query in the cache.
|
|
124
|
+
* Call the returned function to trigger the invalidation.
|
|
125
|
+
*
|
|
126
|
+
* @param queryClient - The TanStack Query client instance
|
|
127
|
+
* @param params - The exact parameters used for this query
|
|
128
|
+
* @returns A function that when called invalidates the query
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* const invalidate = getUser.invalidate(queryClient, { urlParams: { userId: '123' } })
|
|
133
|
+
* await invalidate() // Invalidates this specific query
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
88
136
|
result.invalidate = (queryClient, params) => {
|
|
89
|
-
return queryClient.invalidateQueries({ queryKey: result.queryKey.dataTag(params) });
|
|
137
|
+
return () => queryClient.invalidateQueries({ queryKey: result.queryKey.dataTag(params) });
|
|
90
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Creates a function that invalidates all queries matching the URL pattern.
|
|
141
|
+
* Useful for invalidating all queries for a resource regardless of query params.
|
|
142
|
+
*
|
|
143
|
+
* @param queryClient - The TanStack Query client instance
|
|
144
|
+
* @param params - URL parameters only (query params are ignored for matching)
|
|
145
|
+
* @returns A function that when called invalidates all matching queries
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* const invalidateAll = getUserPosts.invalidateAll(queryClient, { urlParams: { userId: '123' } })
|
|
150
|
+
* await invalidateAll() // Invalidates all getUserPosts queries for user 123
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
91
153
|
result.invalidateAll = (queryClient, params) => {
|
|
92
|
-
return queryClient.invalidateQueries({
|
|
154
|
+
return () => queryClient.invalidateQueries({
|
|
93
155
|
queryKey: result.queryKey.filterKey(params),
|
|
94
156
|
exact: false
|
|
95
157
|
});
|
|
@@ -136,22 +198,54 @@ function makeInfiniteQueryOptions(endpoint, options, baseQuery = {}) {
|
|
|
136
198
|
},
|
|
137
199
|
getNextPageParam: options.getNextPageParam,
|
|
138
200
|
getPreviousPageParam: options.getPreviousPageParam,
|
|
139
|
-
initialPageParam: options.initialPageParam ?? config.querySchema
|
|
201
|
+
initialPageParam: options.initialPageParam ?? config.querySchema?.parse("params" in params ? params.params : {}) ?? ("params" in params ? params.params : {}),
|
|
140
202
|
...baseQuery
|
|
141
203
|
});
|
|
142
204
|
};
|
|
205
|
+
/** The query key creator for this infinite query endpoint */
|
|
143
206
|
res.queryKey = queryKey;
|
|
207
|
+
/**
|
|
208
|
+
* React hook that executes the infinite query.
|
|
209
|
+
* Uses `useInfiniteQuery` from TanStack Query internally.
|
|
210
|
+
*
|
|
211
|
+
* @param params - URL parameters and initial query parameters
|
|
212
|
+
* @returns Infinite query result with pages, fetchNextPage, etc.
|
|
213
|
+
*/
|
|
144
214
|
res.use = (params) => {
|
|
145
215
|
return useInfiniteQuery(res(params));
|
|
146
216
|
};
|
|
217
|
+
/**
|
|
218
|
+
* React hook that executes the infinite query with Suspense support.
|
|
219
|
+
* Uses `useSuspenseInfiniteQuery` from TanStack Query internally.
|
|
220
|
+
* The component will suspend while loading and throw on error.
|
|
221
|
+
*
|
|
222
|
+
* @param params - URL parameters and initial query parameters
|
|
223
|
+
* @returns Infinite query result with pages guaranteed to be defined
|
|
224
|
+
*/
|
|
147
225
|
res.useSuspense = (params) => {
|
|
148
226
|
return useSuspenseInfiniteQuery(res(params));
|
|
149
227
|
};
|
|
228
|
+
/**
|
|
229
|
+
* Creates a function that invalidates this specific infinite query in the cache.
|
|
230
|
+
* Call the returned function to trigger the invalidation.
|
|
231
|
+
*
|
|
232
|
+
* @param queryClient - The TanStack Query client instance
|
|
233
|
+
* @param params - The exact parameters used for this query
|
|
234
|
+
* @returns A function that when called invalidates the query
|
|
235
|
+
*/
|
|
150
236
|
res.invalidate = (queryClient, params) => {
|
|
151
|
-
return queryClient.invalidateQueries({ queryKey: res.queryKey.dataTag(params) });
|
|
237
|
+
return () => queryClient.invalidateQueries({ queryKey: res.queryKey.dataTag(params) });
|
|
152
238
|
};
|
|
239
|
+
/**
|
|
240
|
+
* Creates a function that invalidates all infinite queries matching the URL pattern.
|
|
241
|
+
* Useful for invalidating all queries for a resource regardless of query params.
|
|
242
|
+
*
|
|
243
|
+
* @param queryClient - The TanStack Query client instance
|
|
244
|
+
* @param params - URL parameters only (query params are ignored for matching)
|
|
245
|
+
* @returns A function that when called invalidates all matching queries
|
|
246
|
+
*/
|
|
153
247
|
res.invalidateAll = (queryClient, params) => {
|
|
154
|
-
return queryClient.invalidateQueries({
|
|
248
|
+
return () => queryClient.invalidateQueries({
|
|
155
249
|
queryKey: res.queryKey.filterKey(params),
|
|
156
250
|
exact: false
|
|
157
251
|
});
|
|
@@ -159,6 +253,179 @@ function makeInfiniteQueryOptions(endpoint, options, baseQuery = {}) {
|
|
|
159
253
|
return res;
|
|
160
254
|
}
|
|
161
255
|
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/query/prefetch.mts
|
|
258
|
+
/**
|
|
259
|
+
* Creates a type-safe prefetch helper for SSR/RSC.
|
|
260
|
+
*
|
|
261
|
+
* This utility wraps a query options creator to provide convenient
|
|
262
|
+
* methods for server-side data fetching and hydration.
|
|
263
|
+
*
|
|
264
|
+
* @param queryOptionsCreator - A function that creates query options (from client.query())
|
|
265
|
+
* @returns A prefetch helper object with prefetch, ensureData, and getQueryOptions methods
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```tsx
|
|
269
|
+
* // 1. Create your query
|
|
270
|
+
* const getUserQuery = client.query({
|
|
271
|
+
* method: 'GET',
|
|
272
|
+
* url: '/users/$userId',
|
|
273
|
+
* responseSchema: userSchema,
|
|
274
|
+
* })
|
|
275
|
+
*
|
|
276
|
+
* // 2. Create prefetch helper
|
|
277
|
+
* const userPrefetch = createPrefetchHelper(getUserQuery)
|
|
278
|
+
*
|
|
279
|
+
* // 3. Use in server component
|
|
280
|
+
* async function UserPage({ userId }: { userId: string }) {
|
|
281
|
+
* const queryClient = new QueryClient()
|
|
282
|
+
*
|
|
283
|
+
* await userPrefetch.prefetch(queryClient, {
|
|
284
|
+
* urlParams: { userId },
|
|
285
|
+
* })
|
|
286
|
+
*
|
|
287
|
+
* return (
|
|
288
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
289
|
+
* <UserProfile userId={userId} />
|
|
290
|
+
* </HydrationBoundary>
|
|
291
|
+
* )
|
|
292
|
+
* }
|
|
293
|
+
* ```
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```tsx
|
|
297
|
+
* // With Next.js App Router
|
|
298
|
+
* import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
|
|
299
|
+
* import { createPrefetchHelper } from '@navios/react-query'
|
|
300
|
+
*
|
|
301
|
+
* // Define queries
|
|
302
|
+
* const getPostsQuery = client.query({
|
|
303
|
+
* method: 'GET',
|
|
304
|
+
* url: '/posts',
|
|
305
|
+
* querySchema: z.object({ page: z.number() }),
|
|
306
|
+
* responseSchema: postsSchema,
|
|
307
|
+
* })
|
|
308
|
+
*
|
|
309
|
+
* const postsPrefetch = createPrefetchHelper(getPostsQuery)
|
|
310
|
+
*
|
|
311
|
+
* // Server Component
|
|
312
|
+
* export default async function PostsPage() {
|
|
313
|
+
* const queryClient = new QueryClient()
|
|
314
|
+
*
|
|
315
|
+
* await postsPrefetch.prefetch(queryClient, {
|
|
316
|
+
* params: { page: 1 },
|
|
317
|
+
* })
|
|
318
|
+
*
|
|
319
|
+
* return (
|
|
320
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
321
|
+
* <PostsList />
|
|
322
|
+
* </HydrationBoundary>
|
|
323
|
+
* )
|
|
324
|
+
* }
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
function createPrefetchHelper(queryOptionsCreator) {
|
|
328
|
+
return {
|
|
329
|
+
prefetch: async (queryClient, params) => {
|
|
330
|
+
const options = queryOptionsCreator(params);
|
|
331
|
+
await queryClient.prefetchQuery(options);
|
|
332
|
+
},
|
|
333
|
+
ensureData: async (queryClient, params) => {
|
|
334
|
+
const options = queryOptionsCreator(params);
|
|
335
|
+
return queryClient.ensureQueryData(options);
|
|
336
|
+
},
|
|
337
|
+
getQueryOptions: (params) => {
|
|
338
|
+
return queryOptionsCreator(params);
|
|
339
|
+
},
|
|
340
|
+
prefetchMany: async (queryClient, paramsList) => {
|
|
341
|
+
await Promise.all(paramsList.map((params) => {
|
|
342
|
+
const options = queryOptionsCreator(params);
|
|
343
|
+
return queryClient.prefetchQuery(options);
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Creates multiple prefetch helpers from a record of query options creators.
|
|
350
|
+
*
|
|
351
|
+
* Useful when you have multiple queries that need to be prefetched together.
|
|
352
|
+
*
|
|
353
|
+
* @param queries - Record of query options creator functions
|
|
354
|
+
* @returns Record of prefetch helpers with the same keys
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```tsx
|
|
358
|
+
* // Define all your queries
|
|
359
|
+
* const queries = {
|
|
360
|
+
* user: client.query({
|
|
361
|
+
* method: 'GET',
|
|
362
|
+
* url: '/users/$userId',
|
|
363
|
+
* responseSchema: userSchema,
|
|
364
|
+
* }),
|
|
365
|
+
* posts: client.query({
|
|
366
|
+
* method: 'GET',
|
|
367
|
+
* url: '/users/$userId/posts',
|
|
368
|
+
* responseSchema: postsSchema,
|
|
369
|
+
* }),
|
|
370
|
+
* }
|
|
371
|
+
*
|
|
372
|
+
* // Create all prefetch helpers at once
|
|
373
|
+
* const prefetchers = createPrefetchHelpers(queries)
|
|
374
|
+
*
|
|
375
|
+
* // Use in server component
|
|
376
|
+
* async function UserPage({ userId }: { userId: string }) {
|
|
377
|
+
* const queryClient = new QueryClient()
|
|
378
|
+
*
|
|
379
|
+
* await Promise.all([
|
|
380
|
+
* prefetchers.user.prefetch(queryClient, { urlParams: { userId } }),
|
|
381
|
+
* prefetchers.posts.prefetch(queryClient, { urlParams: { userId } }),
|
|
382
|
+
* ])
|
|
383
|
+
*
|
|
384
|
+
* return (
|
|
385
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
386
|
+
* <UserProfileWithPosts userId={userId} />
|
|
387
|
+
* </HydrationBoundary>
|
|
388
|
+
* )
|
|
389
|
+
* }
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
function createPrefetchHelpers(queries) {
|
|
393
|
+
const result = {};
|
|
394
|
+
for (const key of Object.keys(queries)) result[key] = createPrefetchHelper(queries[key]);
|
|
395
|
+
return result;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Prefetch multiple queries from different query creators in parallel.
|
|
399
|
+
*
|
|
400
|
+
* @param queryClient - The QueryClient instance
|
|
401
|
+
* @param prefetches - Array of { helper, params } objects
|
|
402
|
+
* @returns Promise that resolves when all prefetches complete
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```tsx
|
|
406
|
+
* const userPrefetch = createPrefetchHelper(getUserQuery)
|
|
407
|
+
* const postsPrefetch = createPrefetchHelper(getPostsQuery)
|
|
408
|
+
*
|
|
409
|
+
* async function DashboardPage({ userId }: { userId: string }) {
|
|
410
|
+
* const queryClient = new QueryClient()
|
|
411
|
+
*
|
|
412
|
+
* await prefetchAll(queryClient, [
|
|
413
|
+
* { helper: userPrefetch, params: { urlParams: { userId } } },
|
|
414
|
+
* { helper: postsPrefetch, params: { urlParams: { userId }, params: { limit: 10 } } },
|
|
415
|
+
* ])
|
|
416
|
+
*
|
|
417
|
+
* return (
|
|
418
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
419
|
+
* <Dashboard userId={userId} />
|
|
420
|
+
* </HydrationBoundary>
|
|
421
|
+
* )
|
|
422
|
+
* }
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
async function prefetchAll(queryClient, prefetches) {
|
|
426
|
+
await Promise.all(prefetches.map(({ helper, params }) => helper.prefetch(queryClient, params)));
|
|
427
|
+
}
|
|
428
|
+
|
|
162
429
|
//#endregion
|
|
163
430
|
//#region src/mutation/key-creator.mts
|
|
164
431
|
/**
|
|
@@ -199,16 +466,6 @@ const mutationKeyCreator = createMutationKey;
|
|
|
199
466
|
|
|
200
467
|
//#endregion
|
|
201
468
|
//#region src/mutation/make-hook.mts
|
|
202
|
-
/**
|
|
203
|
-
* Creates a mutation hook for a given endpoint.
|
|
204
|
-
*
|
|
205
|
-
* Returns a function that when called returns a TanStack Query mutation result.
|
|
206
|
-
* The returned function also has helper methods attached (mutationKey, useIsMutating).
|
|
207
|
-
*
|
|
208
|
-
* @param endpoint - The navios endpoint to create a mutation hook for
|
|
209
|
-
* @param options - Mutation configuration including processResponse and callbacks
|
|
210
|
-
* @returns A hook function that returns mutation result with attached helpers
|
|
211
|
-
*/
|
|
212
469
|
function makeMutation(endpoint, options) {
|
|
213
470
|
const config = endpoint.config;
|
|
214
471
|
const mutationKey = createMutationKey(config, {
|
|
@@ -257,23 +514,178 @@ function makeMutation(endpoint, options) {
|
|
|
257
514
|
};
|
|
258
515
|
result.useIsMutating = (keyParams) => {
|
|
259
516
|
if (!options.useKey) throw new Error("useIsMutating can only be used when useKey is set to true");
|
|
260
|
-
return useIsMutating({ mutationKey: mutationKey(
|
|
517
|
+
return useIsMutating({ mutationKey: mutationKey(keyParams) }) > 0;
|
|
261
518
|
};
|
|
262
519
|
result.mutationKey = mutationKey;
|
|
263
520
|
return result;
|
|
264
521
|
}
|
|
265
522
|
|
|
523
|
+
//#endregion
|
|
524
|
+
//#region src/mutation/optimistic.mts
|
|
525
|
+
/**
|
|
526
|
+
* Creates type-safe optimistic update callbacks for mutations.
|
|
527
|
+
*
|
|
528
|
+
* This helper generates the onMutate, onError, and onSettled callbacks
|
|
529
|
+
* that implement the standard optimistic update pattern:
|
|
530
|
+
*
|
|
531
|
+
* 1. onMutate: Cancel refetches, snapshot cache, apply optimistic update
|
|
532
|
+
* 2. onError: Rollback cache to previous value on failure
|
|
533
|
+
* 3. onSettled: Invalidate query to refetch fresh data
|
|
534
|
+
*
|
|
535
|
+
* @experimental This API is experimental and may change in future versions.
|
|
536
|
+
* Use with caution in production code.
|
|
537
|
+
*
|
|
538
|
+
* @param config - Configuration for the optimistic update
|
|
539
|
+
* @returns Object containing onMutate, onError, and onSettled callbacks
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```ts
|
|
543
|
+
* // Create a mutation with optimistic updates
|
|
544
|
+
* const updateUser = client.mutation({
|
|
545
|
+
* method: 'PATCH',
|
|
546
|
+
* url: '/users/$userId',
|
|
547
|
+
* requestSchema: updateUserSchema,
|
|
548
|
+
* responseSchema: userSchema,
|
|
549
|
+
* processResponse: (data) => data,
|
|
550
|
+
* ...createOptimisticUpdate({
|
|
551
|
+
* queryKey: ['users', userId],
|
|
552
|
+
* updateFn: (oldData, variables) => ({
|
|
553
|
+
* ...oldData,
|
|
554
|
+
* ...variables.data,
|
|
555
|
+
* }),
|
|
556
|
+
* }),
|
|
557
|
+
* })
|
|
558
|
+
* ```
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```ts
|
|
562
|
+
* // Optimistic update for adding an item to a list
|
|
563
|
+
* const addTodo = client.mutation({
|
|
564
|
+
* method: 'POST',
|
|
565
|
+
* url: '/todos',
|
|
566
|
+
* requestSchema: createTodoSchema,
|
|
567
|
+
* responseSchema: todoSchema,
|
|
568
|
+
* processResponse: (data) => data,
|
|
569
|
+
* ...createOptimisticUpdate({
|
|
570
|
+
* queryKey: ['todos'],
|
|
571
|
+
* updateFn: (oldData, variables) => [
|
|
572
|
+
* ...(oldData ?? []),
|
|
573
|
+
* { id: 'temp-id', ...variables.data, createdAt: new Date() },
|
|
574
|
+
* ],
|
|
575
|
+
* }),
|
|
576
|
+
* })
|
|
577
|
+
* ```
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* ```ts
|
|
581
|
+
* // Optimistic delete
|
|
582
|
+
* const deleteTodo = client.mutation({
|
|
583
|
+
* method: 'DELETE',
|
|
584
|
+
* url: '/todos/$todoId',
|
|
585
|
+
* responseSchema: z.object({ success: z.boolean() }),
|
|
586
|
+
* processResponse: (data) => data,
|
|
587
|
+
* ...createOptimisticUpdate({
|
|
588
|
+
* queryKey: ['todos'],
|
|
589
|
+
* updateFn: (oldData, variables) =>
|
|
590
|
+
* (oldData ?? []).filter((t) => t.id !== variables.urlParams.todoId),
|
|
591
|
+
* }),
|
|
592
|
+
* })
|
|
593
|
+
* ```
|
|
594
|
+
*/
|
|
595
|
+
function createOptimisticUpdate(config) {
|
|
596
|
+
const { queryKey, updateFn, rollbackOnError = true, invalidateOnSettled = true } = config;
|
|
597
|
+
return {
|
|
598
|
+
onMutate: async (variables, context) => {
|
|
599
|
+
await context.queryClient.cancelQueries({ queryKey });
|
|
600
|
+
const previousData = context.queryClient.getQueryData(queryKey);
|
|
601
|
+
context.queryClient.setQueryData(queryKey, (old) => updateFn(old, variables));
|
|
602
|
+
return { previousData };
|
|
603
|
+
},
|
|
604
|
+
onError: (_err, _variables, context) => {
|
|
605
|
+
if (rollbackOnError && context?.previousData !== void 0) context.queryClient.setQueryData(queryKey, context.previousData);
|
|
606
|
+
},
|
|
607
|
+
onSettled: (_data, _error, _variables, context) => {
|
|
608
|
+
if (invalidateOnSettled) context.queryClient.invalidateQueries({ queryKey });
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Creates optimistic update callbacks that work with multiple query keys.
|
|
614
|
+
*
|
|
615
|
+
* Useful when a mutation affects multiple cached queries.
|
|
616
|
+
*
|
|
617
|
+
* @experimental This API is experimental and may change in future versions.
|
|
618
|
+
* Use with caution in production code.
|
|
619
|
+
*
|
|
620
|
+
* @param configs - Array of optimistic update configurations
|
|
621
|
+
* @returns Combined callbacks that handle all specified queries
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* ```ts
|
|
625
|
+
* // Updating a user affects both user detail and user list queries
|
|
626
|
+
* const updateUser = client.mutation({
|
|
627
|
+
* method: 'PATCH',
|
|
628
|
+
* url: '/users/$userId',
|
|
629
|
+
* requestSchema: updateUserSchema,
|
|
630
|
+
* responseSchema: userSchema,
|
|
631
|
+
* processResponse: (data) => data,
|
|
632
|
+
* ...createMultiOptimisticUpdate([
|
|
633
|
+
* {
|
|
634
|
+
* queryKey: ['users', userId],
|
|
635
|
+
* updateFn: (oldData, variables) => ({ ...oldData, ...variables.data }),
|
|
636
|
+
* },
|
|
637
|
+
* {
|
|
638
|
+
* queryKey: ['users'],
|
|
639
|
+
* updateFn: (oldList, variables) =>
|
|
640
|
+
* (oldList ?? []).map((u) =>
|
|
641
|
+
* u.id === userId ? { ...u, ...variables.data } : u
|
|
642
|
+
* ),
|
|
643
|
+
* },
|
|
644
|
+
* ]),
|
|
645
|
+
* })
|
|
646
|
+
* ```
|
|
647
|
+
*/
|
|
648
|
+
function createMultiOptimisticUpdate(configs) {
|
|
649
|
+
return {
|
|
650
|
+
onMutate: async (variables, context) => {
|
|
651
|
+
const previousData = /* @__PURE__ */ new Map();
|
|
652
|
+
for (const config of configs) {
|
|
653
|
+
await context.queryClient.cancelQueries({ queryKey: config.queryKey });
|
|
654
|
+
const key = JSON.stringify(config.queryKey);
|
|
655
|
+
previousData.set(key, context.queryClient.getQueryData(config.queryKey));
|
|
656
|
+
context.queryClient.setQueryData(config.queryKey, (old) => config.updateFn(old, variables));
|
|
657
|
+
}
|
|
658
|
+
return { previousData };
|
|
659
|
+
},
|
|
660
|
+
onError: (_err, _variables, context) => {
|
|
661
|
+
if (context?.previousData) {
|
|
662
|
+
for (const config of configs) if (config.rollbackOnError !== false) {
|
|
663
|
+
const key = JSON.stringify(config.queryKey);
|
|
664
|
+
const previous = context.previousData.get(key);
|
|
665
|
+
if (previous !== void 0) context.queryClient.setQueryData(config.queryKey, previous);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
onSettled: (_data, _error, _variables, context) => {
|
|
670
|
+
for (const config of configs) if (config.invalidateOnSettled !== false) context.queryClient.invalidateQueries({ queryKey: config.queryKey });
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
266
675
|
//#endregion
|
|
267
676
|
//#region src/client/declare-client.mts
|
|
268
677
|
/**
|
|
269
678
|
* Creates a client instance for making type-safe queries and mutations.
|
|
270
679
|
*
|
|
680
|
+
* @template UseDiscriminator - When `true`, errors are returned as union types.
|
|
681
|
+
* When `false` (default), errors are thrown and not included in TData.
|
|
682
|
+
*
|
|
271
683
|
* @param options - Client configuration including the API builder and defaults
|
|
272
684
|
* @returns A client instance with query, infiniteQuery, and mutation methods
|
|
273
685
|
*
|
|
274
686
|
* @example
|
|
275
687
|
* ```typescript
|
|
276
|
-
* const api =
|
|
688
|
+
* const api = builder({});
|
|
277
689
|
* const client = declareClient({ api });
|
|
278
690
|
*
|
|
279
691
|
* const getUser = client.query({
|
|
@@ -293,7 +705,8 @@ function declareClient({ api, defaults = {} }) {
|
|
|
293
705
|
url: config.url,
|
|
294
706
|
querySchema: config.querySchema,
|
|
295
707
|
requestSchema: config.requestSchema,
|
|
296
|
-
responseSchema: config.responseSchema
|
|
708
|
+
responseSchema: config.responseSchema,
|
|
709
|
+
errorSchema: config.errorSchema
|
|
297
710
|
});
|
|
298
711
|
const queryOptions$1 = makeQueryOptions(endpoint, {
|
|
299
712
|
...defaults,
|
|
@@ -314,7 +727,8 @@ function declareClient({ api, defaults = {} }) {
|
|
|
314
727
|
url: config.url,
|
|
315
728
|
querySchema: config.querySchema,
|
|
316
729
|
requestSchema: config.requestSchema,
|
|
317
|
-
responseSchema: config.responseSchema
|
|
730
|
+
responseSchema: config.responseSchema,
|
|
731
|
+
errorSchema: config.errorSchema
|
|
318
732
|
});
|
|
319
733
|
const infiniteQueryOptions$1 = makeInfiniteQueryOptions(endpoint, {
|
|
320
734
|
...defaults,
|
|
@@ -341,13 +755,16 @@ function declareClient({ api, defaults = {} }) {
|
|
|
341
755
|
url: config.url,
|
|
342
756
|
querySchema: config.querySchema,
|
|
343
757
|
requestSchema: config.requestSchema,
|
|
344
|
-
responseSchema: config.responseSchema
|
|
758
|
+
responseSchema: config.responseSchema,
|
|
759
|
+
errorSchema: config.errorSchema
|
|
345
760
|
});
|
|
346
761
|
const useMutation$1 = makeMutation(endpoint, {
|
|
347
762
|
processResponse: config.processResponse ?? ((data) => data),
|
|
348
763
|
useContext: config.useContext,
|
|
764
|
+
onMutate: config.onMutate,
|
|
349
765
|
onSuccess: config.onSuccess,
|
|
350
766
|
onError: config.onError,
|
|
767
|
+
onSettled: config.onSettled,
|
|
351
768
|
useKey: config.useKey,
|
|
352
769
|
meta: config.meta,
|
|
353
770
|
...defaults
|
|
@@ -374,7 +791,8 @@ function declareClient({ api, defaults = {} }) {
|
|
|
374
791
|
url: config.url,
|
|
375
792
|
querySchema: config.querySchema,
|
|
376
793
|
requestSchema: config.requestSchema,
|
|
377
|
-
responseSchema: config.responseSchema
|
|
794
|
+
responseSchema: config.responseSchema,
|
|
795
|
+
errorSchema: config.errorSchema
|
|
378
796
|
});
|
|
379
797
|
const useMutation$1 = makeMutation(endpoint, {
|
|
380
798
|
processResponse: config.processResponse ?? ((data) => data),
|
|
@@ -401,5 +819,5 @@ function declareClient({ api, defaults = {} }) {
|
|
|
401
819
|
}
|
|
402
820
|
|
|
403
821
|
//#endregion
|
|
404
|
-
export { createMutationKey, createQueryKey, declareClient, makeInfiniteQueryOptions, makeMutation, makeQueryOptions, mutationKeyCreator, queryKeyCreator };
|
|
822
|
+
export { createMultiOptimisticUpdate, createMutationKey, createOptimisticUpdate, createPrefetchHelper, createPrefetchHelpers, createQueryKey, declareClient, makeInfiniteQueryOptions, makeMutation, makeQueryOptions, mutationKeyCreator, prefetchAll, queryKeyCreator };
|
|
405
823
|
//# sourceMappingURL=index.mjs.map
|