@tanstack/start-client-core 1.170.11 → 1.170.13
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/dist/esm/client-rpc/frame-decoder.js +8 -0
- package/dist/esm/client-rpc/frame-decoder.js.map +1 -1
- package/dist/esm/createMiddleware.d.ts +7 -1
- package/dist/esm/createMiddleware.js +8 -3
- package/dist/esm/createMiddleware.js.map +1 -1
- package/dist/esm/createServerFn.d.ts +7 -1
- package/dist/esm/createServerFn.js +13 -8
- package/dist/esm/createServerFn.js.map +1 -1
- package/package.json +3 -3
- package/skills/start-core/auth-server-primitives/SKILL.md +5 -5
- package/skills/start-core/middleware/SKILL.md +5 -5
- package/skills/start-core/server-functions/SKILL.md +7 -7
- package/src/client-rpc/frame-decoder.ts +19 -0
- package/src/createMiddleware.ts +25 -7
- package/src/createServerFn.ts +40 -20
- package/src/tests/createServerFn.test-d.ts +39 -37
- package/src/tests/createServerMiddleware.test-d.ts +14 -10
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: start-core/server-functions
|
|
3
3
|
description: >-
|
|
4
|
-
createServerFn (GET/POST),
|
|
4
|
+
createServerFn (GET/POST), validator (Zod or function),
|
|
5
5
|
useServerFn hook, server context utilities (getRequest,
|
|
6
6
|
getRequestHeader, setResponseHeader, setResponseStatus), error
|
|
7
7
|
handling (throw errors, redirect, notFound), streaming, FormData
|
|
@@ -75,7 +75,7 @@ Use the `useServerFn` hook to call server functions from event handlers:
|
|
|
75
75
|
import { useServerFn } from '@tanstack/react-start'
|
|
76
76
|
|
|
77
77
|
const deletePost = createServerFn({ method: 'POST' })
|
|
78
|
-
.
|
|
78
|
+
.validator((data: { id: string }) => data)
|
|
79
79
|
.handler(async ({ data }) => {
|
|
80
80
|
await db.delete('posts').where({ id: data.id })
|
|
81
81
|
return { success: true }
|
|
@@ -98,7 +98,7 @@ function DeleteButton({ postId }: { postId: string }) {
|
|
|
98
98
|
|
|
99
99
|
```tsx
|
|
100
100
|
const greetUser = createServerFn({ method: 'GET' })
|
|
101
|
-
.
|
|
101
|
+
.validator((data: { name: string }) => data)
|
|
102
102
|
.handler(async ({ data }) => {
|
|
103
103
|
return `Hello, ${data.name}!`
|
|
104
104
|
})
|
|
@@ -112,7 +112,7 @@ await greetUser({ data: { name: 'John' } })
|
|
|
112
112
|
import { z } from 'zod'
|
|
113
113
|
|
|
114
114
|
const createUser = createServerFn({ method: 'POST' })
|
|
115
|
-
.
|
|
115
|
+
.validator(
|
|
116
116
|
z.object({
|
|
117
117
|
name: z.string().min(1),
|
|
118
118
|
age: z.number().min(0),
|
|
@@ -127,7 +127,7 @@ const createUser = createServerFn({ method: 'POST' })
|
|
|
127
127
|
|
|
128
128
|
```tsx
|
|
129
129
|
const submitForm = createServerFn({ method: 'POST' })
|
|
130
|
-
.
|
|
130
|
+
.validator((data) => {
|
|
131
131
|
if (!(data instanceof FormData)) {
|
|
132
132
|
throw new Error('Expected FormData')
|
|
133
133
|
}
|
|
@@ -177,7 +177,7 @@ const requireAuth = createServerFn().handler(async () => {
|
|
|
177
177
|
import { notFound } from '@tanstack/react-router'
|
|
178
178
|
|
|
179
179
|
const getPost = createServerFn()
|
|
180
|
-
.
|
|
180
|
+
.validator((data: { id: string }) => data)
|
|
181
181
|
.handler(async ({ data }) => {
|
|
182
182
|
const post = await db.findPost(data.id)
|
|
183
183
|
if (!post) {
|
|
@@ -258,7 +258,7 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
258
258
|
import { findUserById } from './users.server'
|
|
259
259
|
|
|
260
260
|
export const getUser = createServerFn({ method: 'GET' })
|
|
261
|
-
.
|
|
261
|
+
.validator((data: { id: string }) => data)
|
|
262
262
|
.handler(async ({ data }) => {
|
|
263
263
|
return findUserById(data.id)
|
|
264
264
|
})
|
|
@@ -201,6 +201,25 @@ export function createFrameDecoder(
|
|
|
201
201
|
function extractFlattened(count: number): Uint8Array {
|
|
202
202
|
if (count === 0) return EMPTY_BUFFER
|
|
203
203
|
|
|
204
|
+
// Fast path: the requested bytes are fully contained in the first buffered
|
|
205
|
+
// chunk (the common case — most frames arrive within a single network
|
|
206
|
+
// read). Return a subarray view instead of allocating a new buffer and
|
|
207
|
+
// copying `count` bytes. The view shares the chunk's backing ArrayBuffer,
|
|
208
|
+
// which is safe because buffered chunks are never mutated in place after
|
|
209
|
+
// being read from the network.
|
|
210
|
+
const first = bufferList[0]
|
|
211
|
+
if (first && first.length >= count) {
|
|
212
|
+
const result = first.subarray(0, count)
|
|
213
|
+
if (first.length === count) {
|
|
214
|
+
bufferList.shift()
|
|
215
|
+
} else {
|
|
216
|
+
bufferList[0] = first.subarray(count)
|
|
217
|
+
}
|
|
218
|
+
totalLength -= count
|
|
219
|
+
return result
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Slow path: the requested bytes span multiple chunks — flatten by copying.
|
|
204
223
|
const result = new Uint8Array(count)
|
|
205
224
|
let offset = 0
|
|
206
225
|
let remaining = count
|
package/src/createMiddleware.ts
CHANGED
|
@@ -36,6 +36,16 @@ export const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {
|
|
|
36
36
|
type: 'request',
|
|
37
37
|
...(__opts || options),
|
|
38
38
|
}
|
|
39
|
+
const setValidator = (validator: any) => {
|
|
40
|
+
return createMiddleware(
|
|
41
|
+
{},
|
|
42
|
+
Object.assign(resolvedOptions, {
|
|
43
|
+
validator,
|
|
44
|
+
// TODO remove upon stable
|
|
45
|
+
inputValidator: validator,
|
|
46
|
+
}),
|
|
47
|
+
)
|
|
48
|
+
}
|
|
39
49
|
|
|
40
50
|
return {
|
|
41
51
|
options: resolvedOptions,
|
|
@@ -45,12 +55,9 @@ export const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {
|
|
|
45
55
|
Object.assign(resolvedOptions, { middleware }),
|
|
46
56
|
)
|
|
47
57
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Object.assign(resolvedOptions, { inputValidator }),
|
|
52
|
-
)
|
|
53
|
-
},
|
|
58
|
+
validator: setValidator,
|
|
59
|
+
// TODO remove upon stable
|
|
60
|
+
inputValidator: setValidator,
|
|
54
61
|
client: (client: any) => {
|
|
55
62
|
return createMiddleware({}, Object.assign(resolvedOptions, { client }))
|
|
56
63
|
},
|
|
@@ -170,6 +177,9 @@ export interface FunctionMiddlewareTypes<
|
|
|
170
177
|
TMiddlewares,
|
|
171
178
|
TClientSendContext
|
|
172
179
|
>
|
|
180
|
+
validator: TInputValidator
|
|
181
|
+
// TODO remove upon stable
|
|
182
|
+
/** @deprecated Use `validator` instead. */
|
|
173
183
|
inputValidator: TInputValidator
|
|
174
184
|
}
|
|
175
185
|
|
|
@@ -379,6 +389,9 @@ export interface FunctionMiddlewareOptions<
|
|
|
379
389
|
in out TClientContext,
|
|
380
390
|
> {
|
|
381
391
|
middleware?: TMiddlewares
|
|
392
|
+
validator?: ConstrainValidator<TRegister, 'GET', TInputValidator>
|
|
393
|
+
// TODO remove upon stable
|
|
394
|
+
/** @deprecated Use `validator` instead. */
|
|
382
395
|
inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>
|
|
383
396
|
client?: FunctionMiddlewareClientFn<
|
|
384
397
|
TRegister,
|
|
@@ -668,8 +681,13 @@ export interface FunctionMiddlewareAfterClient<
|
|
|
668
681
|
> {}
|
|
669
682
|
|
|
670
683
|
export interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {
|
|
684
|
+
validator: <TNewValidator>(
|
|
685
|
+
validator: ConstrainValidator<TRegister, 'GET', TNewValidator>,
|
|
686
|
+
) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>
|
|
687
|
+
// TODO remove upon stable
|
|
688
|
+
/** @deprecated Use `validator` instead. */
|
|
671
689
|
inputValidator: <TNewValidator>(
|
|
672
|
-
|
|
690
|
+
validator: ConstrainValidator<TRegister, 'GET', TNewValidator>,
|
|
673
691
|
) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>
|
|
674
692
|
}
|
|
675
693
|
|
package/src/createServerFn.ts
CHANGED
|
@@ -85,6 +85,16 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
|
|
|
85
85
|
resolvedOptions.method = 'GET' as Method
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
const setValidator = (validator: any) => {
|
|
89
|
+
// TODO remove upon stable
|
|
90
|
+
const newOptions = {
|
|
91
|
+
...resolvedOptions,
|
|
92
|
+
validator,
|
|
93
|
+
inputValidator: validator,
|
|
94
|
+
}
|
|
95
|
+
return createServerFn(undefined, newOptions) as any
|
|
96
|
+
}
|
|
97
|
+
|
|
88
98
|
const res: ServerFnBuilder<Register, Method, ServerFnStrict> = {
|
|
89
99
|
options: resolvedOptions,
|
|
90
100
|
middleware: (middleware) => {
|
|
@@ -110,10 +120,9 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
|
|
|
110
120
|
res[TSS_SERVER_FUNCTION_FACTORY] = true
|
|
111
121
|
return res
|
|
112
122
|
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
},
|
|
123
|
+
validator: setValidator,
|
|
124
|
+
// TODO remove upon stable
|
|
125
|
+
inputValidator: setValidator,
|
|
117
126
|
handler: (...args) => {
|
|
118
127
|
// This function signature changes due to AST transformations
|
|
119
128
|
// in the babel plugin. We need to cast it to the correct
|
|
@@ -249,16 +258,19 @@ export async function executeMiddleware(
|
|
|
249
258
|
|
|
250
259
|
// Execute the middleware
|
|
251
260
|
try {
|
|
252
|
-
|
|
253
|
-
'
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
261
|
+
let validator =
|
|
262
|
+
'validator' in nextMiddleware.options
|
|
263
|
+
? nextMiddleware.options.validator
|
|
264
|
+
: undefined
|
|
265
|
+
|
|
266
|
+
// TODO remove upon stable
|
|
267
|
+
if (!validator && 'inputValidator' in nextMiddleware.options) {
|
|
268
|
+
validator = nextMiddleware.options.inputValidator
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (validator && env === 'server') {
|
|
257
272
|
// Execute the middleware's input function
|
|
258
|
-
ctx.data = await execValidator(
|
|
259
|
-
nextMiddleware.options.inputValidator,
|
|
260
|
-
ctx.data,
|
|
261
|
-
)
|
|
273
|
+
ctx.data = await execValidator(validator as AnyValidator, ctx.data)
|
|
262
274
|
}
|
|
263
275
|
|
|
264
276
|
let middlewareFn: MiddlewareFn | undefined = undefined
|
|
@@ -494,6 +506,9 @@ export type ServerFnBaseOptions<
|
|
|
494
506
|
TMiddlewares,
|
|
495
507
|
ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>
|
|
496
508
|
>
|
|
509
|
+
validator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>
|
|
510
|
+
// TODO remove upon stable
|
|
511
|
+
/** @deprecated Use `validator` instead. */
|
|
497
512
|
inputValidator?: ConstrainValidator<
|
|
498
513
|
TRegister,
|
|
499
514
|
TMethod,
|
|
@@ -637,12 +652,7 @@ export type ValidatorFn<
|
|
|
637
652
|
TMiddlewares,
|
|
638
653
|
TStrict extends ServerFnStrict,
|
|
639
654
|
> = <TInputValidator>(
|
|
640
|
-
|
|
641
|
-
TRegister,
|
|
642
|
-
TMethod,
|
|
643
|
-
TInputValidator,
|
|
644
|
-
TStrict
|
|
645
|
-
>,
|
|
655
|
+
validator: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>,
|
|
646
656
|
) => ServerFnAfterValidator<
|
|
647
657
|
TRegister,
|
|
648
658
|
TMethod,
|
|
@@ -657,6 +667,9 @@ export interface ServerFnValidator<
|
|
|
657
667
|
TMiddlewares,
|
|
658
668
|
TStrict extends ServerFnStrict,
|
|
659
669
|
> {
|
|
670
|
+
validator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>
|
|
671
|
+
// TODO remove upon stable
|
|
672
|
+
/** @deprecated Use `validator` instead. */
|
|
660
673
|
inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>
|
|
661
674
|
}
|
|
662
675
|
|
|
@@ -808,6 +821,9 @@ export interface ServerFnTypes<
|
|
|
808
821
|
method: TMethod
|
|
809
822
|
strict: TStrict
|
|
810
823
|
middlewares: TMiddlewares
|
|
824
|
+
validator: TInputValidator
|
|
825
|
+
// TODO remove upon stable
|
|
826
|
+
/** @deprecated Use `validator` instead. */
|
|
811
827
|
inputValidator: TInputValidator
|
|
812
828
|
response: TResponse
|
|
813
829
|
allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>
|
|
@@ -901,10 +917,14 @@ export async function execValidator(
|
|
|
901
917
|
function serverFnBaseToMiddleware(
|
|
902
918
|
options: ServerFnBaseOptions<any, any, any, any, any>,
|
|
903
919
|
): AnyFunctionMiddleware {
|
|
920
|
+
// TODO remove upon stable
|
|
921
|
+
const validator = options.validator ?? options.inputValidator
|
|
922
|
+
|
|
904
923
|
return {
|
|
905
924
|
'~types': undefined!,
|
|
906
925
|
options: {
|
|
907
|
-
|
|
926
|
+
// TODO remove upon stable
|
|
927
|
+
inputValidator: validator,
|
|
908
928
|
client: async ({ next, sendContext, fetch, ...ctx }) => {
|
|
909
929
|
const payload = {
|
|
910
930
|
...ctx,
|
|
@@ -20,6 +20,8 @@ import type {
|
|
|
20
20
|
test('createServerFn without middleware', () => {
|
|
21
21
|
expectTypeOf(createServerFn()).toHaveProperty('handler')
|
|
22
22
|
expectTypeOf(createServerFn()).toHaveProperty('middleware')
|
|
23
|
+
expectTypeOf(createServerFn()).toHaveProperty('validator')
|
|
24
|
+
// TODO remove upon stable
|
|
23
25
|
expectTypeOf(createServerFn()).toHaveProperty('inputValidator')
|
|
24
26
|
|
|
25
27
|
createServerFn({ method: 'GET' }).handler((options) => {
|
|
@@ -35,13 +37,13 @@ test('createServerFn without middleware', () => {
|
|
|
35
37
|
test('createServerFn with validator function', () => {
|
|
36
38
|
const fnAfterValidator = createServerFn({
|
|
37
39
|
method: 'GET',
|
|
38
|
-
}).
|
|
40
|
+
}).validator((input: { input: string }) => ({
|
|
39
41
|
a: input.input,
|
|
40
42
|
}))
|
|
41
43
|
|
|
42
44
|
expectTypeOf(fnAfterValidator).toHaveProperty('handler')
|
|
43
45
|
expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
|
|
44
|
-
expectTypeOf(fnAfterValidator).not.toHaveProperty('
|
|
46
|
+
expectTypeOf(fnAfterValidator).not.toHaveProperty('validator')
|
|
45
47
|
|
|
46
48
|
const fn = fnAfterValidator.handler((options) => {
|
|
47
49
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -67,11 +69,11 @@ test('createServerFn with validator function', () => {
|
|
|
67
69
|
test('createServerFn with async validator function', () => {
|
|
68
70
|
const fnAfterValidator = createServerFn({
|
|
69
71
|
method: 'GET',
|
|
70
|
-
}).
|
|
72
|
+
}).validator((input: string) => Promise.resolve(input))
|
|
71
73
|
|
|
72
74
|
expectTypeOf(fnAfterValidator).toHaveProperty('handler')
|
|
73
75
|
expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
|
|
74
|
-
expectTypeOf(fnAfterValidator).not.toHaveProperty('
|
|
76
|
+
expectTypeOf(fnAfterValidator).not.toHaveProperty('validator')
|
|
75
77
|
|
|
76
78
|
const fn = fnAfterValidator.handler((options) => {
|
|
77
79
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -95,13 +97,13 @@ test('createServerFn with async validator function', () => {
|
|
|
95
97
|
test('createServerFn with validator with parse method', () => {
|
|
96
98
|
const fnAfterValidator = createServerFn({
|
|
97
99
|
method: 'GET',
|
|
98
|
-
}).
|
|
100
|
+
}).validator({
|
|
99
101
|
parse: (input: string) => input,
|
|
100
102
|
})
|
|
101
103
|
|
|
102
104
|
expectTypeOf(fnAfterValidator).toHaveProperty('handler')
|
|
103
105
|
expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
|
|
104
|
-
expectTypeOf(fnAfterValidator).not.toHaveProperty('
|
|
106
|
+
expectTypeOf(fnAfterValidator).not.toHaveProperty('validator')
|
|
105
107
|
|
|
106
108
|
const fn = fnAfterValidator.handler((options) => {
|
|
107
109
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -125,13 +127,13 @@ test('createServerFn with validator with parse method', () => {
|
|
|
125
127
|
test('createServerFn with async validator with parse method', () => {
|
|
126
128
|
const fnAfterValidator = createServerFn({
|
|
127
129
|
method: 'GET',
|
|
128
|
-
}).
|
|
130
|
+
}).validator({
|
|
129
131
|
parse: (input: string) => Promise.resolve(input),
|
|
130
132
|
})
|
|
131
133
|
|
|
132
134
|
expectTypeOf(fnAfterValidator).toHaveProperty('handler')
|
|
133
135
|
expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
|
|
134
|
-
expectTypeOf(fnAfterValidator).not.toHaveProperty('
|
|
136
|
+
expectTypeOf(fnAfterValidator).not.toHaveProperty('validator')
|
|
135
137
|
|
|
136
138
|
const fn = fnAfterValidator.handler((options) => {
|
|
137
139
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -174,11 +176,11 @@ test('createServerFn with standard validator', () => {
|
|
|
174
176
|
|
|
175
177
|
const fnAfterValidator = createServerFn({
|
|
176
178
|
method: 'GET',
|
|
177
|
-
}).
|
|
179
|
+
}).validator(validator)
|
|
178
180
|
|
|
179
181
|
expectTypeOf(fnAfterValidator).toHaveProperty('handler')
|
|
180
182
|
expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
|
|
181
|
-
expectTypeOf(fnAfterValidator).not.toHaveProperty('
|
|
183
|
+
expectTypeOf(fnAfterValidator).not.toHaveProperty('validator')
|
|
182
184
|
|
|
183
185
|
const fn = fnAfterValidator.handler((options) => {
|
|
184
186
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -222,11 +224,11 @@ test('createServerFn with async standard validator', () => {
|
|
|
222
224
|
|
|
223
225
|
const fnAfterValidator = createServerFn({
|
|
224
226
|
method: 'GET',
|
|
225
|
-
}).
|
|
227
|
+
}).validator(validator)
|
|
226
228
|
|
|
227
229
|
expectTypeOf(fnAfterValidator).toHaveProperty('handler')
|
|
228
230
|
expectTypeOf(fnAfterValidator).toHaveProperty('middleware')
|
|
229
|
-
expectTypeOf(fnAfterValidator).not.toHaveProperty('
|
|
231
|
+
expectTypeOf(fnAfterValidator).not.toHaveProperty('validator')
|
|
230
232
|
|
|
231
233
|
const fn = fnAfterValidator.handler((options) => {
|
|
232
234
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -285,7 +287,7 @@ test('createServerFn with middleware and context', () => {
|
|
|
285
287
|
])
|
|
286
288
|
|
|
287
289
|
expectTypeOf(fnWithMiddleware).toHaveProperty('handler')
|
|
288
|
-
expectTypeOf(fnWithMiddleware).toHaveProperty('
|
|
290
|
+
expectTypeOf(fnWithMiddleware).toHaveProperty('validator')
|
|
289
291
|
|
|
290
292
|
fnWithMiddleware.handler((options) => {
|
|
291
293
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -303,14 +305,14 @@ test('createServerFn with middleware and context', () => {
|
|
|
303
305
|
})
|
|
304
306
|
|
|
305
307
|
describe('createServerFn with middleware and validator', () => {
|
|
306
|
-
const middleware1 = createMiddleware({ type: 'function' }).
|
|
308
|
+
const middleware1 = createMiddleware({ type: 'function' }).validator(
|
|
307
309
|
(input: { readonly inputA: 'inputA' }) =>
|
|
308
310
|
({
|
|
309
311
|
outputA: 'outputA',
|
|
310
312
|
}) as const,
|
|
311
313
|
)
|
|
312
314
|
|
|
313
|
-
const middleware2 = createMiddleware({ type: 'function' }).
|
|
315
|
+
const middleware2 = createMiddleware({ type: 'function' }).validator(
|
|
314
316
|
(input: { readonly inputB: 'inputB' }) =>
|
|
315
317
|
({
|
|
316
318
|
outputB: 'outputB',
|
|
@@ -325,7 +327,7 @@ describe('createServerFn with middleware and validator', () => {
|
|
|
325
327
|
test(`response`, () => {
|
|
326
328
|
const fn = createServerFn({ method: 'GET' })
|
|
327
329
|
.middleware([middleware3])
|
|
328
|
-
.
|
|
330
|
+
.validator(
|
|
329
331
|
(input: { readonly inputC: 'inputC' }) =>
|
|
330
332
|
({
|
|
331
333
|
outputC: 'outputC',
|
|
@@ -368,7 +370,7 @@ describe('createServerFn with middleware and validator', () => {
|
|
|
368
370
|
|
|
369
371
|
test('createServerFn overrides properties', () => {
|
|
370
372
|
const middleware1 = createMiddleware({ type: 'function' })
|
|
371
|
-
.
|
|
373
|
+
.validator(
|
|
372
374
|
() =>
|
|
373
375
|
({
|
|
374
376
|
input: 'a' as 'a' | 'b' | 'c',
|
|
@@ -393,7 +395,7 @@ test('createServerFn overrides properties', () => {
|
|
|
393
395
|
|
|
394
396
|
const middleware2 = createMiddleware({ type: 'function' })
|
|
395
397
|
.middleware([middleware1])
|
|
396
|
-
.
|
|
398
|
+
.validator(
|
|
397
399
|
() =>
|
|
398
400
|
({
|
|
399
401
|
input: 'b' as 'b' | 'c',
|
|
@@ -416,7 +418,7 @@ test('createServerFn overrides properties', () => {
|
|
|
416
418
|
|
|
417
419
|
createServerFn()
|
|
418
420
|
.middleware([middleware2])
|
|
419
|
-
.
|
|
421
|
+
.validator(
|
|
420
422
|
() =>
|
|
421
423
|
({
|
|
422
424
|
input: 'c',
|
|
@@ -432,7 +434,7 @@ test('createServerFn overrides properties', () => {
|
|
|
432
434
|
|
|
433
435
|
test('createServerFn where validator is a primitive', () => {
|
|
434
436
|
createServerFn({ method: 'GET' })
|
|
435
|
-
.
|
|
437
|
+
.validator(() => 'c' as const)
|
|
436
438
|
.handler((options) => {
|
|
437
439
|
expectTypeOf(options).toEqualTypeOf<{
|
|
438
440
|
context: undefined
|
|
@@ -445,7 +447,7 @@ test('createServerFn where validator is a primitive', () => {
|
|
|
445
447
|
|
|
446
448
|
test('createServerFn where validator is optional if object is optional', () => {
|
|
447
449
|
const fn = createServerFn({ method: 'GET' })
|
|
448
|
-
.
|
|
450
|
+
.validator((input: 'c' | undefined) => input)
|
|
449
451
|
.handler((options) => {
|
|
450
452
|
expectTypeOf(options).toEqualTypeOf<{
|
|
451
453
|
context: undefined
|
|
@@ -520,7 +522,7 @@ test('createServerFn cannot return function', () => {
|
|
|
520
522
|
|
|
521
523
|
test('createServerFn strict false can validate and return function', () => {
|
|
522
524
|
const fn = createServerFn({ method: 'GET', strict: false })
|
|
523
|
-
.
|
|
525
|
+
.validator((input: { func: () => 'input' }) => ({
|
|
524
526
|
output: input.func(),
|
|
525
527
|
}))
|
|
526
528
|
.handler(({ data }) => {
|
|
@@ -551,7 +553,7 @@ test('createServerFn strict false factory preserves strictness', () => {
|
|
|
551
553
|
})
|
|
552
554
|
|
|
553
555
|
const myServerFn = createServerFnWithoutSerializationCheck()
|
|
554
|
-
.
|
|
556
|
+
.validator((input: { func: () => 'input' }) => ({
|
|
555
557
|
output: input.func(),
|
|
556
558
|
}))
|
|
557
559
|
.handler(({ data }) => {
|
|
@@ -578,7 +580,7 @@ test('createServerFn strict false factory preserves strictness', () => {
|
|
|
578
580
|
|
|
579
581
|
test('createServerFn strict input false can validate function', () => {
|
|
580
582
|
const fn = createServerFn({ strict: { input: false } })
|
|
581
|
-
.
|
|
583
|
+
.validator((input: { func: () => 'input' }) => ({
|
|
582
584
|
output: input.func(),
|
|
583
585
|
}))
|
|
584
586
|
.handler(({ data }) => {
|
|
@@ -644,7 +646,7 @@ test('ServerFnReturnType skips serialization when strict output is false', () =>
|
|
|
644
646
|
})
|
|
645
647
|
|
|
646
648
|
test('createServerFn cannot validate function', () => {
|
|
647
|
-
const validator = createServerFn().
|
|
649
|
+
const validator = createServerFn().validator<
|
|
648
650
|
(input: { func: () => 'string' }) => { output: 'string' }
|
|
649
651
|
>
|
|
650
652
|
|
|
@@ -665,7 +667,7 @@ test('createServerFn strict output false still checks input', () => {
|
|
|
665
667
|
const validator = createServerFn({
|
|
666
668
|
method: 'GET',
|
|
667
669
|
strict: { output: false },
|
|
668
|
-
}).
|
|
670
|
+
}).validator<(input: { func: () => 'string' }) => { output: 'string' }>
|
|
669
671
|
|
|
670
672
|
expectTypeOf(validator)
|
|
671
673
|
.parameter(0)
|
|
@@ -681,7 +683,7 @@ test('createServerFn strict output false still checks input', () => {
|
|
|
681
683
|
})
|
|
682
684
|
|
|
683
685
|
test('createServerFn can validate Date', () => {
|
|
684
|
-
const validator = createServerFn().
|
|
686
|
+
const validator = createServerFn().validator<
|
|
685
687
|
(input: Date) => { output: 'string' }
|
|
686
688
|
>
|
|
687
689
|
|
|
@@ -693,7 +695,7 @@ test('createServerFn can validate Date', () => {
|
|
|
693
695
|
})
|
|
694
696
|
|
|
695
697
|
test('createServerFn can validate FormData', () => {
|
|
696
|
-
const validator = createServerFn({ method: 'POST' }).
|
|
698
|
+
const validator = createServerFn({ method: 'POST' }).validator<
|
|
697
699
|
(input: FormData) => { output: 'string' }
|
|
698
700
|
>
|
|
699
701
|
|
|
@@ -701,7 +703,7 @@ test('createServerFn can validate FormData', () => {
|
|
|
701
703
|
})
|
|
702
704
|
|
|
703
705
|
test('createServerFn cannot validate FormData for GET', () => {
|
|
704
|
-
const validator = createServerFn({ method: 'GET' }).
|
|
706
|
+
const validator = createServerFn({ method: 'GET' }).validator<
|
|
705
707
|
(input: FormData) => { output: 'string' }
|
|
706
708
|
>
|
|
707
709
|
|
|
@@ -740,7 +742,7 @@ test('ServerFnReturnType distributes Response union', () => {
|
|
|
740
742
|
|
|
741
743
|
test('createServerFn can be used as a mutation function', () => {
|
|
742
744
|
const serverFn = createServerFn()
|
|
743
|
-
.
|
|
745
|
+
.validator((data: number) => data)
|
|
744
746
|
.handler(() => 'foo')
|
|
745
747
|
|
|
746
748
|
type MutationFunction<TData = unknown, TVariables = unknown> = (
|
|
@@ -757,7 +759,7 @@ test('createServerFn can be used as a mutation function', () => {
|
|
|
757
759
|
|
|
758
760
|
test('createServerFn validator infers unknown for default input type', () => {
|
|
759
761
|
const fn = createServerFn()
|
|
760
|
-
.
|
|
762
|
+
.validator((input) => {
|
|
761
763
|
expectTypeOf(input).toEqualTypeOf<unknown>()
|
|
762
764
|
|
|
763
765
|
if (typeof input === 'number') return 'success' as const
|
|
@@ -807,7 +809,7 @@ test('incrementally building createServerFn with multiple middleware calls', ()
|
|
|
807
809
|
])
|
|
808
810
|
|
|
809
811
|
expectTypeOf(builderWithMw1).toHaveProperty('handler')
|
|
810
|
-
expectTypeOf(builderWithMw1).toHaveProperty('
|
|
812
|
+
expectTypeOf(builderWithMw1).toHaveProperty('validator')
|
|
811
813
|
expectTypeOf(builderWithMw1).toHaveProperty('middleware')
|
|
812
814
|
|
|
813
815
|
builderWithMw1.handler((options) => {
|
|
@@ -827,7 +829,7 @@ test('incrementally building createServerFn with multiple middleware calls', ()
|
|
|
827
829
|
])
|
|
828
830
|
|
|
829
831
|
expectTypeOf(builderWithMw2).toHaveProperty('handler')
|
|
830
|
-
expectTypeOf(builderWithMw2).toHaveProperty('
|
|
832
|
+
expectTypeOf(builderWithMw2).toHaveProperty('validator')
|
|
831
833
|
expectTypeOf(builderWithMw2).toHaveProperty('middleware')
|
|
832
834
|
|
|
833
835
|
builderWithMw2.handler((options) => {
|
|
@@ -848,7 +850,7 @@ test('incrementally building createServerFn with multiple middleware calls', ()
|
|
|
848
850
|
])
|
|
849
851
|
|
|
850
852
|
expectTypeOf(builderWithMw3).toHaveProperty('handler')
|
|
851
|
-
expectTypeOf(builderWithMw3).toHaveProperty('
|
|
853
|
+
expectTypeOf(builderWithMw3).toHaveProperty('validator')
|
|
852
854
|
expectTypeOf(builderWithMw3).toHaveProperty('middleware')
|
|
853
855
|
|
|
854
856
|
builderWithMw3.handler((options) => {
|
|
@@ -916,7 +918,7 @@ test('createServerFn with request middleware and function middleware', () => {
|
|
|
916
918
|
})
|
|
917
919
|
|
|
918
920
|
const funMw = createMiddleware({ type: 'function' })
|
|
919
|
-
.
|
|
921
|
+
.validator((x: string) => x)
|
|
920
922
|
.server(({ next }) => {
|
|
921
923
|
return next({ context: { a: 'a' } as const })
|
|
922
924
|
})
|
|
@@ -927,7 +929,7 @@ test('createServerFn with request middleware and function middleware', () => {
|
|
|
927
929
|
expectTypeOf(fn({ data: 'a' })).toEqualTypeOf<Promise<{}>>()
|
|
928
930
|
})
|
|
929
931
|
|
|
930
|
-
test('createServerFn with
|
|
932
|
+
test('createServerFn with validator and request middleware', () => {
|
|
931
933
|
const loggingMiddleware = createMiddleware().server(async ({ next }) => {
|
|
932
934
|
console.log('Logging middleware executed on the server')
|
|
933
935
|
const result = await next()
|
|
@@ -936,7 +938,7 @@ test('createServerFn with inputValidator and request middleware', () => {
|
|
|
936
938
|
|
|
937
939
|
const fn = createServerFn()
|
|
938
940
|
.middleware([loggingMiddleware])
|
|
939
|
-
.
|
|
941
|
+
.validator(({ userName }: { userName: string }) => {
|
|
940
942
|
return { userName }
|
|
941
943
|
})
|
|
942
944
|
.handler(async ({ data }) => {
|