@tanstack/start-client-core 1.170.10 → 1.170.12
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/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/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
|
@@ -33,6 +33,8 @@ export interface FunctionMiddlewareTypes<in out TRegister, in out TMiddlewares,
|
|
|
33
33
|
allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext, TServerContext>;
|
|
34
34
|
clientSendContext: TClientSendContext;
|
|
35
35
|
allClientSendContext: AssignAllClientSendContext<TMiddlewares, TClientSendContext>;
|
|
36
|
+
validator: TInputValidator;
|
|
37
|
+
/** @deprecated Use `validator` instead. */
|
|
36
38
|
inputValidator: TInputValidator;
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
@@ -72,6 +74,8 @@ type __AssignAllServerFnContext<TMiddlewares, TSendContext = undefined, TServerC
|
|
|
72
74
|
export type AssignAllClientSendContext<TMiddlewares, TSendContext = undefined> = unknown extends TSendContext ? TSendContext : Assign<AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>, TSendContext>;
|
|
73
75
|
export interface FunctionMiddlewareOptions<in out TRegister, in out TMiddlewares, in out TInputValidator, in out TServerContext, in out TClientContext> {
|
|
74
76
|
middleware?: TMiddlewares;
|
|
77
|
+
validator?: ConstrainValidator<TRegister, 'GET', TInputValidator>;
|
|
78
|
+
/** @deprecated Use `validator` instead. */
|
|
75
79
|
inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>;
|
|
76
80
|
client?: FunctionMiddlewareClientFn<TRegister, TMiddlewares, TInputValidator, TServerContext, TClientContext>;
|
|
77
81
|
server?: FunctionMiddlewareServerFn<TRegister, TMiddlewares, TInputValidator, TServerContext, unknown, unknown>;
|
|
@@ -136,7 +140,9 @@ export type FunctionClientResultWithContext<in out TMiddlewares, in out TSendCon
|
|
|
136
140
|
export interface FunctionMiddlewareAfterClient<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> extends FunctionMiddlewareWithTypes<TRegister, TMiddlewares, TInputValidator, undefined, TServerSendContext, TClientContext, undefined>, FunctionMiddlewareServer<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> {
|
|
137
141
|
}
|
|
138
142
|
export interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {
|
|
139
|
-
|
|
143
|
+
validator: <TNewValidator>(validator: ConstrainValidator<TRegister, 'GET', TNewValidator>) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>;
|
|
144
|
+
/** @deprecated Use `validator` instead. */
|
|
145
|
+
inputValidator: <TNewValidator>(validator: ConstrainValidator<TRegister, 'GET', TNewValidator>) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>;
|
|
140
146
|
}
|
|
141
147
|
export interface FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TInputValidator> extends FunctionMiddlewareWithTypes<TRegister, TMiddlewares, TInputValidator, undefined, undefined, undefined, undefined>, FunctionMiddlewareServer<TRegister, TMiddlewares, TInputValidator, undefined, undefined>, FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {
|
|
142
148
|
}
|
|
@@ -4,14 +4,19 @@ var createMiddleware = (options, __opts) => {
|
|
|
4
4
|
type: "request",
|
|
5
5
|
...__opts || options
|
|
6
6
|
};
|
|
7
|
+
const setValidator = (validator) => {
|
|
8
|
+
return createMiddleware({}, Object.assign(resolvedOptions, {
|
|
9
|
+
validator,
|
|
10
|
+
inputValidator: validator
|
|
11
|
+
}));
|
|
12
|
+
};
|
|
7
13
|
return {
|
|
8
14
|
options: resolvedOptions,
|
|
9
15
|
middleware: (middleware) => {
|
|
10
16
|
return createMiddleware({}, Object.assign(resolvedOptions, { middleware }));
|
|
11
17
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
18
|
+
validator: setValidator,
|
|
19
|
+
inputValidator: setValidator,
|
|
15
20
|
client: (client) => {
|
|
16
21
|
return createMiddleware({}, Object.assign(resolvedOptions, { client }));
|
|
17
22
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMiddleware.js","names":[],"sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type {\n AnyServerFn,\n ConstrainValidator,\n CustomFetch,\n Method,\n} from './createServerFn'\nimport type { ClientFnMeta, ServerFnMeta } from './constants'\nimport type {\n AnyContext,\n Assign,\n Constrain,\n Expand,\n IntersectAssign,\n Register,\n ResolveValidatorInput,\n ResolveValidatorOutput,\n ValidateSerializableInput,\n} from '@tanstack/router-core'\n\nexport type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(\n options?: {\n type?: TType\n },\n __opts?: FunctionMiddlewareOptions<\n TRegister,\n unknown,\n undefined,\n undefined,\n undefined\n >,\n) => CreateMiddlewareResult<TRegister, TType>\n\nexport const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {\n const resolvedOptions = {\n type: 'request',\n ...(__opts || options),\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, { middleware }),\n )\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, { inputValidator }),\n )\n },\n client: (client: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { client }))\n },\n server: (server: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { server }))\n },\n } as any\n}\n\nexport type MiddlewareType = 'request' | 'function'\n\nexport type CreateMiddlewareResult<\n TRegister,\n TType extends MiddlewareType,\n> = 'request' extends TType\n ? RequestMiddleware<TRegister>\n : FunctionMiddleware<TRegister>\n\nexport interface FunctionMiddleware<\n TRegister,\n> extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware>\n >,\n ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares>\n}\n\nexport interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>,\n FunctionMiddlewareValidator<TRegister, TMiddlewares> {}\n\nexport interface FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> {\n '~types': FunctionMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n >\n options: FunctionMiddlewareOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n}\n\nexport interface FunctionMiddlewareTypes<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TServerSendContext,\n in out TClientContext,\n in out TClientSendContext,\n> {\n type: 'function'\n middlewares: TMiddlewares\n input: ResolveValidatorInput<TInputValidator>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n output: ResolveValidatorOutput<TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n clientContext: TClientContext\n allClientContextBeforeNext: AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext\n >\n allClientContextAfterNext: AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext,\n TClientSendContext\n >\n serverContext: TServerContext\n serverSendContext: TServerSendContext\n allServerSendContext: AssignAllServerSendContext<\n TMiddlewares,\n TServerSendContext\n >\n allServerContext: AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n clientSendContext: TClientSendContext\n allClientSendContext: AssignAllClientSendContext<\n TMiddlewares,\n TClientSendContext\n >\n inputValidator: TInputValidator\n}\n\n/**\n * Recursively resolve the input type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allInput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allInput'>,\n ResolveValidatorInput<TInputValidator>\n >\n\nexport type IntersectAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? IntersectAllMiddleware<\n TRest,\n TType,\n IntersectAssign<\n TAcc,\n TMiddleware['~types'][TType & keyof TMiddleware['~types']]\n >\n >\n : TAcc\n : TAcc\n\nexport type AnyFunctionMiddleware = FunctionMiddlewareWithTypes<\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n\n/**\n * Recursively merge the output type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allOutput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allOutput'>,\n Awaited<ResolveValidatorOutput<TInputValidator>>\n >\n\n/**\n * Recursively resolve the client context type produced by a sequence of middleware\n */\nexport type AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext = undefined,\n> = unknown extends TClientContext\n ? TClientContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>,\n TClientContext\n >\n\nexport type AssignAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? AssignAllMiddleware<\n TRest,\n TType,\n Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]>\n >\n : TAcc\n : TAcc\n\nexport type AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext = undefined,\n TSendContext = undefined,\n> = unknown extends TClientContext\n ? Assign<TClientContext, TSendContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>,\n Assign<TClientContext, TSendContext>\n >\n\nexport type AssignAllServerSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>,\n TSendContext\n >\n\nexport type AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n // Fetch Request Context\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>,\n __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext>\n >\n>\n\n// export type GlobalFetchRequestContext<TRegister> = AnyContext\nexport type GlobalFetchRequestContext = Register extends {\n server: { requestContext: infer TRequestContext }\n}\n ? TRequestContext\n : AnyContext\n\nexport type GlobalServerRequestContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any>\n}\n ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerRequestContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,\n Assign<\n GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,/\n __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext>\n >\n >\n>\n\ntype GlobalServerFnContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares>\n}\n ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerFnContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllClientSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>,\n TSendContext\n >\n\nexport interface FunctionMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TClientContext,\n> {\n middleware?: TMiddlewares\n inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n client?: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n server?: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n unknown,\n unknown\n >\n}\n\nexport type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <\n TSendContext = undefined,\n TNewClientContext = undefined,\n>(ctx?: {\n context?: TNewClientContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n headers?: HeadersInit\n fetch?: CustomFetch\n}) => Promise<\n FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>\n>\n\nexport interface FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n> {\n server: <TNewServerContext = undefined, TSendContext = undefined>(\n server: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >,\n ) => FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TNewServerContext,\n TServerSendContext,\n TClientContext,\n TSendContext\n >\n}\n\nexport type FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext,\n> = (\n options: FunctionMiddlewareServerFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext\n >,\n) => FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n>\n\nexport type FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n> = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: {\n context?: TNewServerContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n}) => Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >\n>\n\nexport type FunctionServerResultWithContext<\n in out TRegister,\n in out TMiddlewares,\n in out TServerSendContext,\n in out TServerContext,\n in out TSendContext,\n> = {\n 'use functions must return the result of next()': true\n '~types': {\n context: TServerContext\n sendContext: TSendContext\n }\n context: Expand<\n AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n >\n sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>>\n}\n\nexport interface FunctionMiddlewareServerFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerSendContext,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<\n AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext>\n >\n next: FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext\n >\n method: Method\n serverFnMeta: ServerFnMeta\n signal: AbortSignal\n}\n\nexport type FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext,\n> =\n | Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n >\n | FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n\nexport interface FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> extends FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n> {}\n\nexport interface FunctionMiddlewareClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n> {\n client: <TSendServerContext = undefined, TNewClientContext = undefined>(\n client: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >,\n ) => FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >\n}\n\nexport type FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendContext,\n TClientContext,\n> = (\n options: FunctionMiddlewareClientFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator\n >,\n) => FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext\n>\n\nexport interface FunctionMiddlewareClientFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n> {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares>>\n method: Method\n signal: AbortSignal\n serverFnMeta: ClientFnMeta\n next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>\n filename: string\n fetch?: CustomFetch\n}\n\nexport type FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext,\n> =\n | Promise<\n FunctionClientResultWithContext<\n TMiddlewares,\n TSendContext,\n TClientContext\n >\n >\n | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>\n\nexport type FunctionClientResultWithContext<\n in out TMiddlewares,\n in out TSendContext,\n in out TClientContext,\n> = {\n 'use functions must return the result of next()': true\n context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>\n headers: HeadersInit\n fetch?: CustomFetch\n}\n\nexport interface FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n TServerSendContext,\n TClientContext,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext\n > {}\n\nexport interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {\n inputValidator: <TNewValidator>(\n inputValidator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n}\n\nexport interface FunctionMiddlewareAfterValidator<\n TRegister,\n TMiddlewares,\n TInputValidator,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {}\n\nexport interface RequestMiddleware<\n TRegister,\n> extends RequestMiddlewareAfterMiddleware<TRegister, undefined> {\n middleware: <const TMiddlewares = undefined>(\n middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>,\n ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n}\n\nexport type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any>\n\nexport interface RequestMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext>\n options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext>\n}\n\nexport interface RequestMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TServerContext,\n> {\n middleware?: TMiddlewares\n server?: RequestServerFn<TRegister, TMiddlewares, TServerContext>\n}\nexport interface RequestMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n type: 'request'\n // this only exists so we can use request middlewares in server functions\n allInput: undefined\n // this only exists so we can use request middlewares in server functions\n allOutput: undefined\n middlewares: TMiddlewares\n serverContext: TServerContext\n allServerContext: AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n}\n\nexport interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>,\n RequestMiddlewareServer<TRegister, TMiddlewares> {}\n\nexport interface RequestMiddlewareServer<TRegister, TMiddlewares> {\n server: <TServerContext = undefined>(\n fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>,\n ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext>\n}\n\nexport type RequestServerFn<TRegister, TMiddlewares, TServerContext> = (\n options: RequestServerOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerOptions<TRegister, TMiddlewares> {\n request: Request\n pathname: string\n context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>\n next: RequestServerNextFn<TRegister, TMiddlewares>\n /**\n * Type of Start handler currently processing this request.\n */\n handlerType: 'serverFn' | 'router'\n /**\n * Metadata about the server function being invoked.\n * This is only present when the request is handling a server function call.\n * For regular page requests, this will be undefined.\n */\n serverFnMeta?: ServerFnMeta\n}\n\nexport type RequestServerNextFn<TRegister, TMiddlewares> = <\n TServerContext = undefined,\n>(\n options?: RequestServerNextFnOptions<TServerContext>,\n) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerNextFnOptions<TServerContext> {\n context?: TServerContext\n}\n\nexport type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> =\n | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>>\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n\nexport type RequestMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerContext,\n> =\n | Promise<\n RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response\n >\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n | Response\n\nexport interface RequestServerResult<TRegister, TMiddlewares, TServerContext> {\n request: Request\n pathname: string\n context: Expand<\n AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n >\n response: Response\n}\n\nexport interface RequestMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TServerContext,\n> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}\n"],"mappings":";AAiCA,IAAa,oBAA4C,SAAS,WAAW;CAC3E,MAAM,kBAAkB;EACtB,MAAM;EACN,GAAI,UAAU;CAChB;CAEA,OAAO;EACL,SAAS;EACT,aAAa,eAAoB;GAC/B,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,WAAW,CAAC,CAC/C;EACF;EACA,iBAAiB,mBAAwB;GACvC,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,eAAe,CAAC,CACnD;EACF;EACA,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;EACA,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"createMiddleware.js","names":[],"sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type {\n AnyServerFn,\n ConstrainValidator,\n CustomFetch,\n Method,\n} from './createServerFn'\nimport type { ClientFnMeta, ServerFnMeta } from './constants'\nimport type {\n AnyContext,\n Assign,\n Constrain,\n Expand,\n IntersectAssign,\n Register,\n ResolveValidatorInput,\n ResolveValidatorOutput,\n ValidateSerializableInput,\n} from '@tanstack/router-core'\n\nexport type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(\n options?: {\n type?: TType\n },\n __opts?: FunctionMiddlewareOptions<\n TRegister,\n unknown,\n undefined,\n undefined,\n undefined\n >,\n) => CreateMiddlewareResult<TRegister, TType>\n\nexport const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {\n const resolvedOptions = {\n type: 'request',\n ...(__opts || options),\n }\n const setValidator = (validator: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, {\n validator,\n // TODO remove upon stable\n inputValidator: validator,\n }),\n )\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, { middleware }),\n )\n },\n validator: setValidator,\n // TODO remove upon stable\n inputValidator: setValidator,\n client: (client: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { client }))\n },\n server: (server: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { server }))\n },\n } as any\n}\n\nexport type MiddlewareType = 'request' | 'function'\n\nexport type CreateMiddlewareResult<\n TRegister,\n TType extends MiddlewareType,\n> = 'request' extends TType\n ? RequestMiddleware<TRegister>\n : FunctionMiddleware<TRegister>\n\nexport interface FunctionMiddleware<\n TRegister,\n> extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware>\n >,\n ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares>\n}\n\nexport interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>,\n FunctionMiddlewareValidator<TRegister, TMiddlewares> {}\n\nexport interface FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> {\n '~types': FunctionMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n >\n options: FunctionMiddlewareOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n}\n\nexport interface FunctionMiddlewareTypes<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TServerSendContext,\n in out TClientContext,\n in out TClientSendContext,\n> {\n type: 'function'\n middlewares: TMiddlewares\n input: ResolveValidatorInput<TInputValidator>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n output: ResolveValidatorOutput<TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n clientContext: TClientContext\n allClientContextBeforeNext: AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext\n >\n allClientContextAfterNext: AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext,\n TClientSendContext\n >\n serverContext: TServerContext\n serverSendContext: TServerSendContext\n allServerSendContext: AssignAllServerSendContext<\n TMiddlewares,\n TServerSendContext\n >\n allServerContext: AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n clientSendContext: TClientSendContext\n allClientSendContext: AssignAllClientSendContext<\n TMiddlewares,\n TClientSendContext\n >\n validator: TInputValidator\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator: TInputValidator\n}\n\n/**\n * Recursively resolve the input type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allInput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allInput'>,\n ResolveValidatorInput<TInputValidator>\n >\n\nexport type IntersectAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? IntersectAllMiddleware<\n TRest,\n TType,\n IntersectAssign<\n TAcc,\n TMiddleware['~types'][TType & keyof TMiddleware['~types']]\n >\n >\n : TAcc\n : TAcc\n\nexport type AnyFunctionMiddleware = FunctionMiddlewareWithTypes<\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n\n/**\n * Recursively merge the output type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allOutput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allOutput'>,\n Awaited<ResolveValidatorOutput<TInputValidator>>\n >\n\n/**\n * Recursively resolve the client context type produced by a sequence of middleware\n */\nexport type AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext = undefined,\n> = unknown extends TClientContext\n ? TClientContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>,\n TClientContext\n >\n\nexport type AssignAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? AssignAllMiddleware<\n TRest,\n TType,\n Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]>\n >\n : TAcc\n : TAcc\n\nexport type AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext = undefined,\n TSendContext = undefined,\n> = unknown extends TClientContext\n ? Assign<TClientContext, TSendContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>,\n Assign<TClientContext, TSendContext>\n >\n\nexport type AssignAllServerSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>,\n TSendContext\n >\n\nexport type AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n // Fetch Request Context\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>,\n __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext>\n >\n>\n\n// export type GlobalFetchRequestContext<TRegister> = AnyContext\nexport type GlobalFetchRequestContext = Register extends {\n server: { requestContext: infer TRequestContext }\n}\n ? TRequestContext\n : AnyContext\n\nexport type GlobalServerRequestContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any>\n}\n ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerRequestContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,\n Assign<\n GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,/\n __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext>\n >\n >\n>\n\ntype GlobalServerFnContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares>\n}\n ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerFnContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllClientSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>,\n TSendContext\n >\n\nexport interface FunctionMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TClientContext,\n> {\n middleware?: TMiddlewares\n validator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n client?: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n server?: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n unknown,\n unknown\n >\n}\n\nexport type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <\n TSendContext = undefined,\n TNewClientContext = undefined,\n>(ctx?: {\n context?: TNewClientContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n headers?: HeadersInit\n fetch?: CustomFetch\n}) => Promise<\n FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>\n>\n\nexport interface FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n> {\n server: <TNewServerContext = undefined, TSendContext = undefined>(\n server: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >,\n ) => FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TNewServerContext,\n TServerSendContext,\n TClientContext,\n TSendContext\n >\n}\n\nexport type FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext,\n> = (\n options: FunctionMiddlewareServerFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext\n >,\n) => FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n>\n\nexport type FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n> = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: {\n context?: TNewServerContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n}) => Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >\n>\n\nexport type FunctionServerResultWithContext<\n in out TRegister,\n in out TMiddlewares,\n in out TServerSendContext,\n in out TServerContext,\n in out TSendContext,\n> = {\n 'use functions must return the result of next()': true\n '~types': {\n context: TServerContext\n sendContext: TSendContext\n }\n context: Expand<\n AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n >\n sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>>\n}\n\nexport interface FunctionMiddlewareServerFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerSendContext,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<\n AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext>\n >\n next: FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext\n >\n method: Method\n serverFnMeta: ServerFnMeta\n signal: AbortSignal\n}\n\nexport type FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext,\n> =\n | Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n >\n | FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n\nexport interface FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> extends FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n> {}\n\nexport interface FunctionMiddlewareClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n> {\n client: <TSendServerContext = undefined, TNewClientContext = undefined>(\n client: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >,\n ) => FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >\n}\n\nexport type FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendContext,\n TClientContext,\n> = (\n options: FunctionMiddlewareClientFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator\n >,\n) => FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext\n>\n\nexport interface FunctionMiddlewareClientFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n> {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares>>\n method: Method\n signal: AbortSignal\n serverFnMeta: ClientFnMeta\n next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>\n filename: string\n fetch?: CustomFetch\n}\n\nexport type FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext,\n> =\n | Promise<\n FunctionClientResultWithContext<\n TMiddlewares,\n TSendContext,\n TClientContext\n >\n >\n | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>\n\nexport type FunctionClientResultWithContext<\n in out TMiddlewares,\n in out TSendContext,\n in out TClientContext,\n> = {\n 'use functions must return the result of next()': true\n context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>\n headers: HeadersInit\n fetch?: CustomFetch\n}\n\nexport interface FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n TServerSendContext,\n TClientContext,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext\n > {}\n\nexport interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {\n validator: <TNewValidator>(\n validator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator: <TNewValidator>(\n validator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n}\n\nexport interface FunctionMiddlewareAfterValidator<\n TRegister,\n TMiddlewares,\n TInputValidator,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {}\n\nexport interface RequestMiddleware<\n TRegister,\n> extends RequestMiddlewareAfterMiddleware<TRegister, undefined> {\n middleware: <const TMiddlewares = undefined>(\n middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>,\n ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n}\n\nexport type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any>\n\nexport interface RequestMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext>\n options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext>\n}\n\nexport interface RequestMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TServerContext,\n> {\n middleware?: TMiddlewares\n server?: RequestServerFn<TRegister, TMiddlewares, TServerContext>\n}\nexport interface RequestMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n type: 'request'\n // this only exists so we can use request middlewares in server functions\n allInput: undefined\n // this only exists so we can use request middlewares in server functions\n allOutput: undefined\n middlewares: TMiddlewares\n serverContext: TServerContext\n allServerContext: AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n}\n\nexport interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>,\n RequestMiddlewareServer<TRegister, TMiddlewares> {}\n\nexport interface RequestMiddlewareServer<TRegister, TMiddlewares> {\n server: <TServerContext = undefined>(\n fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>,\n ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext>\n}\n\nexport type RequestServerFn<TRegister, TMiddlewares, TServerContext> = (\n options: RequestServerOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerOptions<TRegister, TMiddlewares> {\n request: Request\n pathname: string\n context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>\n next: RequestServerNextFn<TRegister, TMiddlewares>\n /**\n * Type of Start handler currently processing this request.\n */\n handlerType: 'serverFn' | 'router'\n /**\n * Metadata about the server function being invoked.\n * This is only present when the request is handling a server function call.\n * For regular page requests, this will be undefined.\n */\n serverFnMeta?: ServerFnMeta\n}\n\nexport type RequestServerNextFn<TRegister, TMiddlewares> = <\n TServerContext = undefined,\n>(\n options?: RequestServerNextFnOptions<TServerContext>,\n) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerNextFnOptions<TServerContext> {\n context?: TServerContext\n}\n\nexport type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> =\n | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>>\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n\nexport type RequestMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerContext,\n> =\n | Promise<\n RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response\n >\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n | Response\n\nexport interface RequestServerResult<TRegister, TMiddlewares, TServerContext> {\n request: Request\n pathname: string\n context: Expand<\n AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n >\n response: Response\n}\n\nexport interface RequestMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TServerContext,\n> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}\n"],"mappings":";AAiCA,IAAa,oBAA4C,SAAS,WAAW;CAC3E,MAAM,kBAAkB;EACtB,MAAM;EACN,GAAI,UAAU;CAChB;CACA,MAAM,gBAAgB,cAAmB;EACvC,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB;GAC7B;GAEA,gBAAgB;EAClB,CAAC,CACH;CACF;CAEA,OAAO;EACL,SAAS;EACT,aAAa,eAAoB;GAC/B,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,WAAW,CAAC,CAC/C;EACF;EACA,WAAW;EAEX,gBAAgB;EAChB,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;EACA,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;CACF;AACF"}
|
|
@@ -77,6 +77,8 @@ export type ServerFnBaseOptions<TRegister, TMethod extends Method = 'GET', TResp
|
|
|
77
77
|
method: TMethod;
|
|
78
78
|
strict?: TStrict;
|
|
79
79
|
middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>>;
|
|
80
|
+
validator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>;
|
|
81
|
+
/** @deprecated Use `validator` instead. */
|
|
80
82
|
inputValidator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>;
|
|
81
83
|
extractedFn?: CompiledFetcherFn<TRegister, TResponse>;
|
|
82
84
|
serverFn?: ServerFn<TRegister, TMethod, TMiddlewares, TInputValidator, TResponse, TStrict>;
|
|
@@ -91,8 +93,10 @@ export interface ServerFnMiddleware<TRegister, TMethod extends Method, TMiddlewa
|
|
|
91
93
|
export interface ServerFnAfterMiddleware<TRegister, TMethod extends Method, TMiddlewares, TInputValidator, TStrict extends ServerFnStrict> extends ServerFnWithTypes<TRegister, TMethod, TMiddlewares, TInputValidator, undefined, TStrict>, ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined, TStrict>, ServerFnValidator<TRegister, TMethod, TMiddlewares, TStrict>, ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict> {
|
|
92
94
|
<TNewMethod extends Method = TMethod, TNewStrict extends ServerFnStrict = TStrict>(options?: ServerFnOptions<TNewMethod, TNewStrict>): ServerFnAfterMiddleware<TRegister, TNewMethod, TMiddlewares, TInputValidator, TNewStrict>;
|
|
93
95
|
}
|
|
94
|
-
export type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares, TStrict extends ServerFnStrict> = <TInputValidator>(
|
|
96
|
+
export type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares, TStrict extends ServerFnStrict> = <TInputValidator>(validator: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>) => ServerFnAfterValidator<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict>;
|
|
95
97
|
export interface ServerFnValidator<TRegister, TMethod extends Method, TMiddlewares, TStrict extends ServerFnStrict> {
|
|
98
|
+
validator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>;
|
|
99
|
+
/** @deprecated Use `validator` instead. */
|
|
96
100
|
inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>;
|
|
97
101
|
}
|
|
98
102
|
export interface ServerFnAfterValidator<TRegister, TMethod extends Method, TMiddlewares, TInputValidator, TStrict extends ServerFnStrict> extends ServerFnWithTypes<TRegister, TMethod, TMiddlewares, TInputValidator, undefined, TStrict>, ServerFnMiddleware<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict>, ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict> {
|
|
@@ -116,6 +120,8 @@ export interface ServerFnTypes<in out TRegister, in out TMethod extends Method,
|
|
|
116
120
|
method: TMethod;
|
|
117
121
|
strict: TStrict;
|
|
118
122
|
middlewares: TMiddlewares;
|
|
123
|
+
validator: TInputValidator;
|
|
124
|
+
/** @deprecated Use `validator` instead. */
|
|
119
125
|
inputValidator: TInputValidator;
|
|
120
126
|
response: TResponse;
|
|
121
127
|
allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>;
|
|
@@ -8,6 +8,13 @@ import { isRedirect, parseRedirect } from "@tanstack/router-core";
|
|
|
8
8
|
var createServerFn = (options, __opts) => {
|
|
9
9
|
const resolvedOptions = __opts || options || {};
|
|
10
10
|
if (typeof resolvedOptions.method === "undefined") resolvedOptions.method = "GET";
|
|
11
|
+
const setValidator = (validator) => {
|
|
12
|
+
return createServerFn(void 0, {
|
|
13
|
+
...resolvedOptions,
|
|
14
|
+
validator,
|
|
15
|
+
inputValidator: validator
|
|
16
|
+
});
|
|
17
|
+
};
|
|
11
18
|
const res = {
|
|
12
19
|
options: resolvedOptions,
|
|
13
20
|
middleware: (middleware) => {
|
|
@@ -24,12 +31,8 @@ var createServerFn = (options, __opts) => {
|
|
|
24
31
|
res[TSS_SERVER_FUNCTION_FACTORY] = true;
|
|
25
32
|
return res;
|
|
26
33
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
...resolvedOptions,
|
|
30
|
-
inputValidator
|
|
31
|
-
});
|
|
32
|
-
},
|
|
34
|
+
validator: setValidator,
|
|
35
|
+
inputValidator: setValidator,
|
|
33
36
|
handler: (...args) => {
|
|
34
37
|
const [extractedFn, serverFn] = args;
|
|
35
38
|
const newOptions = {
|
|
@@ -92,7 +95,9 @@ async function executeMiddleware(middlewares, env, opts) {
|
|
|
92
95
|
const nextMiddleware = flattenedMiddlewares.shift();
|
|
93
96
|
if (!nextMiddleware) return ctx;
|
|
94
97
|
try {
|
|
95
|
-
|
|
98
|
+
let validator = "validator" in nextMiddleware.options ? nextMiddleware.options.validator : void 0;
|
|
99
|
+
if (!validator && "inputValidator" in nextMiddleware.options) validator = nextMiddleware.options.inputValidator;
|
|
100
|
+
if (validator && env === "server") ctx.data = await execValidator(validator, ctx.data);
|
|
96
101
|
let middlewareFn = void 0;
|
|
97
102
|
if (env === "client") {
|
|
98
103
|
if ("client" in nextMiddleware.options) middlewareFn = nextMiddleware.options.client;
|
|
@@ -175,7 +180,7 @@ function serverFnBaseToMiddleware(options) {
|
|
|
175
180
|
return {
|
|
176
181
|
"~types": void 0,
|
|
177
182
|
options: {
|
|
178
|
-
inputValidator: options.inputValidator,
|
|
183
|
+
inputValidator: options.validator ?? options.inputValidator,
|
|
179
184
|
client: async ({ next, sendContext, fetch, ...ctx }) => {
|
|
180
185
|
const payload = {
|
|
181
186
|
...ctx,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerFn.js","names":[],"sources":["../../src/createServerFn.ts"],"sourcesContent":["import { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { isRedirect, parseRedirect } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getStartOptions } from './getStartOptions'\nimport { getStartContextServerOnly } from './getStartContextServerOnly'\nimport { createNullProtoObject, safeObjectMerge } from './safeObjectMerge'\nimport type {\n ClientFnMeta,\n ServerFnMeta,\n TSS_SERVER_FUNCTION,\n} from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n Validator,\n} from '@tanstack/router-core'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AssignAllServerFnContext,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\nexport type ServerFnStrict = boolean | { input?: boolean; output?: boolean }\n\nexport interface ServerFnOptions<\n TMethod extends Method = Method,\n TStrict extends ServerFnStrict = true,\n> {\n method?: TMethod\n strict?: TStrict\n}\n\nexport type ServerFnStrictInput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { input: infer TInput extends boolean }\n ? TInput\n : true\n\nexport type ServerFnStrictOutput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { output: infer TOutput extends boolean }\n ? TOutput\n : true\n\nexport type CreateServerFn<TRegister> = <\n TMethod extends Method,\n TStrict extends ServerFnStrict = true,\n TResponse = unknown,\n TMiddlewares = undefined,\n TInputValidator = undefined,\n>(\n options?: ServerFnOptions<TMethod, TStrict>,\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TResponse,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n) => ServerFnBuilder<TRegister, TMethod, TStrict>\n\nexport const createServerFn: CreateServerFn<Register> = (options, __opts) => {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n any,\n any,\n any,\n any,\n any,\n any\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as Method\n }\n\n const res: ServerFnBuilder<Register, Method, ServerFnStrict> = {\n options: resolvedOptions,\n middleware: (middleware) => {\n // multiple calls to `middleware()` merge the middlewares with the previously supplied ones\n // this is primarily useful for letting users create their own abstractions on top of `createServerFn`\n\n const newMiddleware = [...(resolvedOptions.middleware || [])]\n middleware.map((m) => {\n if (TSS_SERVER_FUNCTION_FACTORY in m) {\n if (m.options.middleware) {\n newMiddleware.push(...m.options.middleware)\n }\n } else {\n newMiddleware.push(m)\n }\n })\n\n const newOptions = {\n ...resolvedOptions,\n middleware: newMiddleware,\n }\n const res = createServerFn(undefined, newOptions)\n res[TSS_SERVER_FUNCTION_FACTORY] = true\n return res\n },\n inputValidator: (inputValidator) => {\n const newOptions = { ...resolvedOptions, inputValidator }\n return createServerFn(undefined, newOptions) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<Register, any>,\n ServerFn<Register, Method, any, any, any>,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n const newOptions = { ...resolvedOptions, extractedFn, serverFn }\n\n const resolvedMiddleware = [\n ...(newOptions.middleware || []),\n serverFnBaseToMiddleware(newOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n // Propagate the declared HTTP method onto the extracted handler\n // so the manifest-exported symbol (resolved by getServerFnById)\n // carries `method`, enabling the server handler to reject\n // mismatched HTTP methods before parsing request payloads.\n ;(extractedFn as any).method = resolvedOptions.method\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n const result = await executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data,\n headers: opts?.headers,\n signal: opts?.signal,\n fetch: opts?.fetch,\n context: createNullProtoObject(),\n })\n\n const redirect = parseRedirect(result.error)\n if (redirect) {\n throw redirect\n }\n\n if (result.error) throw result.error\n return result.result\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // Expose the declared HTTP method so the server handler\n // can reject mismatched methods before parsing payloads\n method: resolvedOptions.method,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any) => {\n const startContext = getStartContextServerOnly()\n const serverContextAfterGlobalMiddlewares =\n startContext.contextAfterGlobalMiddlewares\n const ctx = {\n ...extractedFn,\n ...opts,\n // Ensure we use the full serverFnMeta from the provider file's extractedFn\n // (which has id, name, filename) rather than the partial one from SSR/client\n // callers (which only has id)\n serverFnMeta: extractedFn.serverFnMeta,\n // Merge client context first so trusted server middleware context wins.\n context: safeObjectMerge(\n opts.context,\n serverContextAfterGlobalMiddlewares,\n ),\n request: startContext.request,\n }\n\n const result = await executeMiddleware(\n resolvedMiddleware,\n 'server',\n ctx,\n ).then((d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }))\n\n return result\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method, ServerFnStrict>\n const fun = (options?: ServerFnOptions<Method, ServerFnStrict>) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions)\n }\n return Object.assign(fun, res) as any\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const globalMiddlewares = getStartOptions()?.functionMiddleware || []\n let flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n // On server, filter out middlewares that already executed in the request phase\n // to prevent duplicate execution (issue #5239)\n if (env === 'server') {\n const startContext = getStartContextServerOnly({ throwIfNotFound: false })\n if (startContext?.executedRequestMiddlewares) {\n flattenedMiddlewares = flattenedMiddlewares.filter(\n (m) => !startContext.executedRequestMiddlewares.has(m),\n )\n }\n }\n\n const callNextMiddleware: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n // Execute the middleware\n try {\n if (\n 'inputValidator' in nextMiddleware.options &&\n nextMiddleware.options.inputValidator &&\n env === 'server'\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(\n nextMiddleware.options.inputValidator,\n ctx.data,\n )\n }\n\n let middlewareFn: MiddlewareFn | undefined = undefined\n if (env === 'client') {\n if ('client' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.client as\n | MiddlewareFn\n | undefined\n }\n }\n // env === 'server'\n else if ('server' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined\n }\n\n if (middlewareFn) {\n const userNext = async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n // Use safeObjectMerge for context objects to prevent prototype pollution\n const nextCtx = {\n ...ctx,\n ...userCtx,\n context: safeObjectMerge(ctx.context, userCtx.context),\n sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n _callSiteFetch: ctx._callSiteFetch,\n fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n }\n\n const result = await callNextMiddleware(nextCtx)\n\n if (result.error) {\n throw result.error\n }\n\n return result\n }\n\n // Execute the middleware\n const result = await middlewareFn({\n ...ctx,\n next: userNext,\n })\n\n // If result is NOT a ctx object, we need to return it as\n // the { result }\n if (isRedirect(result)) {\n return {\n ...ctx,\n error: result,\n }\n }\n\n if (result instanceof Response) {\n return {\n ...ctx,\n result,\n }\n }\n\n if (!(result as any)) {\n throw new Error(\n 'User middleware returned undefined. You must call next() or return a result in your middlewares.',\n )\n }\n\n return result\n }\n\n return callNextMiddleware(ctx)\n } catch (error: any) {\n return {\n ...ctx,\n error,\n }\n }\n }\n\n // Start the middleware chain\n return callNextMiddleware({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || createNullProtoObject(),\n _callSiteFetch: opts.fetch,\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n context?: any\n}\n\nexport type Fetcher<TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n\nexport interface FetcherBase {\n [TSS_SERVER_FUNCTION]: true\n url: string\n method: Method\n __executeServer: (opts: {\n method: Method\n data: unknown\n headers?: HeadersInit\n context?: any\n }) => Promise<unknown>\n}\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\n// Ideally, this type should just be `export type CustomFetch = typeof globalThis.fetch`, but that conflicts with the type overrides the `bun-types` package - a dependency of unplugin.\n// Relevant bun issues:\n// - https://github.com/oven-sh/bun/issues/23500\n// - https://github.com/oven-sh/bun/issues/23741\nexport type CustomFetch = typeof fetch extends (...args: infer A) => infer R\n ? (...args: A) => R\n : never\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n}\n\nexport interface OptionalFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<\n TRegister,\n TResponse,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictOutput<TStrict> extends false\n ? TResponse\n : TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U, TStrict>>\n : TResponse extends Response\n ? TResponse\n : ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict extends ServerFnStrict = true,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse, TStrict>\n\nexport interface ServerFnCtx<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n serverFnMeta: ServerFnMeta\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n method: TMethod\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\n serverFnMeta: ServerFnMeta\n}\n\nexport type ServerFnBaseOptions<\n TRegister,\n TMethod extends Method = 'GET',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInputValidator = unknown,\n TStrict extends ServerFnStrict = true,\n> = {\n method: TMethod\n strict?: TStrict\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n inputValidator?: ConstrainValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictInput<TStrict> extends false\n ? ResolveValidatorInput<TInputValidator>\n : TMethod extends 'POST'\n ? ResolveValidatorInput<TInputValidator> extends FormData\n ? ResolveValidatorInput<TInputValidator>\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n\nexport type ValidateValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator, TStrict>\n\nexport type AppendMiddlewares<TMiddlewares, TNewMiddlewares> =\n TMiddlewares extends ReadonlyArray<any>\n ? TNewMiddlewares extends ReadonlyArray<any>\n ? readonly [...TMiddlewares, ...TNewMiddlewares]\n : TMiddlewares\n : TNewMiddlewares\n\nexport interface ServerFnMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n> {\n middleware: <const TNewMiddlewares>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n AppendMiddlewares<TMiddlewares, TNewMiddlewares>,\n TInputValidator,\n TStrict\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares, TStrict>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator,\n TNewStrict\n >\n}\n\nexport type ValidatorFn<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> = <TInputValidator>(\n inputValidator: ConstrainValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >,\n) => ServerFnAfterValidator<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> {\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse,\n TStrict\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<\n TRegister,\n TMethod extends Method = 'GET',\n TStrict extends ServerFnStrict = true,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n undefined,\n undefined,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, undefined, TStrict>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined, TStrict> {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnBuilder<TRegister, TNewMethod, TNewStrict>\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\n >\n}\n\nexport interface ServerFnWithTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n in out TStrict extends ServerFnStrict,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, any, any, any, any, any>\n\nexport interface ServerFnTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n in out TStrict extends ServerFnStrict,\n> {\n method: TMethod\n strict: TStrict\n middlewares: TMiddlewares\n inputValidator: TInputValidator\n response: TResponse\n allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n}\n\nexport function flattenMiddlewares<\n T extends AnyFunctionMiddleware | AnyRequestMiddleware,\n>(middlewares: Array<T>, maxDepth: number = 100): Array<T> {\n const seen = new Set<T>()\n const flattened: Array<T> = []\n\n const recurse = (middleware: Array<T>, depth: number) => {\n if (depth > maxDepth) {\n throw new Error(\n `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`,\n )\n }\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware as Array<T>, depth + 1)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares, 0)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n serverFnMeta: ClientFnMeta\n fetch?: CustomFetch\n /** @internal - Preserves the call-site fetch to ensure it has highest priority over middleware */\n _callSiteFetch?: CustomFetch\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport async function execValidator(\n validator: AnyValidator,\n input: unknown,\n): Promise<unknown> {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = await validator['~standard'].validate(input)\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nfunction serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n '~types': undefined!,\n options: {\n inputValidator: options.inputValidator,\n client: async ({ next, sendContext, fetch, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n fetch,\n }\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res)\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx)\n\n return next({\n ...ctx,\n result,\n } as any)\n },\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createServerFn.js","names":[],"sources":["../../src/createServerFn.ts"],"sourcesContent":["import { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { isRedirect, parseRedirect } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getStartOptions } from './getStartOptions'\nimport { getStartContextServerOnly } from './getStartContextServerOnly'\nimport { createNullProtoObject, safeObjectMerge } from './safeObjectMerge'\nimport type {\n ClientFnMeta,\n ServerFnMeta,\n TSS_SERVER_FUNCTION,\n} from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n Validator,\n} from '@tanstack/router-core'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AssignAllServerFnContext,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\nexport type ServerFnStrict = boolean | { input?: boolean; output?: boolean }\n\nexport interface ServerFnOptions<\n TMethod extends Method = Method,\n TStrict extends ServerFnStrict = true,\n> {\n method?: TMethod\n strict?: TStrict\n}\n\nexport type ServerFnStrictInput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { input: infer TInput extends boolean }\n ? TInput\n : true\n\nexport type ServerFnStrictOutput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { output: infer TOutput extends boolean }\n ? TOutput\n : true\n\nexport type CreateServerFn<TRegister> = <\n TMethod extends Method,\n TStrict extends ServerFnStrict = true,\n TResponse = unknown,\n TMiddlewares = undefined,\n TInputValidator = undefined,\n>(\n options?: ServerFnOptions<TMethod, TStrict>,\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TResponse,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n) => ServerFnBuilder<TRegister, TMethod, TStrict>\n\nexport const createServerFn: CreateServerFn<Register> = (options, __opts) => {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n any,\n any,\n any,\n any,\n any,\n any\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as Method\n }\n\n const setValidator = (validator: any) => {\n // TODO remove upon stable\n const newOptions = {\n ...resolvedOptions,\n validator,\n inputValidator: validator,\n }\n return createServerFn(undefined, newOptions) as any\n }\n\n const res: ServerFnBuilder<Register, Method, ServerFnStrict> = {\n options: resolvedOptions,\n middleware: (middleware) => {\n // multiple calls to `middleware()` merge the middlewares with the previously supplied ones\n // this is primarily useful for letting users create their own abstractions on top of `createServerFn`\n\n const newMiddleware = [...(resolvedOptions.middleware || [])]\n middleware.map((m) => {\n if (TSS_SERVER_FUNCTION_FACTORY in m) {\n if (m.options.middleware) {\n newMiddleware.push(...m.options.middleware)\n }\n } else {\n newMiddleware.push(m)\n }\n })\n\n const newOptions = {\n ...resolvedOptions,\n middleware: newMiddleware,\n }\n const res = createServerFn(undefined, newOptions)\n res[TSS_SERVER_FUNCTION_FACTORY] = true\n return res\n },\n validator: setValidator,\n // TODO remove upon stable\n inputValidator: setValidator,\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<Register, any>,\n ServerFn<Register, Method, any, any, any>,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n const newOptions = { ...resolvedOptions, extractedFn, serverFn }\n\n const resolvedMiddleware = [\n ...(newOptions.middleware || []),\n serverFnBaseToMiddleware(newOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n // Propagate the declared HTTP method onto the extracted handler\n // so the manifest-exported symbol (resolved by getServerFnById)\n // carries `method`, enabling the server handler to reject\n // mismatched HTTP methods before parsing request payloads.\n ;(extractedFn as any).method = resolvedOptions.method\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n const result = await executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data,\n headers: opts?.headers,\n signal: opts?.signal,\n fetch: opts?.fetch,\n context: createNullProtoObject(),\n })\n\n const redirect = parseRedirect(result.error)\n if (redirect) {\n throw redirect\n }\n\n if (result.error) throw result.error\n return result.result\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // Expose the declared HTTP method so the server handler\n // can reject mismatched methods before parsing payloads\n method: resolvedOptions.method,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any) => {\n const startContext = getStartContextServerOnly()\n const serverContextAfterGlobalMiddlewares =\n startContext.contextAfterGlobalMiddlewares\n const ctx = {\n ...extractedFn,\n ...opts,\n // Ensure we use the full serverFnMeta from the provider file's extractedFn\n // (which has id, name, filename) rather than the partial one from SSR/client\n // callers (which only has id)\n serverFnMeta: extractedFn.serverFnMeta,\n // Merge client context first so trusted server middleware context wins.\n context: safeObjectMerge(\n opts.context,\n serverContextAfterGlobalMiddlewares,\n ),\n request: startContext.request,\n }\n\n const result = await executeMiddleware(\n resolvedMiddleware,\n 'server',\n ctx,\n ).then((d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }))\n\n return result\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method, ServerFnStrict>\n const fun = (options?: ServerFnOptions<Method, ServerFnStrict>) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions)\n }\n return Object.assign(fun, res) as any\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const globalMiddlewares = getStartOptions()?.functionMiddleware || []\n let flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n // On server, filter out middlewares that already executed in the request phase\n // to prevent duplicate execution (issue #5239)\n if (env === 'server') {\n const startContext = getStartContextServerOnly({ throwIfNotFound: false })\n if (startContext?.executedRequestMiddlewares) {\n flattenedMiddlewares = flattenedMiddlewares.filter(\n (m) => !startContext.executedRequestMiddlewares.has(m),\n )\n }\n }\n\n const callNextMiddleware: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n // Execute the middleware\n try {\n let validator =\n 'validator' in nextMiddleware.options\n ? nextMiddleware.options.validator\n : undefined\n\n // TODO remove upon stable\n if (!validator && 'inputValidator' in nextMiddleware.options) {\n validator = nextMiddleware.options.inputValidator\n }\n\n if (validator && env === 'server') {\n // Execute the middleware's input function\n ctx.data = await execValidator(validator as AnyValidator, ctx.data)\n }\n\n let middlewareFn: MiddlewareFn | undefined = undefined\n if (env === 'client') {\n if ('client' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.client as\n | MiddlewareFn\n | undefined\n }\n }\n // env === 'server'\n else if ('server' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined\n }\n\n if (middlewareFn) {\n const userNext = async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n // Use safeObjectMerge for context objects to prevent prototype pollution\n const nextCtx = {\n ...ctx,\n ...userCtx,\n context: safeObjectMerge(ctx.context, userCtx.context),\n sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n _callSiteFetch: ctx._callSiteFetch,\n fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n }\n\n const result = await callNextMiddleware(nextCtx)\n\n if (result.error) {\n throw result.error\n }\n\n return result\n }\n\n // Execute the middleware\n const result = await middlewareFn({\n ...ctx,\n next: userNext,\n })\n\n // If result is NOT a ctx object, we need to return it as\n // the { result }\n if (isRedirect(result)) {\n return {\n ...ctx,\n error: result,\n }\n }\n\n if (result instanceof Response) {\n return {\n ...ctx,\n result,\n }\n }\n\n if (!(result as any)) {\n throw new Error(\n 'User middleware returned undefined. You must call next() or return a result in your middlewares.',\n )\n }\n\n return result\n }\n\n return callNextMiddleware(ctx)\n } catch (error: any) {\n return {\n ...ctx,\n error,\n }\n }\n }\n\n // Start the middleware chain\n return callNextMiddleware({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || createNullProtoObject(),\n _callSiteFetch: opts.fetch,\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n context?: any\n}\n\nexport type Fetcher<TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n\nexport interface FetcherBase {\n [TSS_SERVER_FUNCTION]: true\n url: string\n method: Method\n __executeServer: (opts: {\n method: Method\n data: unknown\n headers?: HeadersInit\n context?: any\n }) => Promise<unknown>\n}\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\n// Ideally, this type should just be `export type CustomFetch = typeof globalThis.fetch`, but that conflicts with the type overrides the `bun-types` package - a dependency of unplugin.\n// Relevant bun issues:\n// - https://github.com/oven-sh/bun/issues/23500\n// - https://github.com/oven-sh/bun/issues/23741\nexport type CustomFetch = typeof fetch extends (...args: infer A) => infer R\n ? (...args: A) => R\n : never\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n}\n\nexport interface OptionalFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<\n TRegister,\n TResponse,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictOutput<TStrict> extends false\n ? TResponse\n : TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U, TStrict>>\n : TResponse extends Response\n ? TResponse\n : ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict extends ServerFnStrict = true,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse, TStrict>\n\nexport interface ServerFnCtx<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n serverFnMeta: ServerFnMeta\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n method: TMethod\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\n serverFnMeta: ServerFnMeta\n}\n\nexport type ServerFnBaseOptions<\n TRegister,\n TMethod extends Method = 'GET',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInputValidator = unknown,\n TStrict extends ServerFnStrict = true,\n> = {\n method: TMethod\n strict?: TStrict\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n validator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator?: ConstrainValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictInput<TStrict> extends false\n ? ResolveValidatorInput<TInputValidator>\n : TMethod extends 'POST'\n ? ResolveValidatorInput<TInputValidator> extends FormData\n ? ResolveValidatorInput<TInputValidator>\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n\nexport type ValidateValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator, TStrict>\n\nexport type AppendMiddlewares<TMiddlewares, TNewMiddlewares> =\n TMiddlewares extends ReadonlyArray<any>\n ? TNewMiddlewares extends ReadonlyArray<any>\n ? readonly [...TMiddlewares, ...TNewMiddlewares]\n : TMiddlewares\n : TNewMiddlewares\n\nexport interface ServerFnMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n> {\n middleware: <const TNewMiddlewares>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n AppendMiddlewares<TMiddlewares, TNewMiddlewares>,\n TInputValidator,\n TStrict\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares, TStrict>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator,\n TNewStrict\n >\n}\n\nexport type ValidatorFn<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> = <TInputValidator>(\n validator: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>,\n) => ServerFnAfterValidator<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> {\n validator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse,\n TStrict\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<\n TRegister,\n TMethod extends Method = 'GET',\n TStrict extends ServerFnStrict = true,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n undefined,\n undefined,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, undefined, TStrict>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined, TStrict> {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnBuilder<TRegister, TNewMethod, TNewStrict>\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\n >\n}\n\nexport interface ServerFnWithTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n in out TStrict extends ServerFnStrict,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, any, any, any, any, any>\n\nexport interface ServerFnTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n in out TStrict extends ServerFnStrict,\n> {\n method: TMethod\n strict: TStrict\n middlewares: TMiddlewares\n validator: TInputValidator\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator: TInputValidator\n response: TResponse\n allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n}\n\nexport function flattenMiddlewares<\n T extends AnyFunctionMiddleware | AnyRequestMiddleware,\n>(middlewares: Array<T>, maxDepth: number = 100): Array<T> {\n const seen = new Set<T>()\n const flattened: Array<T> = []\n\n const recurse = (middleware: Array<T>, depth: number) => {\n if (depth > maxDepth) {\n throw new Error(\n `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`,\n )\n }\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware as Array<T>, depth + 1)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares, 0)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n serverFnMeta: ClientFnMeta\n fetch?: CustomFetch\n /** @internal - Preserves the call-site fetch to ensure it has highest priority over middleware */\n _callSiteFetch?: CustomFetch\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport async function execValidator(\n validator: AnyValidator,\n input: unknown,\n): Promise<unknown> {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = await validator['~standard'].validate(input)\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nfunction serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n // TODO remove upon stable\n const validator = options.validator ?? options.inputValidator\n\n return {\n '~types': undefined!,\n options: {\n // TODO remove upon stable\n inputValidator: validator,\n client: async ({ next, sendContext, fetch, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n fetch,\n }\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res)\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx)\n\n return next({\n ...ctx,\n result,\n } as any)\n },\n },\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/start-client-core",
|
|
3
|
-
"version": "1.170.
|
|
3
|
+
"version": "1.170.12",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -91,9 +91,9 @@
|
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"seroval": "^1.5.4",
|
|
94
|
-
"@tanstack/router-core": "1.171.
|
|
94
|
+
"@tanstack/router-core": "1.171.13",
|
|
95
95
|
"@tanstack/start-fn-stubs": "1.162.0",
|
|
96
|
-
"@tanstack/start-storage-context": "1.167.
|
|
96
|
+
"@tanstack/start-storage-context": "1.167.15"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"vite": "*",
|
|
@@ -31,7 +31,7 @@ This skill covers the **server half** of authentication: session storage, cookie
|
|
|
31
31
|
## Production Checklist
|
|
32
32
|
|
|
33
33
|
- Enforce auth in every server function, server route, or API endpoint that reads or writes private user, tenant, or account data. Use route `beforeLoad` for page UX, not as the data boundary.
|
|
34
|
-
- Use `.
|
|
34
|
+
- Use `.validator()` on every server function that accepts input.
|
|
35
35
|
- Store sessions in `HttpOnly`, `Secure`, `SameSite` cookies. Do not store session tokens in `localStorage` or `sessionStorage`.
|
|
36
36
|
- Hash passwords with bcrypt, scrypt, or Argon2. For missing users, verify against a dummy hash and return the same login/reset message.
|
|
37
37
|
- Rate limit login, registration, and password-reset endpoints.
|
|
@@ -139,7 +139,7 @@ import { z } from 'zod'
|
|
|
139
139
|
import { setSessionCookie } from './session'
|
|
140
140
|
|
|
141
141
|
export const login = createServerFn({ method: 'POST' })
|
|
142
|
-
.
|
|
142
|
+
.validator(z.object({ email: z.string().email(), password: z.string() }))
|
|
143
143
|
.handler(async ({ data }) => {
|
|
144
144
|
const user = await db.users.findByEmail(data.email)
|
|
145
145
|
// Always run verifyPasswordHash — even when the user doesn't exist —
|
|
@@ -237,7 +237,7 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
237
237
|
import { z } from 'zod'
|
|
238
238
|
|
|
239
239
|
export const requestPasswordReset = createServerFn({ method: 'POST' })
|
|
240
|
-
.
|
|
240
|
+
.validator(z.object({ email: z.string().email() }))
|
|
241
241
|
.handler(async ({ data }) => {
|
|
242
242
|
const user = await db.users.findByEmail(data.email)
|
|
243
243
|
if (user) {
|
|
@@ -369,7 +369,7 @@ A parsed UUID is _some_ workspace, not an _authorized_ workspace.
|
|
|
369
369
|
// WRONG — UUID is well-formed but the user may not be a member
|
|
370
370
|
const getWorkspaceData = createServerFn({ method: 'GET' })
|
|
371
371
|
.middleware([authMiddleware])
|
|
372
|
-
.
|
|
372
|
+
.validator(z.object({ workspaceId: z.string().uuid() }))
|
|
373
373
|
.handler(async ({ context, data }) => {
|
|
374
374
|
return db.workspaces.findById(data.workspaceId) // missing membership check!
|
|
375
375
|
})
|
|
@@ -377,7 +377,7 @@ const getWorkspaceData = createServerFn({ method: 'GET' })
|
|
|
377
377
|
// CORRECT — verify the session principal has access to that workspace
|
|
378
378
|
const getWorkspaceData = createServerFn({ method: 'GET' })
|
|
379
379
|
.middleware([authMiddleware])
|
|
380
|
-
.
|
|
380
|
+
.validator(z.object({ workspaceId: z.string().uuid() }))
|
|
381
381
|
.handler(async ({ context, data }) => {
|
|
382
382
|
const member = await db.memberships.find({
|
|
383
383
|
userId: context.session.userId,
|
|
@@ -20,7 +20,7 @@ sources:
|
|
|
20
20
|
|
|
21
21
|
Middleware customizes the behavior of server functions and server routes. It is composable — middleware can depend on other middleware to form a chain.
|
|
22
22
|
|
|
23
|
-
> **CRITICAL**: TypeScript enforces method order: `middleware()` → `
|
|
23
|
+
> **CRITICAL**: TypeScript enforces method order: `middleware()` → `validator()` → `client()` → `server()`. Wrong order causes type errors.
|
|
24
24
|
> **CRITICAL**: Validating the _shape_ of `sendContext` (e.g. `z.string().uuid().parse(...)`) is NOT authorization. A parsed identifier is a well-formed identifier, not an authorized one. Always re-check access against the session principal before using a client-sent ID as a query key, filter, or path parameter.
|
|
25
25
|
|
|
26
26
|
## Two Types of Middleware
|
|
@@ -29,7 +29,7 @@ Middleware customizes the behavior of server functions and server routes. It is
|
|
|
29
29
|
| ----------------- | -------------------------------------------- | ---------------------------------------- |
|
|
30
30
|
| Scope | All server requests (SSR, routes, functions) | Server functions only |
|
|
31
31
|
| Methods | `.server()` | `.client()`, `.server()` |
|
|
32
|
-
| Input validation | No | Yes (`.
|
|
32
|
+
| Input validation | No | Yes (`.validator()`) |
|
|
33
33
|
| Client-side logic | No | Yes |
|
|
34
34
|
| Created with | `createMiddleware()` | `createMiddleware({ type: 'function' })` |
|
|
35
35
|
|
|
@@ -160,7 +160,7 @@ import { z } from 'zod'
|
|
|
160
160
|
import { zodValidator } from '@tanstack/zod-adapter'
|
|
161
161
|
|
|
162
162
|
const workspaceMiddleware = createMiddleware({ type: 'function' })
|
|
163
|
-
.
|
|
163
|
+
.validator(zodValidator(z.object({ workspaceId: z.string() })))
|
|
164
164
|
.server(async ({ next, data }) => {
|
|
165
165
|
console.log('Workspace:', data.workspaceId)
|
|
166
166
|
return next()
|
|
@@ -382,10 +382,10 @@ createMiddleware({ type: 'function' })
|
|
|
382
382
|
.server(() => { ... })
|
|
383
383
|
.client(() => { ... })
|
|
384
384
|
|
|
385
|
-
// CORRECT — middleware →
|
|
385
|
+
// CORRECT — middleware → validator → client → server
|
|
386
386
|
createMiddleware({ type: 'function' })
|
|
387
387
|
.middleware([dep])
|
|
388
|
-
.
|
|
388
|
+
.validator(schema)
|
|
389
389
|
.client(({ next }) => next())
|
|
390
390
|
.server(({ next }) => next())
|
|
391
391
|
```
|
|
@@ -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
|
})
|
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 }) => {
|
|
@@ -10,17 +10,20 @@ test('createServeMiddleware removes middleware after middleware,', () => {
|
|
|
10
10
|
|
|
11
11
|
expectTypeOf(middleware).toHaveProperty('middleware')
|
|
12
12
|
expectTypeOf(middleware).toHaveProperty('server')
|
|
13
|
+
expectTypeOf(middleware).toHaveProperty('validator')
|
|
14
|
+
// TODO remove upon stable
|
|
13
15
|
expectTypeOf(middleware).toHaveProperty('inputValidator')
|
|
14
16
|
|
|
15
17
|
const middlewareAfterMiddleware = middleware.middleware([])
|
|
16
18
|
|
|
17
|
-
expectTypeOf(middlewareAfterMiddleware).toHaveProperty('
|
|
19
|
+
expectTypeOf(middlewareAfterMiddleware).toHaveProperty('validator')
|
|
18
20
|
expectTypeOf(middlewareAfterMiddleware).toHaveProperty('server')
|
|
19
21
|
expectTypeOf(middlewareAfterMiddleware).not.toHaveProperty('middleware')
|
|
20
22
|
|
|
21
|
-
const middlewareAfterInput = middleware.
|
|
23
|
+
const middlewareAfterInput = middleware.validator(() => {})
|
|
22
24
|
|
|
23
25
|
expectTypeOf(middlewareAfterInput).toHaveProperty('server')
|
|
26
|
+
expectTypeOf(middlewareAfterInput).not.toHaveProperty('validator')
|
|
24
27
|
expectTypeOf(middlewareAfterInput).not.toHaveProperty('middleware')
|
|
25
28
|
|
|
26
29
|
const middlewareAfterServer = middleware.server(async (options) => {
|
|
@@ -43,6 +46,7 @@ test('createServeMiddleware removes middleware after middleware,', () => {
|
|
|
43
46
|
|
|
44
47
|
expectTypeOf(middlewareAfterServer).not.toHaveProperty('server')
|
|
45
48
|
expectTypeOf(middlewareAfterServer).not.toHaveProperty('input')
|
|
49
|
+
expectTypeOf(middlewareAfterServer).not.toHaveProperty('validator')
|
|
46
50
|
expectTypeOf(middlewareAfterServer).not.toHaveProperty('middleware')
|
|
47
51
|
})
|
|
48
52
|
|
|
@@ -257,7 +261,7 @@ test('createMiddleware merges client context and sends to the server', () => {
|
|
|
257
261
|
|
|
258
262
|
test('createMiddleware merges input', () => {
|
|
259
263
|
const middleware1 = createMiddleware({ type: 'function' })
|
|
260
|
-
.
|
|
264
|
+
.validator(() => {
|
|
261
265
|
return {
|
|
262
266
|
a: 'a',
|
|
263
267
|
} as const
|
|
@@ -269,7 +273,7 @@ test('createMiddleware merges input', () => {
|
|
|
269
273
|
|
|
270
274
|
const middleware2 = createMiddleware({ type: 'function' })
|
|
271
275
|
.middleware([middleware1])
|
|
272
|
-
.
|
|
276
|
+
.validator(() => {
|
|
273
277
|
return {
|
|
274
278
|
b: 'b',
|
|
275
279
|
} as const
|
|
@@ -281,7 +285,7 @@ test('createMiddleware merges input', () => {
|
|
|
281
285
|
|
|
282
286
|
createMiddleware({ type: 'function' })
|
|
283
287
|
.middleware([middleware2])
|
|
284
|
-
.
|
|
288
|
+
.validator(() => ({ c: 'c' }) as const)
|
|
285
289
|
.server(({ next, data }) => {
|
|
286
290
|
expectTypeOf(data).toEqualTypeOf<{
|
|
287
291
|
readonly a: 'a'
|
|
@@ -595,7 +599,7 @@ test('createMiddleware sendContext cannot send a function', () => {
|
|
|
595
599
|
})
|
|
596
600
|
|
|
597
601
|
test('createMiddleware cannot validate function', () => {
|
|
598
|
-
const validator = createMiddleware({ type: 'function' }).
|
|
602
|
+
const validator = createMiddleware({ type: 'function' }).validator<
|
|
599
603
|
(input: { func: () => 'string' }) => { output: 'string' }
|
|
600
604
|
>
|
|
601
605
|
|
|
@@ -611,7 +615,7 @@ test('createMiddleware cannot validate function', () => {
|
|
|
611
615
|
})
|
|
612
616
|
|
|
613
617
|
test('createMiddleware can validate Date', () => {
|
|
614
|
-
const validator = createMiddleware({ type: 'function' }).
|
|
618
|
+
const validator = createMiddleware({ type: 'function' }).validator<
|
|
615
619
|
(input: Date) => { output: 'string' }
|
|
616
620
|
>
|
|
617
621
|
|
|
@@ -623,7 +627,7 @@ test('createMiddleware can validate Date', () => {
|
|
|
623
627
|
})
|
|
624
628
|
|
|
625
629
|
test('createMiddleware can validate FormData', () => {
|
|
626
|
-
const validator = createMiddleware({ type: 'function' }).
|
|
630
|
+
const validator = createMiddleware({ type: 'function' }).validator<
|
|
627
631
|
(input: FormData) => { output: 'string' }
|
|
628
632
|
>
|
|
629
633
|
|
|
@@ -639,7 +643,7 @@ test('createMiddleware can validate FormData', () => {
|
|
|
639
643
|
})
|
|
640
644
|
|
|
641
645
|
test('createMiddleware merging from parent with undefined validator', () => {
|
|
642
|
-
const middleware1 = createMiddleware({ type: 'function' }).
|
|
646
|
+
const middleware1 = createMiddleware({ type: 'function' }).validator(
|
|
643
647
|
(input: { test: string }) => input.test,
|
|
644
648
|
)
|
|
645
649
|
|
|
@@ -654,7 +658,7 @@ test('createMiddleware merging from parent with undefined validator', () => {
|
|
|
654
658
|
|
|
655
659
|
test('createMiddleware validator infers unknown for default input type', () => {
|
|
656
660
|
createMiddleware({ type: 'function' })
|
|
657
|
-
.
|
|
661
|
+
.validator((input) => {
|
|
658
662
|
expectTypeOf(input).toEqualTypeOf<unknown>()
|
|
659
663
|
|
|
660
664
|
if (typeof input === 'number') return 'success' as const
|