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