@tanstack/react-start-client 1.111.15 → 1.112.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.
@@ -1,4 +1,4 @@
1
- import { expectTypeOf, test } from 'vitest'
1
+ import { describe, expectTypeOf, test } from 'vitest'
2
2
  import { createServerFn } from '../createServerFn'
3
3
  import { createMiddleware } from '../createMiddleware'
4
4
  import type { Constrain, Validator } from '@tanstack/router-core'
@@ -20,16 +20,17 @@ test('createServerFn without middleware', () => {
20
20
  context: undefined
21
21
  data: undefined
22
22
  signal: AbortSignal
23
+ response: 'data'
23
24
  }>()
24
25
  })
25
26
  })
26
27
 
27
28
  test('createServerFn with validator', () => {
28
- const fnAfterValidator = createServerFn({ method: 'GET' }).validator(
29
- (input: { input: string }) => ({
30
- a: input.input,
31
- }),
32
- )
29
+ const fnAfterValidator = createServerFn({
30
+ method: 'GET',
31
+ }).validator((input: { input: string }) => ({
32
+ a: input.input,
33
+ }))
33
34
 
34
35
  expectTypeOf(fnAfterValidator).toHaveProperty('handler')
35
36
  expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
@@ -43,6 +44,7 @@ test('createServerFn with validator', () => {
43
44
  a: string
44
45
  }
45
46
  signal: AbortSignal
47
+ response: 'data'
46
48
  }>()
47
49
  })
48
50
 
@@ -50,11 +52,10 @@ test('createServerFn with validator', () => {
50
52
  data: { input: string }
51
53
  headers?: HeadersInit
52
54
  type?: 'static' | 'dynamic'
53
- fullResponse?: boolean
54
55
  signal?: AbortSignal
55
56
  }>()
56
57
 
57
- expectTypeOf(fn).returns.resolves.toEqualTypeOf<void>()
58
+ expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
58
59
  })
59
60
 
60
61
  test('createServerFn with middleware and context', () => {
@@ -105,11 +106,12 @@ test('createServerFn with middleware and context', () => {
105
106
  }
106
107
  data: undefined
107
108
  signal: AbortSignal
109
+ response: 'data'
108
110
  }>()
109
111
  })
110
112
  })
111
113
 
112
- test('createServerFn with middleware and validator', () => {
114
+ describe('createServerFn with middleware and validator', () => {
113
115
  const middleware1 = createMiddleware().validator(
114
116
  (input: { readonly inputA: 'inputA' }) =>
115
117
  ({
@@ -126,60 +128,96 @@ test('createServerFn with middleware and validator', () => {
126
128
 
127
129
  const middleware3 = createMiddleware().middleware([middleware1, middleware2])
128
130
 
129
- const fn = createServerFn({ method: 'GET' })
130
- .middleware([middleware3])
131
- .validator(
132
- (input: { readonly inputC: 'inputC' }) =>
133
- ({
134
- outputC: 'outputC',
135
- }) as const,
136
- )
137
- .handler((options) => {
138
- expectTypeOf(options).toEqualTypeOf<{
139
- method: 'GET'
140
- context: undefined
141
- data: {
142
- readonly outputA: 'outputA'
143
- readonly outputB: 'outputB'
144
- readonly outputC: 'outputC'
145
- }
146
- signal: AbortSignal
147
- }>()
131
+ test(`response: 'data'`, () => {
132
+ const fn = createServerFn({ method: 'GET', response: 'data' })
133
+ .middleware([middleware3])
134
+ .validator(
135
+ (input: { readonly inputC: 'inputC' }) =>
136
+ ({
137
+ outputC: 'outputC',
138
+ }) as const,
139
+ )
140
+ .handler((options) => {
141
+ expectTypeOf(options).toEqualTypeOf<{
142
+ method: 'GET'
143
+ context: undefined
144
+ data: {
145
+ readonly outputA: 'outputA'
146
+ readonly outputB: 'outputB'
147
+ readonly outputC: 'outputC'
148
+ }
149
+ signal: AbortSignal
150
+ response: 'data'
151
+ }>()
152
+
153
+ return 'some-data' as const
154
+ })
155
+
156
+ expectTypeOf(fn).parameter(0).toEqualTypeOf<{
157
+ data: {
158
+ readonly inputA: 'inputA'
159
+ readonly inputB: 'inputB'
160
+ readonly inputC: 'inputC'
161
+ }
162
+ headers?: HeadersInit
163
+ type?: 'static' | 'dynamic'
164
+ signal?: AbortSignal
165
+ }>()
148
166
 
149
- return 'data' as const
150
- })
167
+ expectTypeOf(fn).returns.resolves.toEqualTypeOf<'some-data'>()
168
+ expectTypeOf(() =>
169
+ fn({
170
+ data: { inputA: 'inputA', inputB: 'inputB', inputC: 'inputC' },
171
+ }),
172
+ ).returns.resolves.toEqualTypeOf<'some-data'>()
173
+ })
151
174
 
152
- expectTypeOf(fn).parameter(0).toEqualTypeOf<{
153
- data: {
154
- readonly inputA: 'inputA'
155
- readonly inputB: 'inputB'
156
- readonly inputC: 'inputC'
157
- }
158
- headers?: HeadersInit
159
- type?: 'static' | 'dynamic'
160
- fullResponse?: boolean
161
- signal?: AbortSignal
162
- }>()
175
+ test(`response: 'full'`, () => {
176
+ const fn = createServerFn({ method: 'GET', response: 'full' })
177
+ .middleware([middleware3])
178
+ .validator(
179
+ (input: { readonly inputC: 'inputC' }) =>
180
+ ({
181
+ outputC: 'outputC',
182
+ }) as const,
183
+ )
184
+ .handler((options) => {
185
+ expectTypeOf(options).toEqualTypeOf<{
186
+ method: 'GET'
187
+ context: undefined
188
+ data: {
189
+ readonly outputA: 'outputA'
190
+ readonly outputB: 'outputB'
191
+ readonly outputC: 'outputC'
192
+ }
193
+ signal: AbortSignal
194
+ response: 'full'
195
+ }>()
196
+
197
+ return 'some-data' as const
198
+ })
199
+
200
+ expectTypeOf(fn).parameter(0).toEqualTypeOf<{
201
+ data: {
202
+ readonly inputA: 'inputA'
203
+ readonly inputB: 'inputB'
204
+ readonly inputC: 'inputC'
205
+ }
206
+ headers?: HeadersInit
207
+ type?: 'static' | 'dynamic'
208
+ signal?: AbortSignal
209
+ }>()
163
210
 
164
- expectTypeOf(fn).returns.resolves.toEqualTypeOf<'data'>()
165
-
166
- expectTypeOf(() =>
167
- fn({
168
- fullResponse: false,
169
- data: { inputA: 'inputA', inputB: 'inputB', inputC: 'inputC' },
170
- }),
171
- ).returns.resolves.toEqualTypeOf<'data'>()
172
-
173
- expectTypeOf(() =>
174
- fn({
175
- fullResponse: true,
176
- data: { inputA: 'inputA', inputB: 'inputB', inputC: 'inputC' },
177
- }),
178
- ).returns.resolves.toEqualTypeOf<{
179
- result: 'data'
180
- context: undefined
181
- error: unknown
182
- }>()
211
+ expectTypeOf(() =>
212
+ fn({
213
+ data: { inputA: 'inputA', inputB: 'inputB', inputC: 'inputC' },
214
+ }),
215
+ ).returns.resolves.toEqualTypeOf<{
216
+ result: 'some-data'
217
+ context: undefined
218
+ error: unknown
219
+ }>()
220
+ })
183
221
  })
184
222
 
185
223
  test('createServerFn overrides properties', () => {
@@ -255,6 +293,7 @@ test('createServerFn where validator is a primitive', () => {
255
293
  context: undefined
256
294
  data: 'c'
257
295
  signal: AbortSignal
296
+ response: 'data'
258
297
  }>()
259
298
  })
260
299
  })
@@ -268,6 +307,7 @@ test('createServerFn where validator is optional if object is optional', () => {
268
307
  context: undefined
269
308
  data: 'c' | undefined
270
309
  signal: AbortSignal
310
+ response: 'data'
271
311
  }>()
272
312
  })
273
313
 
@@ -276,13 +316,12 @@ test('createServerFn where validator is optional if object is optional', () => {
276
316
  data?: 'c' | undefined
277
317
  headers?: HeadersInit
278
318
  type?: 'static' | 'dynamic'
279
- fullResponse?: boolean
280
319
  signal?: AbortSignal
281
320
  }
282
321
  | undefined
283
322
  >()
284
323
 
285
- expectTypeOf(fn).returns.resolves.toEqualTypeOf<void>()
324
+ expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
286
325
  })
287
326
 
288
327
  test('createServerFn where data is optional if there is no validator', () => {
@@ -292,6 +331,7 @@ test('createServerFn where data is optional if there is no validator', () => {
292
331
  context: undefined
293
332
  data: undefined
294
333
  signal: AbortSignal
334
+ response: 'data'
295
335
  }>()
296
336
  })
297
337
 
@@ -300,13 +340,12 @@ test('createServerFn where data is optional if there is no validator', () => {
300
340
  data?: undefined
301
341
  headers?: HeadersInit
302
342
  type?: 'static' | 'dynamic'
303
- fullResponse?: boolean
304
343
  signal?: AbortSignal
305
344
  }
306
345
  | undefined
307
346
  >()
308
347
 
309
- expectTypeOf(fn).returns.resolves.toEqualTypeOf<void>()
348
+ expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
310
349
  })
311
350
 
312
351
  test('createServerFn returns Date', () => {
@@ -388,3 +427,75 @@ test('createServerFn can validate FormData', () => {
388
427
  >
389
428
  >()
390
429
  })
430
+
431
+ describe('response', () => {
432
+ describe('data', () => {
433
+ test(`response: 'data' is passed into handler without response being set`, () => {
434
+ createServerFn().handler((options) => {
435
+ expectTypeOf(options.response).toEqualTypeOf<'data'>()
436
+ })
437
+ })
438
+
439
+ test(`response: 'data' is passed into handler with explicit response: 'data'`, () => {
440
+ createServerFn({ response: 'data' }).handler((options) => {
441
+ expectTypeOf(options.response).toEqualTypeOf<'data'>()
442
+ })
443
+ })
444
+ })
445
+ describe('full', () => {
446
+ test(`response: 'full' is passed into handler`, () => {
447
+ createServerFn({ response: 'full' }).handler((options) => {
448
+ expectTypeOf(options.response).toEqualTypeOf<'full'>()
449
+ })
450
+ })
451
+ })
452
+
453
+ describe('raw', () => {
454
+ test(`response: 'raw' is passed into handler`, () => {
455
+ createServerFn({ response: 'raw' }).handler((options) => {
456
+ expectTypeOf(options.response).toEqualTypeOf<'raw'>()
457
+ return null
458
+ })
459
+ })
460
+ })
461
+ test(`client receives Response when Response is returned`, () => {
462
+ const fn = createServerFn({ response: 'raw' }).handler(() => {
463
+ return new Response('Hello World')
464
+ })
465
+
466
+ expectTypeOf(fn()).toEqualTypeOf<Promise<Response>>()
467
+ })
468
+
469
+ test(`client receives Response when ReadableStream is returned`, () => {
470
+ const fn = createServerFn({ response: 'raw' }).handler(() => {
471
+ return new ReadableStream()
472
+ })
473
+
474
+ expectTypeOf(fn()).toEqualTypeOf<Promise<Response>>()
475
+ })
476
+
477
+ test(`client receives Response when string is returned`, () => {
478
+ const fn = createServerFn({ response: 'raw' }).handler(() => {
479
+ return 'hello'
480
+ })
481
+
482
+ expectTypeOf(fn()).toEqualTypeOf<Promise<Response>>()
483
+ })
484
+ })
485
+
486
+ test('createServerFn can be used as a mutation function', () => {
487
+ const serverFn = createServerFn()
488
+ .validator((data: number) => data)
489
+ .handler(() => 'foo')
490
+
491
+ type MutationFunction<TData = unknown, TVariables = unknown> = (
492
+ variables: TVariables,
493
+ ) => Promise<TData>
494
+
495
+ // simplifeid "clone" of @tansctack/react-query's useMutation
496
+ const useMutation = <TData, TVariables>(
497
+ fn: MutationFunction<TData, TVariables>,
498
+ ) => {}
499
+
500
+ useMutation(serverFn)
501
+ })