@navios/react-query 0.7.0 → 1.0.0-alpha.1

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 (124) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/README.md +152 -4
  3. package/dist/src/__tests__/errorSchema.spec.d.mts +2 -0
  4. package/dist/src/__tests__/errorSchema.spec.d.mts.map +1 -0
  5. package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts +2 -0
  6. package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts.map +1 -0
  7. package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts +2 -0
  8. package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts.map +1 -0
  9. package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts +2 -0
  10. package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts.map +1 -0
  11. package/dist/src/client/__type-tests__/mutation.spec-d.d.mts +2 -0
  12. package/dist/src/client/__type-tests__/mutation.spec-d.d.mts.map +1 -0
  13. package/dist/src/client/__type-tests__/query.spec-d.d.mts +2 -0
  14. package/dist/src/client/__type-tests__/query.spec-d.d.mts.map +1 -0
  15. package/dist/src/client/declare-client.d.mts +15 -8
  16. package/dist/src/client/declare-client.d.mts.map +1 -1
  17. package/dist/src/client/types/from-endpoint.d.mts +130 -0
  18. package/dist/src/client/types/from-endpoint.d.mts.map +1 -0
  19. package/dist/src/client/types/helpers.d.mts +74 -0
  20. package/dist/src/client/types/helpers.d.mts.map +1 -0
  21. package/dist/src/client/types/index.d.mts +21 -0
  22. package/dist/src/client/types/index.d.mts.map +1 -0
  23. package/dist/src/client/types/infinite-query.d.mts +61 -0
  24. package/dist/src/client/types/infinite-query.d.mts.map +1 -0
  25. package/dist/src/client/types/multipart-mutation.d.mts +98 -0
  26. package/dist/src/client/types/multipart-mutation.d.mts.map +1 -0
  27. package/dist/src/client/types/mutation.d.mts +75 -0
  28. package/dist/src/client/types/mutation.d.mts.map +1 -0
  29. package/dist/src/client/types/query.d.mts +65 -0
  30. package/dist/src/client/types/query.d.mts.map +1 -0
  31. package/dist/src/client/types.d.mts +1 -608
  32. package/dist/src/client/types.d.mts.map +1 -1
  33. package/dist/src/common/types.d.mts +30 -3
  34. package/dist/src/common/types.d.mts.map +1 -1
  35. package/dist/src/mutation/index.d.mts +1 -0
  36. package/dist/src/mutation/index.d.mts.map +1 -1
  37. package/dist/src/mutation/make-hook.d.mts +42 -16
  38. package/dist/src/mutation/make-hook.d.mts.map +1 -1
  39. package/dist/src/mutation/optimistic.d.mts +166 -0
  40. package/dist/src/mutation/optimistic.d.mts.map +1 -0
  41. package/dist/src/mutation/types.d.mts +51 -19
  42. package/dist/src/mutation/types.d.mts.map +1 -1
  43. package/dist/src/query/index.d.mts +1 -0
  44. package/dist/src/query/index.d.mts.map +1 -1
  45. package/dist/src/query/key-creator.d.mts.map +1 -1
  46. package/dist/src/query/make-infinite-options.d.mts +3 -2
  47. package/dist/src/query/make-infinite-options.d.mts.map +1 -1
  48. package/dist/src/query/make-options.d.mts +42 -12
  49. package/dist/src/query/make-options.d.mts.map +1 -1
  50. package/dist/src/query/prefetch.d.mts +245 -0
  51. package/dist/src/query/prefetch.d.mts.map +1 -0
  52. package/dist/src/query/types.d.mts +35 -17
  53. package/dist/src/query/types.d.mts.map +1 -1
  54. package/dist/tsconfig.tsbuildinfo +1 -1
  55. package/lib/index.cjs +454 -37
  56. package/lib/index.cjs.map +1 -1
  57. package/lib/index.d.cts +1021 -598
  58. package/lib/index.d.cts.map +1 -1
  59. package/lib/index.d.mts +1019 -596
  60. package/lib/index.d.mts.map +1 -1
  61. package/lib/index.mjs +441 -29
  62. package/lib/index.mjs.map +1 -1
  63. package/package.json +8 -8
  64. package/src/__tests__/declare-client.spec.mts +1 -2
  65. package/src/__tests__/errorSchema.spec.mts +391 -0
  66. package/src/__tests__/make-mutation.spec.mts +6 -5
  67. package/src/__tests__/makeDataTag.spec.mts +2 -1
  68. package/src/__tests__/makeQueryOptions.spec.mts +2 -1
  69. package/src/client/__type-tests__/from-endpoint.spec-d.mts +550 -0
  70. package/src/client/__type-tests__/infinite-query.spec-d.mts +648 -0
  71. package/src/client/__type-tests__/multipart-mutation.spec-d.mts +725 -0
  72. package/src/client/__type-tests__/mutation.spec-d.mts +757 -0
  73. package/src/client/__type-tests__/query.spec-d.mts +701 -0
  74. package/src/client/declare-client.mts +59 -34
  75. package/src/client/types/from-endpoint.mts +345 -0
  76. package/src/client/types/helpers.mts +140 -0
  77. package/src/client/types/index.mts +26 -0
  78. package/src/client/types/infinite-query.mts +133 -0
  79. package/src/client/types/multipart-mutation.mts +264 -0
  80. package/src/client/types/mutation.mts +176 -0
  81. package/src/client/types/query.mts +132 -0
  82. package/src/client/types.mts +1 -1935
  83. package/src/common/types.mts +48 -3
  84. package/src/mutation/index.mts +1 -0
  85. package/src/mutation/make-hook.mts +171 -63
  86. package/src/mutation/optimistic.mts +294 -0
  87. package/src/mutation/types.mts +102 -29
  88. package/src/query/index.mts +1 -0
  89. package/src/query/key-creator.mts +24 -13
  90. package/src/query/make-infinite-options.mts +53 -10
  91. package/src/query/make-options.mts +184 -43
  92. package/src/query/prefetch.mts +326 -0
  93. package/src/query/types.mts +76 -16
  94. package/dist/src/declare-client.d.mts +0 -31
  95. package/dist/src/declare-client.d.mts.map +0 -1
  96. package/dist/src/make-infinite-query-options.d.mts +0 -13
  97. package/dist/src/make-infinite-query-options.d.mts.map +0 -1
  98. package/dist/src/make-mutation.d.mts +0 -15
  99. package/dist/src/make-mutation.d.mts.map +0 -1
  100. package/dist/src/make-query-options.d.mts +0 -15
  101. package/dist/src/make-query-options.d.mts.map +0 -1
  102. package/dist/src/types/client-endpoint-helper.d.mts +0 -8
  103. package/dist/src/types/client-endpoint-helper.d.mts.map +0 -1
  104. package/dist/src/types/client-instance.d.mts +0 -211
  105. package/dist/src/types/client-instance.d.mts.map +0 -1
  106. package/dist/src/types/index.d.mts +0 -8
  107. package/dist/src/types/index.d.mts.map +0 -1
  108. package/dist/src/types/mutation-args.d.mts +0 -10
  109. package/dist/src/types/mutation-args.d.mts.map +0 -1
  110. package/dist/src/types/mutation-helpers.d.mts +0 -10
  111. package/dist/src/types/mutation-helpers.d.mts.map +0 -1
  112. package/dist/src/types/query-args.d.mts +0 -8
  113. package/dist/src/types/query-args.d.mts.map +0 -1
  114. package/dist/src/types/query-helpers.d.mts +0 -14
  115. package/dist/src/types/query-helpers.d.mts.map +0 -1
  116. package/dist/src/types/query-url-params-args.d.mts +0 -5
  117. package/dist/src/types/query-url-params-args.d.mts.map +0 -1
  118. package/dist/src/types.d.mts +0 -49
  119. package/dist/src/types.d.mts.map +0 -1
  120. package/dist/src/utils/mutation-key.creator.d.mts +0 -39
  121. package/dist/src/utils/mutation-key.creator.d.mts.map +0 -1
  122. package/dist/src/utils/query-key-creator.d.mts +0 -24
  123. package/dist/src/utils/query-key-creator.d.mts.map +0 -1
  124. package/src/client/__type-tests__/client-instance.spec-d.mts +0 -852
@@ -0,0 +1,648 @@
1
+ import type { ErrorSchemaRecord } from '@navios/builder'
2
+ import type {
3
+ DataTag,
4
+ InfiniteData,
5
+ UseSuspenseInfiniteQueryOptions,
6
+ } from '@tanstack/react-query'
7
+ import type { z } from 'zod/v4'
8
+
9
+ import { assertType, describe, test } from 'vitest'
10
+ import { z as zod } from 'zod/v4'
11
+
12
+ import type { Split } from '../../common/types.mjs'
13
+ import type { QueryHelpers } from '../../query/types.mjs'
14
+ import type { ClientInstance, EndpointHelper } from '../types.mjs'
15
+
16
+ // ============================================================================
17
+ // TEST SCHEMAS
18
+ // ============================================================================
19
+
20
+ const responseSchema = zod.object({
21
+ id: zod.string(),
22
+ name: zod.string(),
23
+ })
24
+
25
+ const querySchema = zod.object({
26
+ page: zod.number(),
27
+ limit: zod.number(),
28
+ })
29
+
30
+ const requestSchema = zod.object({
31
+ name: zod.string(),
32
+ email: zod.string(),
33
+ })
34
+
35
+ const error400Schema = zod.object({ error: zod.string(), code: zod.number() })
36
+ const error404Schema = zod.object({ notFound: zod.literal(true) })
37
+ const error500Schema = zod.object({ serverError: zod.string() })
38
+
39
+ const errorSchema = {
40
+ 400: error400Schema,
41
+ 404: error404Schema,
42
+ 500: error500Schema,
43
+ } satisfies ErrorSchemaRecord
44
+
45
+ type ResponseType = z.output<typeof responseSchema>
46
+ type QueryType = z.input<typeof querySchema>
47
+ type RequestType = z.input<typeof requestSchema>
48
+ type Error400 = z.output<typeof error400Schema>
49
+ type Error404 = z.output<typeof error404Schema>
50
+ type Error500 = z.output<typeof error500Schema>
51
+ type ErrorUnion = Error400 | Error404 | Error500
52
+ type ResponseWithErrors = ResponseType | ErrorUnion
53
+
54
+ // ============================================================================
55
+ // CLIENT INSTANCE DECLARATIONS
56
+ // ============================================================================
57
+
58
+ declare const client: ClientInstance<false>
59
+ declare const clientWithDiscriminator: ClientInstance<true>
60
+
61
+ // ============================================================================
62
+ // INFINITE QUERY METHOD - DEFAULT MODE (UseDiscriminator=false)
63
+ // ============================================================================
64
+
65
+ describe('ClientInstance<false> infiniteQuery() method', () => {
66
+ describe('GET infinite queries', () => {
67
+ test('basic GET infinite query', () => {
68
+ const query = client.infiniteQuery({
69
+ method: 'GET',
70
+ url: '/users',
71
+ querySchema,
72
+ responseSchema,
73
+ getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) =>
74
+ undefined,
75
+ })
76
+
77
+ assertType<
78
+ (params: {
79
+ params: QueryType
80
+ }) => UseSuspenseInfiniteQueryOptions<
81
+ ResponseType,
82
+ Error,
83
+ InfiniteData<ResponseType>,
84
+ DataTag<Split<'/users', '/'>, ResponseType, Error>,
85
+ z.output<typeof querySchema>
86
+ >
87
+ >(query)
88
+
89
+ // Should have QueryHelpers with isInfinite=true
90
+ assertType<
91
+ QueryHelpers<
92
+ '/users',
93
+ typeof querySchema,
94
+ ResponseType,
95
+ true
96
+ >['queryKey']
97
+ >(query.queryKey)
98
+ })
99
+
100
+ test('GET infinite query with URL params', () => {
101
+ const query = client.infiniteQuery({
102
+ method: 'GET',
103
+ url: '/users/$userId/posts',
104
+ querySchema,
105
+ responseSchema,
106
+ getNextPageParam: () => undefined,
107
+ })
108
+
109
+ assertType<
110
+ (params: {
111
+ urlParams: { userId: string | number }
112
+ params: QueryType
113
+ }) => UseSuspenseInfiniteQueryOptions<
114
+ ResponseType,
115
+ Error,
116
+ InfiniteData<ResponseType>,
117
+ DataTag<Split<'/users/$userId/posts', '/'>, ResponseType, Error>,
118
+ z.output<typeof querySchema>
119
+ >
120
+ >(query)
121
+ })
122
+
123
+ test('GET infinite query with multiple URL params', () => {
124
+ const query = client.infiniteQuery({
125
+ method: 'GET',
126
+ url: '/orgs/$orgId/users/$userId/posts',
127
+ querySchema,
128
+ responseSchema,
129
+ getNextPageParam: () => undefined,
130
+ })
131
+
132
+ assertType<
133
+ (params: {
134
+ urlParams: { orgId: string | number; userId: string | number }
135
+ params: QueryType
136
+ }) => UseSuspenseInfiniteQueryOptions<
137
+ ResponseType,
138
+ Error,
139
+ InfiniteData<ResponseType>,
140
+ DataTag<
141
+ Split<'/orgs/$orgId/users/$userId/posts', '/'>,
142
+ ResponseType,
143
+ Error
144
+ >,
145
+ z.output<typeof querySchema>
146
+ >
147
+ >(query)
148
+ })
149
+
150
+ test('GET infinite query with processResponse transformation', () => {
151
+ const query = client.infiniteQuery({
152
+ method: 'GET',
153
+ url: '/users',
154
+ querySchema,
155
+ responseSchema,
156
+ processResponse: (data) => ({ user: data, timestamp: Date.now() }),
157
+ getNextPageParam: () => undefined,
158
+ })
159
+
160
+ type TransformedType = { user: ResponseType; timestamp: number }
161
+
162
+ assertType<
163
+ (params: {
164
+ params: QueryType
165
+ }) => UseSuspenseInfiniteQueryOptions<
166
+ TransformedType,
167
+ Error,
168
+ InfiniteData<TransformedType>,
169
+ DataTag<Split<'/users', '/'>, TransformedType, Error>,
170
+ z.output<typeof querySchema>
171
+ >
172
+ >(query)
173
+ })
174
+
175
+ test('GET infinite query with errorSchema (errors thrown)', () => {
176
+ const query = client.infiniteQuery({
177
+ method: 'GET',
178
+ url: '/users',
179
+ querySchema,
180
+ responseSchema,
181
+ errorSchema,
182
+ getNextPageParam: () => undefined,
183
+ })
184
+
185
+ // With UseDiscriminator=false, errors are thrown
186
+ assertType<
187
+ (params: {
188
+ params: QueryType
189
+ }) => UseSuspenseInfiniteQueryOptions<
190
+ ResponseType,
191
+ Error,
192
+ InfiniteData<ResponseType>,
193
+ DataTag<Split<'/users', '/'>, ResponseType, Error>,
194
+ z.output<typeof querySchema>
195
+ >
196
+ >(query)
197
+ })
198
+ })
199
+
200
+ describe('POST infinite queries', () => {
201
+ test('POST infinite query with request schema', () => {
202
+ const query = client.infiniteQuery({
203
+ method: 'POST',
204
+ url: '/search',
205
+ querySchema,
206
+ requestSchema,
207
+ responseSchema,
208
+ getNextPageParam: () => undefined,
209
+ })
210
+
211
+ assertType<
212
+ (params: {
213
+ params: QueryType
214
+ data: RequestType
215
+ }) => UseSuspenseInfiniteQueryOptions<
216
+ ResponseType,
217
+ Error,
218
+ InfiniteData<ResponseType>,
219
+ DataTag<Split<'/search', '/'>, ResponseType, Error>,
220
+ z.output<typeof querySchema>
221
+ >
222
+ >(query)
223
+ })
224
+
225
+ test('POST infinite query with URL params and request schema', () => {
226
+ const query = client.infiniteQuery({
227
+ method: 'POST',
228
+ url: '/users/$userId/search',
229
+ querySchema,
230
+ requestSchema,
231
+ responseSchema,
232
+ getNextPageParam: () => undefined,
233
+ })
234
+
235
+ assertType<
236
+ (params: {
237
+ urlParams: { userId: string | number }
238
+ params: QueryType
239
+ data: RequestType
240
+ }) => UseSuspenseInfiniteQueryOptions<
241
+ ResponseType,
242
+ Error,
243
+ InfiniteData<ResponseType>,
244
+ DataTag<Split<'/users/$userId/search', '/'>, ResponseType, Error>,
245
+ z.output<typeof querySchema>
246
+ >
247
+ >(query)
248
+ })
249
+ })
250
+
251
+ describe('pagination callbacks', () => {
252
+ test('getNextPageParam receives correct types', () => {
253
+ client.infiniteQuery({
254
+ method: 'GET',
255
+ url: '/users',
256
+ querySchema,
257
+ responseSchema,
258
+ getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) => {
259
+ assertType<ResponseType>(lastPage)
260
+ assertType<ResponseType[]>(allPages)
261
+ assertType<z.infer<typeof querySchema> | undefined>(lastPageParam)
262
+ assertType<z.infer<typeof querySchema>[] | undefined>(allPageParams)
263
+ return { page: 1, limit: 10 }
264
+ },
265
+ })
266
+ })
267
+
268
+ test('getPreviousPageParam receives correct types', () => {
269
+ client.infiniteQuery({
270
+ method: 'GET',
271
+ url: '/users',
272
+ querySchema,
273
+ responseSchema,
274
+ getNextPageParam: () => undefined,
275
+ getPreviousPageParam: (
276
+ firstPage,
277
+ allPages,
278
+ lastPageParam,
279
+ allPageParams,
280
+ ) => {
281
+ assertType<ResponseType>(firstPage)
282
+ assertType<ResponseType[]>(allPages)
283
+ assertType<z.infer<typeof querySchema> | undefined>(lastPageParam)
284
+ assertType<z.infer<typeof querySchema>[] | undefined>(allPageParams)
285
+ return { page: 0, limit: 10 }
286
+ },
287
+ })
288
+ })
289
+
290
+ test('pagination callbacks with transformed page result', () => {
291
+ type TransformedPage = { items: ResponseType[]; hasMore: boolean }
292
+
293
+ client.infiniteQuery({
294
+ method: 'GET',
295
+ url: '/users',
296
+ querySchema,
297
+ responseSchema,
298
+ processResponse: (data): TransformedPage => ({
299
+ items: [data],
300
+ hasMore: true,
301
+ }),
302
+ getNextPageParam: (lastPage, allPages) => {
303
+ assertType<TransformedPage>(lastPage)
304
+ assertType<TransformedPage[]>(allPages)
305
+ return lastPage.hasMore ? { page: 1, limit: 10 } : undefined
306
+ },
307
+ })
308
+ })
309
+ })
310
+
311
+ describe('QueryHelpers', () => {
312
+ test('infinite query has QueryHelpers with isInfinite=true', () => {
313
+ const query = client.infiniteQuery({
314
+ method: 'GET',
315
+ url: '/users',
316
+ querySchema,
317
+ responseSchema,
318
+ getNextPageParam: () => undefined,
319
+ })
320
+
321
+ assertType<
322
+ QueryHelpers<
323
+ '/users',
324
+ typeof querySchema,
325
+ ResponseType,
326
+ true
327
+ >['queryKey']
328
+ >(query.queryKey)
329
+ assertType<
330
+ QueryHelpers<'/users', typeof querySchema, ResponseType, true>['use']
331
+ >(query.use)
332
+ assertType<
333
+ QueryHelpers<
334
+ '/users',
335
+ typeof querySchema,
336
+ ResponseType,
337
+ true
338
+ >['useSuspense']
339
+ >(query.useSuspense)
340
+ assertType<
341
+ QueryHelpers<
342
+ '/users',
343
+ typeof querySchema,
344
+ ResponseType,
345
+ true
346
+ >['invalidate']
347
+ >(query.invalidate)
348
+ assertType<
349
+ QueryHelpers<
350
+ '/users',
351
+ typeof querySchema,
352
+ ResponseType,
353
+ true
354
+ >['invalidateAll']
355
+ >(query.invalidateAll)
356
+ })
357
+ })
358
+
359
+ describe('EndpointHelper', () => {
360
+ test('infinite query exposes endpoint property', () => {
361
+ const query = client.infiniteQuery({
362
+ method: 'GET',
363
+ url: '/users',
364
+ querySchema,
365
+ responseSchema,
366
+ getNextPageParam: () => undefined,
367
+ })
368
+
369
+ assertType<
370
+ EndpointHelper<
371
+ {
372
+ method: 'GET'
373
+ url: '/users'
374
+ querySchema: typeof querySchema
375
+ requestSchema: undefined
376
+ responseSchema: typeof responseSchema
377
+ errorSchema: undefined
378
+ urlParamsSchema: undefined
379
+ },
380
+ false
381
+ >['endpoint']
382
+ >(query.endpoint)
383
+ })
384
+ })
385
+ })
386
+
387
+ // ============================================================================
388
+ // INFINITE QUERY METHOD - DISCRIMINATOR MODE (UseDiscriminator=true)
389
+ // ============================================================================
390
+
391
+ describe('ClientInstance<true> infiniteQuery() method (discriminator mode)', () => {
392
+ describe('errorSchema includes error union in PageResult', () => {
393
+ test('infinite query returns union PageResult', () => {
394
+ const query = clientWithDiscriminator.infiniteQuery({
395
+ method: 'GET',
396
+ url: '/users',
397
+ querySchema,
398
+ responseSchema,
399
+ errorSchema,
400
+ getNextPageParam: (lastPage) => {
401
+ assertType<ResponseWithErrors>(lastPage)
402
+ return undefined
403
+ },
404
+ })
405
+
406
+ assertType<
407
+ (params: {
408
+ params: QueryType
409
+ }) => UseSuspenseInfiniteQueryOptions<
410
+ ResponseWithErrors,
411
+ Error,
412
+ InfiniteData<ResponseWithErrors>,
413
+ DataTag<Split<'/users', '/'>, ResponseWithErrors, Error>,
414
+ z.output<typeof querySchema>
415
+ >
416
+ >(query)
417
+ })
418
+
419
+ test('processResponse receives union type', () => {
420
+ clientWithDiscriminator.infiniteQuery({
421
+ method: 'GET',
422
+ url: '/users',
423
+ querySchema,
424
+ responseSchema,
425
+ errorSchema,
426
+ processResponse: (data) => {
427
+ assertType<ResponseWithErrors>(data)
428
+ return data
429
+ },
430
+ getNextPageParam: () => undefined,
431
+ })
432
+ })
433
+
434
+ test('processResponse can transform union type', () => {
435
+ type ExpectedResult =
436
+ | { ok: false; error: ErrorUnion }
437
+ | { ok: true; data: ResponseType }
438
+
439
+ const query = clientWithDiscriminator.infiniteQuery({
440
+ method: 'GET',
441
+ url: '/users',
442
+ querySchema,
443
+ responseSchema,
444
+ errorSchema,
445
+ processResponse: (data): ExpectedResult => {
446
+ // Use 'id' property to discriminate - only ResponseType has 'id'
447
+ if ('id' in data) {
448
+ return { ok: true, data }
449
+ }
450
+ return { ok: false, error: data }
451
+ },
452
+ getNextPageParam: (lastPage) => {
453
+ if (!lastPage.ok) return undefined
454
+ return { page: 1, limit: 10 }
455
+ },
456
+ })
457
+
458
+ assertType<
459
+ (params: {
460
+ params: QueryType
461
+ }) => UseSuspenseInfiniteQueryOptions<
462
+ ExpectedResult,
463
+ Error,
464
+ InfiniteData<ExpectedResult>,
465
+ DataTag<Split<'/users', '/'>, ExpectedResult, Error>,
466
+ z.output<typeof querySchema>
467
+ >
468
+ >(query)
469
+ })
470
+
471
+ test('getNextPageParam receives union type', () => {
472
+ clientWithDiscriminator.infiniteQuery({
473
+ method: 'GET',
474
+ url: '/users',
475
+ querySchema,
476
+ responseSchema,
477
+ errorSchema,
478
+ getNextPageParam: (lastPage, allPages) => {
479
+ assertType<ResponseWithErrors>(lastPage)
480
+ assertType<ResponseWithErrors[]>(allPages)
481
+ return undefined
482
+ },
483
+ })
484
+ })
485
+ })
486
+
487
+ describe('without errorSchema behaves same as default', () => {
488
+ test('infinite query without errorSchema returns only success type', () => {
489
+ const query = clientWithDiscriminator.infiniteQuery({
490
+ method: 'GET',
491
+ url: '/users',
492
+ querySchema,
493
+ responseSchema,
494
+ getNextPageParam: () => undefined,
495
+ })
496
+
497
+ assertType<
498
+ (params: {
499
+ params: QueryType
500
+ }) => UseSuspenseInfiniteQueryOptions<
501
+ ResponseType,
502
+ Error,
503
+ InfiniteData<ResponseType>,
504
+ DataTag<Split<'/users', '/'>, ResponseType, Error>,
505
+ z.output<typeof querySchema>
506
+ >
507
+ >(query)
508
+ })
509
+ })
510
+ })
511
+
512
+ // ============================================================================
513
+ // ERROR CASES - Should fail type checking
514
+ // ============================================================================
515
+
516
+ describe('infiniteQuery() error cases', () => {
517
+ describe('missing required parameters', () => {
518
+ test('infinite query without params when querySchema is defined', () => {
519
+ const query = client.infiniteQuery({
520
+ method: 'GET',
521
+ url: '/users',
522
+ querySchema,
523
+ responseSchema,
524
+ getNextPageParam: () => undefined,
525
+ })
526
+
527
+ // @ts-expect-error - missing params
528
+ query({})
529
+ })
530
+
531
+ test('infinite query without urlParams when URL has params', () => {
532
+ const query = client.infiniteQuery({
533
+ method: 'GET',
534
+ url: '/users/$userId/posts',
535
+ querySchema,
536
+ responseSchema,
537
+ getNextPageParam: () => undefined,
538
+ })
539
+
540
+ // @ts-expect-error - missing urlParams
541
+ query({ params: { page: 1, limit: 10 } })
542
+ })
543
+
544
+ test('POST infinite query without data when requestSchema is defined', () => {
545
+ const query = client.infiniteQuery({
546
+ method: 'POST',
547
+ url: '/search',
548
+ querySchema,
549
+ requestSchema,
550
+ responseSchema,
551
+ getNextPageParam: () => undefined,
552
+ })
553
+
554
+ // @ts-expect-error - missing data
555
+ query({ params: { page: 1, limit: 10 } })
556
+ })
557
+ })
558
+
559
+ describe('wrong parameter types', () => {
560
+ test('params with wrong shape', () => {
561
+ const query = client.infiniteQuery({
562
+ method: 'GET',
563
+ url: '/users',
564
+ querySchema,
565
+ responseSchema,
566
+ getNextPageParam: () => undefined,
567
+ })
568
+
569
+ // @ts-expect-error - wrong property names
570
+ query({ params: { offset: 0, count: 10 } })
571
+ })
572
+
573
+ test('params with wrong value types', () => {
574
+ const query = client.infiniteQuery({
575
+ method: 'GET',
576
+ url: '/users',
577
+ querySchema,
578
+ responseSchema,
579
+ getNextPageParam: () => undefined,
580
+ })
581
+
582
+ // @ts-expect-error - page should be number, not string
583
+ query({ params: { page: '1', limit: 10 } })
584
+ })
585
+
586
+ test('urlParams with wrong type', () => {
587
+ const query = client.infiniteQuery({
588
+ method: 'GET',
589
+ url: '/users/$userId/posts',
590
+ querySchema,
591
+ responseSchema,
592
+ getNextPageParam: () => undefined,
593
+ })
594
+
595
+ // @ts-expect-error - userId should be string | number, not boolean
596
+ query({ urlParams: { userId: true }, params: { page: 1, limit: 10 } })
597
+ })
598
+
599
+ test('data with wrong shape', () => {
600
+ const query = client.infiniteQuery({
601
+ method: 'POST',
602
+ url: '/search',
603
+ querySchema,
604
+ requestSchema,
605
+ responseSchema,
606
+ getNextPageParam: () => undefined,
607
+ })
608
+
609
+ query({
610
+ params: { page: 1, limit: 10 },
611
+ data: {
612
+ // @ts-expect-error - wrong property names
613
+ username: 'test',
614
+ mail: 'test@test.com',
615
+ },
616
+ })
617
+ })
618
+ })
619
+
620
+ describe('getNextPageParam return type', () => {
621
+ test('getNextPageParam must return compatible type', () => {
622
+ client.infiniteQuery({
623
+ method: 'GET',
624
+ url: '/users',
625
+ querySchema,
626
+ responseSchema,
627
+ // @ts-expect-error - return type doesn't match querySchema input
628
+ getNextPageParam: () => ({ wrongKey: 'value' }),
629
+ })
630
+ })
631
+ })
632
+
633
+ describe('processResponse type safety', () => {
634
+ test('processResponse receives correct input type', () => {
635
+ client.infiniteQuery({
636
+ method: 'GET',
637
+ url: '/users',
638
+ querySchema,
639
+ responseSchema,
640
+ processResponse: (data) => {
641
+ // @ts-expect-error - data doesn't have 'nonExistent' property
642
+ return data.nonExistent
643
+ },
644
+ getNextPageParam: () => undefined,
645
+ })
646
+ })
647
+ })
648
+ })