@navios/react-query 1.0.0-alpha.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/coverage/base.css +224 -0
  3. package/coverage/block-navigation.js +87 -0
  4. package/coverage/client/declare-client.mts.html +1264 -0
  5. package/coverage/client/index.html +116 -0
  6. package/coverage/clover.xml +160 -0
  7. package/coverage/coverage-final.json +8 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +146 -0
  10. package/coverage/mutation/index.html +131 -0
  11. package/coverage/mutation/key-creator.mts.html +277 -0
  12. package/coverage/mutation/make-hook.mts.html +952 -0
  13. package/coverage/prettify.css +1 -0
  14. package/coverage/prettify.js +2 -0
  15. package/coverage/query/index.html +161 -0
  16. package/coverage/query/key-creator.mts.html +415 -0
  17. package/coverage/query/make-infinite-options.mts.html +601 -0
  18. package/coverage/query/make-options.mts.html +838 -0
  19. package/coverage/query/prefetch.mts.html +1063 -0
  20. package/coverage/sort-arrow-sprite.png +0 -0
  21. package/coverage/sorter.js +210 -0
  22. package/dist/src/__tests__/prefetch.spec.d.mts +2 -0
  23. package/dist/src/__tests__/prefetch.spec.d.mts.map +1 -0
  24. package/dist/src/client/types/from-endpoint.d.mts.map +1 -1
  25. package/dist/src/common/types.d.mts +10 -0
  26. package/dist/src/common/types.d.mts.map +1 -1
  27. package/dist/src/mutation/optimistic.d.mts +7 -1
  28. package/dist/src/mutation/optimistic.d.mts.map +1 -1
  29. package/dist/src/mutation/types.d.mts +1 -12
  30. package/dist/src/mutation/types.d.mts.map +1 -1
  31. package/dist/src/query/types.d.mts +2 -13
  32. package/dist/src/query/types.d.mts.map +1 -1
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/lib/index.cjs +6 -0
  35. package/lib/index.cjs.map +1 -1
  36. package/lib/index.d.cts +20 -24
  37. package/lib/index.d.cts.map +1 -1
  38. package/lib/index.d.mts +20 -24
  39. package/lib/index.d.mts.map +1 -1
  40. package/lib/index.mjs +6 -0
  41. package/lib/index.mjs.map +1 -1
  42. package/package.json +3 -3
  43. package/src/__tests__/declare-client.spec.mts +228 -0
  44. package/src/__tests__/prefetch.spec.mts +310 -0
  45. package/src/client/__type-tests__/infinite-query.spec-d.mts +1 -1
  46. package/src/client/types/from-endpoint.mts +0 -1
  47. package/src/common/types.mts +19 -0
  48. package/src/mutation/optimistic.mts +7 -1
  49. package/src/mutation/types.mts +4 -20
  50. package/src/query/types.mts +1 -22
@@ -0,0 +1,310 @@
1
+ import { QueryClient } from '@tanstack/react-query'
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
+
4
+ import {
5
+ createPrefetchHelper,
6
+ createPrefetchHelpers,
7
+ prefetchAll,
8
+ } from '../query/prefetch.mjs'
9
+
10
+ describe('createPrefetchHelper', () => {
11
+ let queryClient: QueryClient
12
+
13
+ beforeEach(() => {
14
+ queryClient = new QueryClient({
15
+ defaultOptions: {
16
+ queries: {
17
+ retry: false,
18
+ },
19
+ },
20
+ })
21
+ })
22
+
23
+ it('should create a prefetch helper with all methods', () => {
24
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
25
+ queryKey: ['users', params.userId] as const,
26
+ queryFn: async () => ({ id: params.userId, name: 'Test User' }),
27
+ }))
28
+
29
+ const helper = createPrefetchHelper(mockQueryOptions)
30
+
31
+ expect(helper).toHaveProperty('prefetch')
32
+ expect(helper).toHaveProperty('ensureData')
33
+ expect(helper).toHaveProperty('getQueryOptions')
34
+ expect(helper).toHaveProperty('prefetchMany')
35
+ expect(typeof helper.prefetch).toBe('function')
36
+ expect(typeof helper.ensureData).toBe('function')
37
+ expect(typeof helper.getQueryOptions).toBe('function')
38
+ expect(typeof helper.prefetchMany).toBe('function')
39
+ })
40
+
41
+ describe('prefetch', () => {
42
+ it('should call queryClient.prefetchQuery with correct options', async () => {
43
+ const mockQueryFn = vi.fn().mockResolvedValue({ id: '123', name: 'Test' })
44
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
45
+ queryKey: ['users', params.userId] as const,
46
+ queryFn: mockQueryFn,
47
+ }))
48
+
49
+ const helper = createPrefetchHelper(mockQueryOptions)
50
+ await helper.prefetch(queryClient, { userId: '123' })
51
+
52
+ expect(mockQueryOptions).toHaveBeenCalledWith({ userId: '123' })
53
+ expect(mockQueryFn).toHaveBeenCalled()
54
+ })
55
+
56
+ it('should prefetch data and store in cache', async () => {
57
+ const userData = { id: '456', name: 'Cached User' }
58
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
59
+ queryKey: ['users', params.userId] as const,
60
+ queryFn: async () => userData,
61
+ }))
62
+
63
+ const helper = createPrefetchHelper(mockQueryOptions)
64
+ await helper.prefetch(queryClient, { userId: '456' })
65
+
66
+ const cachedData = queryClient.getQueryData(['users', '456'])
67
+ expect(cachedData).toEqual(userData)
68
+ })
69
+ })
70
+
71
+ describe('ensureData', () => {
72
+ it('should return data after ensuring it exists in cache', async () => {
73
+ const userData = { id: '789', name: 'Ensured User' }
74
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
75
+ queryKey: ['users', params.userId] as const,
76
+ queryFn: async () => userData,
77
+ }))
78
+
79
+ const helper = createPrefetchHelper(mockQueryOptions)
80
+ const result = await helper.ensureData(queryClient, { userId: '789' })
81
+
82
+ expect(result).toEqual(userData)
83
+ })
84
+
85
+ it('should not refetch if data is already cached', async () => {
86
+ const mockQueryFn = vi.fn().mockResolvedValue({ id: '111', name: 'User' })
87
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
88
+ queryKey: ['users', params.userId] as const,
89
+ queryFn: mockQueryFn,
90
+ }))
91
+
92
+ // Pre-populate cache
93
+ queryClient.setQueryData(['users', '111'], {
94
+ id: '111',
95
+ name: 'Cached User',
96
+ })
97
+
98
+ const helper = createPrefetchHelper(mockQueryOptions)
99
+ const result = await helper.ensureData(queryClient, { userId: '111' })
100
+
101
+ expect(result).toEqual({ id: '111', name: 'Cached User' })
102
+ expect(mockQueryFn).not.toHaveBeenCalled()
103
+ })
104
+ })
105
+
106
+ describe('getQueryOptions', () => {
107
+ it('should return query options for given params', () => {
108
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
109
+ queryKey: ['users', params.userId] as const,
110
+ queryFn: async () => ({ id: params.userId }),
111
+ }))
112
+
113
+ const helper = createPrefetchHelper(mockQueryOptions)
114
+ const options = helper.getQueryOptions({ userId: 'abc' })
115
+
116
+ expect(mockQueryOptions).toHaveBeenCalledWith({ userId: 'abc' })
117
+ expect(options).toHaveProperty('queryKey', ['users', 'abc'])
118
+ expect(options).toHaveProperty('queryFn')
119
+ })
120
+ })
121
+
122
+ describe('prefetchMany', () => {
123
+ it('should prefetch multiple queries in parallel', async () => {
124
+ const mockQueryFn = vi.fn().mockImplementation(async (userId: string) => ({
125
+ id: userId,
126
+ name: `User ${userId}`,
127
+ }))
128
+
129
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
130
+ queryKey: ['users', params.userId] as const,
131
+ queryFn: () => mockQueryFn(params.userId),
132
+ }))
133
+
134
+ const helper = createPrefetchHelper(mockQueryOptions)
135
+ await helper.prefetchMany(queryClient, [
136
+ { userId: '1' },
137
+ { userId: '2' },
138
+ { userId: '3' },
139
+ ])
140
+
141
+ expect(queryClient.getQueryData(['users', '1'])).toEqual({
142
+ id: '1',
143
+ name: 'User 1',
144
+ })
145
+ expect(queryClient.getQueryData(['users', '2'])).toEqual({
146
+ id: '2',
147
+ name: 'User 2',
148
+ })
149
+ expect(queryClient.getQueryData(['users', '3'])).toEqual({
150
+ id: '3',
151
+ name: 'User 3',
152
+ })
153
+ })
154
+
155
+ it('should handle empty params list', async () => {
156
+ const mockQueryOptions = vi.fn((params: { userId: string }) => ({
157
+ queryKey: ['users', params.userId] as const,
158
+ queryFn: async () => ({ id: params.userId }),
159
+ }))
160
+
161
+ const helper = createPrefetchHelper(mockQueryOptions)
162
+ await helper.prefetchMany(queryClient, [])
163
+
164
+ expect(mockQueryOptions).not.toHaveBeenCalled()
165
+ })
166
+ })
167
+ })
168
+
169
+ describe('createPrefetchHelpers', () => {
170
+ let queryClient: QueryClient
171
+
172
+ beforeEach(() => {
173
+ queryClient = new QueryClient({
174
+ defaultOptions: {
175
+ queries: {
176
+ retry: false,
177
+ },
178
+ },
179
+ })
180
+ })
181
+
182
+ it('should create helpers for multiple queries', () => {
183
+ const queries = {
184
+ user: vi.fn((params: { userId: string }) => ({
185
+ queryKey: ['users', params.userId] as const,
186
+ queryFn: async () => ({ id: params.userId }),
187
+ })),
188
+ posts: vi.fn((params: { userId: string }) => ({
189
+ queryKey: ['users', params.userId, 'posts'] as const,
190
+ queryFn: async () => [{ id: '1', title: 'Post 1' }],
191
+ })),
192
+ }
193
+
194
+ const helpers = createPrefetchHelpers(queries)
195
+
196
+ expect(helpers).toHaveProperty('user')
197
+ expect(helpers).toHaveProperty('posts')
198
+ expect(helpers.user).toHaveProperty('prefetch')
199
+ expect(helpers.posts).toHaveProperty('prefetch')
200
+ })
201
+
202
+ it('should work with individual helpers independently', async () => {
203
+ const queries = {
204
+ user: vi.fn((params: { userId: string }) => ({
205
+ queryKey: ['users', params.userId] as const,
206
+ queryFn: async () => ({ id: params.userId, name: 'User' }),
207
+ })),
208
+ posts: vi.fn((params: { userId: string }) => ({
209
+ queryKey: ['users', params.userId, 'posts'] as const,
210
+ queryFn: async () => [{ id: '1', title: 'Post' }],
211
+ })),
212
+ }
213
+
214
+ const helpers = createPrefetchHelpers(queries)
215
+
216
+ await helpers.user.prefetch(queryClient, { userId: '123' })
217
+ await helpers.posts.prefetch(queryClient, { userId: '123' })
218
+
219
+ expect(queryClient.getQueryData(['users', '123'])).toEqual({
220
+ id: '123',
221
+ name: 'User',
222
+ })
223
+ expect(queryClient.getQueryData(['users', '123', 'posts'])).toEqual([
224
+ { id: '1', title: 'Post' },
225
+ ])
226
+ })
227
+ })
228
+
229
+ describe('prefetchAll', () => {
230
+ let queryClient: QueryClient
231
+
232
+ beforeEach(() => {
233
+ queryClient = new QueryClient({
234
+ defaultOptions: {
235
+ queries: {
236
+ retry: false,
237
+ },
238
+ },
239
+ })
240
+ })
241
+
242
+ it('should prefetch all queries in parallel', async () => {
243
+ const userHelper = createPrefetchHelper(
244
+ vi.fn((params: { userId: string }) => ({
245
+ queryKey: ['users', params.userId] as const,
246
+ queryFn: async () => ({ id: params.userId, name: 'User' }),
247
+ })),
248
+ )
249
+
250
+ const postsHelper = createPrefetchHelper(
251
+ vi.fn((params: { userId: string; limit: number }) => ({
252
+ queryKey: ['users', params.userId, 'posts', params.limit] as const,
253
+ queryFn: async () => [{ id: '1', title: 'Post' }],
254
+ })),
255
+ )
256
+
257
+ await prefetchAll(queryClient, [
258
+ { helper: userHelper, params: { userId: '123' } },
259
+ { helper: postsHelper, params: { userId: '123', limit: 10 } },
260
+ ])
261
+
262
+ expect(queryClient.getQueryData(['users', '123'])).toEqual({
263
+ id: '123',
264
+ name: 'User',
265
+ })
266
+ expect(queryClient.getQueryData(['users', '123', 'posts', 10])).toEqual([
267
+ { id: '1', title: 'Post' },
268
+ ])
269
+ })
270
+
271
+ it('should handle empty prefetches array', async () => {
272
+ await expect(prefetchAll(queryClient, [])).resolves.toBeUndefined()
273
+ })
274
+
275
+ it('should handle errors in individual prefetches', async () => {
276
+ const errorHelper = createPrefetchHelper<
277
+ Record<string, never>,
278
+ { error: boolean }
279
+ >(
280
+ vi.fn(() => ({
281
+ queryKey: ['error'] as const,
282
+ queryFn: async (): Promise<{ error: boolean }> => {
283
+ throw new Error('Fetch failed')
284
+ },
285
+ })),
286
+ )
287
+
288
+ const successHelper = createPrefetchHelper<
289
+ Record<string, never>,
290
+ { success: boolean }
291
+ >(
292
+ vi.fn(() => ({
293
+ queryKey: ['success'] as const,
294
+ queryFn: async () => ({ success: true }),
295
+ })),
296
+ )
297
+
298
+ // prefetchAll should not throw even if individual queries fail
299
+ // because prefetchQuery doesn't throw
300
+ await expect(
301
+ prefetchAll(queryClient, [
302
+ { helper: errorHelper, params: {} },
303
+ { helper: successHelper, params: {} },
304
+ ]),
305
+ ).resolves.toBeUndefined()
306
+
307
+ // Success query should still be cached
308
+ expect(queryClient.getQueryData(['success'])).toEqual({ success: true })
309
+ })
310
+ })
@@ -70,7 +70,7 @@ describe('ClientInstance<false> infiniteQuery() method', () => {
70
70
  url: '/users',
71
71
  querySchema,
72
72
  responseSchema,
73
- getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) =>
73
+ getNextPageParam: (_lastPage, _allPages, _lastPageParam, _allPageParams) =>
74
74
  undefined,
75
75
  })
76
76
 
@@ -1,5 +1,4 @@
1
1
  import type {
2
- BaseEndpointConfig,
3
2
  BaseEndpointOptions,
4
3
  EndpointOptions,
5
4
  InferEndpointParams,
@@ -24,6 +24,25 @@ export type ProcessResponseFunction<TData = unknown, TVariables = unknown> = (
24
24
  variables: TVariables,
25
25
  ) => Promise<TData> | TData
26
26
 
27
+ /**
28
+ * Compute the response input type based on discriminator and error schema.
29
+ * When UseDiscriminator=true and errorSchema is present, errors are included as a union.
30
+ * When UseDiscriminator=false, only the success type is returned (errors are thrown).
31
+ *
32
+ * @template UseDiscriminator - Whether to include error types in the response union
33
+ * @template ResponseSchema - The success response schema
34
+ * @template ErrorSchema - The error schema record (optional)
35
+ */
36
+ export type ComputeResponseInput<
37
+ UseDiscriminator extends boolean,
38
+ ResponseSchema extends ZodType,
39
+ ErrorSchema extends ErrorSchemaRecord | undefined,
40
+ > = UseDiscriminator extends true
41
+ ? ErrorSchema extends ErrorSchemaRecord
42
+ ? z.output<ResponseSchema> | InferErrorSchemaOutput<ErrorSchema>
43
+ : z.output<ResponseSchema>
44
+ : z.output<ResponseSchema>
45
+
27
46
  /**
28
47
  * Options for creating a client instance.
29
48
  *
@@ -8,7 +8,7 @@ import type { QueryClient } from '@tanstack/react-query'
8
8
  * @template TQueryData - The query cache data type
9
9
  */
10
10
  export interface OptimisticUpdateConfig<
11
- TData,
11
+ _TData,
12
12
  TVariables,
13
13
  TQueryData,
14
14
  > {
@@ -86,6 +86,9 @@ export interface OptimisticUpdateCallbacks<TData, TVariables, TQueryData> {
86
86
  * 2. onError: Rollback cache to previous value on failure
87
87
  * 3. onSettled: Invalidate query to refetch fresh data
88
88
  *
89
+ * @experimental This API is experimental and may change in future versions.
90
+ * Use with caution in production code.
91
+ *
89
92
  * @param config - Configuration for the optimistic update
90
93
  * @returns Object containing onMutate, onError, and onSettled callbacks
91
94
  *
@@ -206,6 +209,9 @@ export function createOptimisticUpdate<
206
209
  *
207
210
  * Useful when a mutation affects multiple cached queries.
208
211
  *
212
+ * @experimental This API is experimental and may change in future versions.
213
+ * Use with caution in production code.
214
+ *
209
215
  * @param configs - Array of optimistic update configurations
210
216
  * @returns Combined callbacks that handle all specified queries
211
217
  *
@@ -13,26 +13,10 @@ import type {
13
13
  } from '@tanstack/react-query'
14
14
  import type { z, ZodObject, ZodType } from 'zod/v4'
15
15
 
16
- import type { ProcessResponseFunction } from '../common/types.mjs'
17
-
18
- /**
19
- * Compute the response input type based on discriminator and error schema.
20
- * When UseDiscriminator=true and errorSchema is present, errors are included as a union.
21
- * When UseDiscriminator=false, only the success type is returned (errors are thrown).
22
- *
23
- * @template UseDiscriminator - Whether to include error types in the response union
24
- * @template ResponseSchema - The success response schema
25
- * @template ErrorSchema - The error schema record (optional)
26
- */
27
- type ComputeResponseInput<
28
- UseDiscriminator extends boolean,
29
- ResponseSchema extends ZodType,
30
- ErrorSchema extends ErrorSchemaRecord | undefined,
31
- > = UseDiscriminator extends true
32
- ? ErrorSchema extends ErrorSchemaRecord
33
- ? z.output<ResponseSchema> | InferErrorSchemaOutput<ErrorSchema>
34
- : z.output<ResponseSchema>
35
- : z.output<ResponseSchema>
16
+ import type {
17
+ ComputeResponseInput,
18
+ ProcessResponseFunction,
19
+ } from '../common/types.mjs'
36
20
 
37
21
  /**
38
22
  * Arguments for mutation functions based on URL params, request schema, and query schema.
@@ -2,10 +2,8 @@ import type {
2
2
  AnyEndpointConfig,
3
3
  BaseEndpointConfig,
4
4
  EndpointOptions,
5
- ErrorSchemaRecord,
6
5
  HttpMethod,
7
6
  InferEndpointReturn,
8
- InferErrorSchemaOutput,
9
7
  RequestArgs,
10
8
  Simplify,
11
9
  UrlHasParams,
@@ -20,26 +18,7 @@ import type {
20
18
  } from '@tanstack/react-query'
21
19
  import type { z, ZodObject, ZodType } from 'zod/v4'
22
20
 
23
- import type { Split } from '../common/types.mjs'
24
-
25
- /**
26
- * Compute the response input type based on discriminator and error schema.
27
- * When UseDiscriminator=true and errorSchema is present, errors are included as a union.
28
- * When UseDiscriminator=false, only the success type is returned (errors are thrown).
29
- *
30
- * @template UseDiscriminator - Whether to include error types in the response union
31
- * @template ResponseSchema - The success response schema
32
- * @template ErrorSchema - The error schema record (optional)
33
- */
34
- type ComputeResponseInput<
35
- UseDiscriminator extends boolean,
36
- ResponseSchema extends ZodType,
37
- ErrorSchema extends ErrorSchemaRecord | undefined,
38
- > = UseDiscriminator extends true
39
- ? ErrorSchema extends ErrorSchemaRecord
40
- ? z.output<ResponseSchema> | InferErrorSchemaOutput<ErrorSchema>
41
- : z.output<ResponseSchema>
42
- : z.output<ResponseSchema>
21
+ import type { ComputeResponseInput, Split } from '../common/types.mjs'
43
22
 
44
23
  /**
45
24
  * Helper type to extract the result type from processResponse.