@tanstack/start-client-core 1.170.7 → 1.170.9
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.js.map +1 -1
- package/dist/esm/createServerFn.js.map +1 -1
- package/package.json +3 -3
- package/skills/start-core/auth-server-primitives/SKILL.md +13 -2
- package/skills/start-core/middleware/SKILL.md +2 -2
- package/skills/start-core/server-functions/SKILL.md +3 -3
- package/src/createMiddleware.ts +6 -12
- package/src/createServerFn.ts +6 -15
|
@@ -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 {} as any,\n Object.assign(resolvedOptions, { middleware }),\n ) as any\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { inputValidator }),\n ) as any\n },\n client: (client: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { client }),\n ) as any\n },\n server: (server: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { server }),\n ) as any\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,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAC3C;EACF;EACA,SAAS,WAAgB;GACvB,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAC3C;EACF;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\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 +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 FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\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) as any\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 as any,\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) as any\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 } as any\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 as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any,\n any\n >\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 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":";;;;;;;AAyEA,IAAa,kBAA4C,SAAS,WAAW;CAC3E,MAAM,kBAAmB,UAAU,WAAW,CAAC;CAS/C,IAAI,OAAO,gBAAgB,WAAW,aACpC,gBAAgB,SAAS;CAG3B,MAAM,MAAyD;EAC7D,SAAS;EACT,aAAa,eAAe;GAI1B,MAAM,gBAAgB,CAAC,GAAI,gBAAgB,cAAc,CAAC,CAAE;GAC5D,WAAW,KAAK,MAAM;IACpB,IAAI,+BAA+B;SAC7B,EAAE,QAAQ,YACZ,cAAc,KAAK,GAAG,EAAE,QAAQ,UAAU;IAAA,OAG5C,cAAc,KAAK,CAAC;GAExB,CAAC;GAMD,MAAM,MAAM,eAAe,KAAA,GAAW;IAHpC,GAAG;IACH,YAAY;GAEwB,CAAU;GAChD,IAAI,+BAA+B;GACnC,OAAO;EACT;EACA,iBAAiB,mBAAmB;GAElC,OAAO,eAAe,KAAA,GAAW;IADZ,GAAG;IAAiB;GACR,CAAU;EAC7C;EACA,UAAU,GAAG,SAAS;GAIpB,MAAM,CAAC,aAAa,YAAY;GAOhC,MAAM,aAAa;IAAE,GAAG;IAAiB;IAAa;GAAS;GAE/D,MAAM,qBAAqB,CACzB,GAAI,WAAW,cAAc,CAAC,GAC9B,yBAAyB,UAAU,CACrC;GASC,YAAqB,SAAS,gBAAgB;GAE/C,OAAO,OAAO,OACZ,OAAO,SAAoC;IAEzC,MAAM,SAAS,MAAM,kBAAkB,oBAAoB,UAAU;KACnE,GAAG;KACH,GAAG;KACH,MAAM,MAAM;KACZ,SAAS,MAAM;KACf,QAAQ,MAAM;KACd,OAAO,MAAM;KACb,SAAS,sBAAsB;IACjC,CAAC;IAED,MAAM,WAAW,cAAc,OAAO,KAAK;IAC3C,IAAI,UACF,MAAM;IAGR,IAAI,OAAO,OAAO,MAAM,OAAO;IAC/B,OAAO,OAAO;GAChB,GACA;IAEE,GAAG;IAGH,QAAQ,gBAAgB;IAGxB,iBAAiB,OAAO,SAAc;KACpC,MAAM,eAAe,0BAA0B;KAC/C,MAAM,sCACJ,aAAa;KA2Bf,OAAO,MAXc,kBACnB,oBACA,UACA;MAjBA,GAAG;MACH,GAAG;MAIH,cAAc,YAAY;MAE1B,SAAS,gBACP,KAAK,SACL,mCACF;MACA,SAAS,aAAa;KAMtB,CACF,EAAE,MAAM,OAAO;MAEb,QAAQ,EAAE;MACV,OAAO,EAAE;MACT,SAAS,EAAE;KACb,EAAE;IAGJ;GACF,CACF;EACF;CACF;CACA,MAAM,OAAO,YAAsD;EAKjE,OAAO,eAAe,KAAA,GAAW;GAH/B,GAAG;GACH,GAAG;EAE4B,CAAU;CAC7C;CACA,OAAO,OAAO,OAAO,KAAK,GAAG;AAC/B;AAEA,eAAsB,kBACpB,aACA,KACA,MACmC;CAEnC,IAAI,uBAAuB,mBAAmB,CAC5C,GAFwB,gBAAgB,GAAG,sBAAsB,CAAC,GAGlE,GAAG,WACL,CAAC;CAID,IAAI,QAAQ,UAAU;EACpB,MAAM,eAAe,0BAA0B,EAAE,iBAAiB,MAAM,CAAC;EACzE,IAAI,cAAc,4BAChB,uBAAuB,qBAAqB,QACzC,MAAM,CAAC,aAAa,2BAA2B,IAAI,CAAC,CACvD;CAEJ;CAEA,MAAM,qBAA6B,OAAO,QAAQ;EAEhD,MAAM,iBAAiB,qBAAqB,MAAM;EAGlD,IAAI,CAAC,gBACH,OAAO;EAIT,IAAI;GACF,IACE,oBAAoB,eAAe,WACnC,eAAe,QAAQ,kBACvB,QAAQ,UAGR,IAAI,OAAO,MAAM,cACf,eAAe,QAAQ,gBACvB,IAAI,IACN;GAGF,IAAI,eAAyC,KAAA;GAC7C,IAAI,QAAQ;QACN,YAAY,eAAe,SAC7B,eAAe,eAAe,QAAQ;GAAA,OAMrC,IAAI,YAAY,eAAe,SAClC,eAAe,eAAe,QAAQ;GAGxC,IAAI,cAAc;IAChB,MAAM,WAAW,OACf,UAAgD,CAAC,MAC9C;KAoBH,MAAM,SAAS,MAAM,mBAAmB;MAhBtC,GAAG;MACH,GAAG;MACH,SAAS,gBAAgB,IAAI,SAAS,QAAQ,OAAO;MACrD,aAAa,gBAAgB,IAAI,aAAa,QAAQ,WAAW;MACjE,SAAS,aAAa,IAAI,SAAS,QAAQ,OAAO;MAClD,gBAAgB,IAAI;MACpB,OAAO,IAAI,kBAAkB,QAAQ,SAAS,IAAI;MAClD,QACE,QAAQ,WAAW,KAAA,IACf,QAAQ,SACR,mBAAmB,WACjB,UACC,IAAY;MACrB,OAAO,QAAQ,SAAU,IAAY;KAGC,CAAO;KAE/C,IAAI,OAAO,OACT,MAAM,OAAO;KAGf,OAAO;IACT;IAGA,MAAM,SAAS,MAAM,aAAa;KAChC,GAAG;KACH,MAAM;IACR,CAAC;IAID,IAAI,WAAW,MAAM,GACnB,OAAO;KACL,GAAG;KACH,OAAO;IACT;IAGF,IAAI,kBAAkB,UACpB,OAAO;KACL,GAAG;KACH;IACF;IAGF,IAAI,CAAE,QACJ,MAAM,IAAI,MACR,kGACF;IAGF,OAAO;GACT;GAEA,OAAO,mBAAmB,GAAG;EAC/B,SAAS,OAAY;GACnB,OAAO;IACL,GAAG;IACH;GACF;EACF;CACF;CAGA,OAAO,mBAAmB;EACxB,GAAG;EACH,SAAS,KAAK,WAAW,CAAC;EAC1B,aAAa,KAAK,eAAe,CAAC;EAClC,SAAS,KAAK,WAAW,sBAAsB;EAC/C,gBAAgB,KAAK;CACvB,CAAC;AACH;AA6cA,SAAgB,mBAEd,aAAuB,WAAmB,KAAe;CACzD,MAAM,uBAAO,IAAI,IAAO;CACxB,MAAM,YAAsB,CAAC;CAE7B,MAAM,WAAW,YAAsB,UAAkB;EACvD,IAAI,QAAQ,UACV,MAAM,IAAI,MACR,gDAAgD,SAAS,iCAC3D;EAEF,WAAW,SAAS,MAAM;GACxB,IAAI,EAAE,QAAQ,YACZ,QAAQ,EAAE,QAAQ,YAAwB,QAAQ,CAAC;GAGrD,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;IAChB,KAAK,IAAI,CAAC;IACV,UAAU,KAAK,CAAC;GAClB;EACF,CAAC;CACH;CAEA,QAAQ,aAAa,CAAC;CAEtB,OAAO;AACT;AA8BA,eAAsB,cACpB,WACA,OACkB;CAClB,IAAI,aAAa,MAAM,OAAO,CAAC;CAE/B,IAAI,eAAe,WAAW;EAC5B,MAAM,SAAS,MAAM,UAAU,aAAa,SAAS,KAAK;EAE1D,IAAI,OAAO,QACT,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,QAAQ,KAAA,GAAW,CAAC,CAAC;EAE7D,OAAO,OAAO;CAChB;CAEA,IAAI,WAAW,WACb,OAAO,UAAU,MAAM,KAAK;CAG9B,IAAI,OAAO,cAAc,YACvB,OAAO,UAAU,KAAK;CAGxB,MAAM,IAAI,MAAM,yBAAyB;AAC3C;AAEA,SAAS,yBACP,SACuB;CACvB,OAAO;EACL,UAAU,KAAA;EACV,SAAS;GACP,gBAAgB,QAAQ;GACxB,QAAQ,OAAO,EAAE,MAAM,aAAa,OAAO,GAAG,UAAU;IACtD,MAAM,UAAU;KACd,GAAG;KAEH,SAAS;KACT;IACF;IAMA,OAAO,KAAK,MAFM,QAAQ,cAAc,OAAO,CAEhC;GACjB;GACA,QAAQ,OAAO,EAAE,MAAM,GAAG,UAAU;IAElC,MAAM,SAAS,MAAM,QAAQ,WAAW,GAAG;IAE3C,OAAO,KAAK;KACV,GAAG;KACH;IACF,CAAQ;GACV;EACF;CACF;AACF"}
|
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.9",
|
|
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.11",
|
|
95
95
|
"@tanstack/start-fn-stubs": "1.162.0",
|
|
96
|
-
"@tanstack/start-storage-context": "1.167.
|
|
96
|
+
"@tanstack/start-storage-context": "1.167.13"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"vite": "*",
|
|
@@ -24,10 +24,21 @@ sources:
|
|
|
24
24
|
|
|
25
25
|
This skill covers the **server half** of authentication: session storage, cookie issuance, OAuth flow, password-reset hardening, CSRF, rate limiting. For the **routing half** (`_authenticated` layout, `beforeLoad` redirects, RBAC checks), see [router-core/auth-and-guards](../../../../router-core/skills/router-core/auth-and-guards/SKILL.md).
|
|
26
26
|
|
|
27
|
-
> **CRITICAL**:
|
|
27
|
+
> **CRITICAL**: Protect the data/API boundary first. Server functions, server routes, and other API endpoints that touch private data must enforce auth **inside the handler** or middleware. Route guards are route UX, not the data security boundary.
|
|
28
28
|
> **CRITICAL**: Validating the _shape_ of a client-supplied identifier (`z.string().uuid().parse(...)`) is not authorization. A parsed UUID is still _some_ tenant — re-check membership against the session principal before using it.
|
|
29
29
|
> **CRITICAL**: Read session/cookies inside `.handler()` or middleware `.server()`, not at module scope. Module-level reads run before requests exist (and are also undefined on Cloudflare Workers).
|
|
30
30
|
|
|
31
|
+
## Production Checklist
|
|
32
|
+
|
|
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 `.inputValidator()` on every server function that accepts input.
|
|
35
|
+
- Store sessions in `HttpOnly`, `Secure`, `SameSite` cookies. Do not store session tokens in `localStorage` or `sessionStorage`.
|
|
36
|
+
- Hash passwords with bcrypt, scrypt, or Argon2. For missing users, verify against a dummy hash and return the same login/reset message.
|
|
37
|
+
- Rate limit login, registration, and password-reset endpoints.
|
|
38
|
+
- Use CSRF or same-origin protections for non-GET server functions and server routes.
|
|
39
|
+
- Log authentication events and monitor failures.
|
|
40
|
+
- Test direct unauthenticated calls to protected server functions; they should reject before returning data.
|
|
41
|
+
|
|
31
42
|
## Session Cookies
|
|
32
43
|
|
|
33
44
|
The recommended session storage is an HTTP-only cookie holding either an opaque session ID (with server-side lookup) or a signed/encrypted token. The cookie flags matter — set them all.
|
|
@@ -117,7 +128,7 @@ export const getMyOrders = createServerFn({ method: 'GET' })
|
|
|
117
128
|
})
|
|
118
129
|
```
|
|
119
130
|
|
|
120
|
-
> **Route guards do not cover this.** A `createFileRoute('/_authenticated/orders')` with a `beforeLoad` redirect does NOT protect `getMyOrders` — the RPC is reachable
|
|
131
|
+
> **Route guards do not cover this.** A `createFileRoute('/_authenticated/orders')` with a `beforeLoad` redirect does NOT protect `getMyOrders` — the RPC is reachable directly whether or not the user ever hits the route. Apply `authMiddleware` (or re-check inside `.handler()`) on every server function that needs auth.
|
|
121
132
|
|
|
122
133
|
## Issuing a Session on Login
|
|
123
134
|
|
|
@@ -243,7 +243,7 @@ const authMiddleware = createMiddleware().server(async ({ next, request }) => {
|
|
|
243
243
|
})
|
|
244
244
|
```
|
|
245
245
|
|
|
246
|
-
> **Attach `authMiddleware` to every `createServerFn` that needs auth.** Server functions are
|
|
246
|
+
> **Attach `authMiddleware` to every `createServerFn` that needs auth.** Server functions are API endpoints; a route `beforeLoad` does not protect their data, only the route's UI. Protect the endpoint that reads or mutates private data. See [router-core/auth-and-guards](../../../../router-core/skills/router-core/auth-and-guards/SKILL.md) and [start-core/auth-server-primitives](../auth-server-primitives/SKILL.md).
|
|
247
247
|
|
|
248
248
|
```tsx
|
|
249
249
|
type Permissions = Record<string, string[]>
|
|
@@ -395,4 +395,4 @@ createMiddleware({ type: 'function' })
|
|
|
395
395
|
- [start-core/server-functions](../server-functions/SKILL.md) — what middleware wraps
|
|
396
396
|
- [start-core/server-routes](../server-routes/SKILL.md) — middleware on API endpoints
|
|
397
397
|
- [start-core/auth-server-primitives](../auth-server-primitives/SKILL.md) — building the `authMiddleware` factory itself: session cookie reads, OAuth state, CSRF
|
|
398
|
-
- [router-core/auth-and-guards](../../../../router-core/skills/router-core/auth-and-guards/SKILL.md) — routing-side guards
|
|
398
|
+
- [router-core/auth-and-guards](../../../../router-core/skills/router-core/auth-and-guards/SKILL.md) — routing-side UX guards; data auth belongs in the server function, server route, or API endpoint handler/middleware
|
|
@@ -19,7 +19,7 @@ sources:
|
|
|
19
19
|
|
|
20
20
|
Server functions are type-safe RPCs created with `createServerFn`. They run exclusively on the server but can be called from anywhere — loaders, components, hooks, event handlers, or other server functions.
|
|
21
21
|
|
|
22
|
-
> **CRITICAL**: Server functions are
|
|
22
|
+
> **CRITICAL**: Server functions are API endpoints. They are reachable independently of whichever route renders the calling UI. **Auth must be enforced inside the handler (or via middleware) for any server function that touches private data.** Route `beforeLoad` is UX, not the data boundary. See [start-core/auth-server-primitives](../auth-server-primitives/SKILL.md) for the session/middleware pattern.
|
|
23
23
|
> **CRITICAL**: Loaders are ISOMORPHIC — they run on BOTH client and server. Database queries, file system access, and secret API keys MUST go inside `createServerFn`, NOT in loaders directly.
|
|
24
24
|
> **CRITICAL**: Do not use `"use server"` directives, `getServerSideProps`, or any Next.js/Remix server patterns. TanStack Start uses `createServerFn` exclusively.
|
|
25
25
|
|
|
@@ -270,7 +270,7 @@ Static imports of server functions are safe — the build replaces implementatio
|
|
|
270
270
|
|
|
271
271
|
### 1. CRITICAL: Relying on a route guard to protect a server function
|
|
272
272
|
|
|
273
|
-
A `beforeLoad` redirect protects the **route's UI**, not the **
|
|
273
|
+
A `beforeLoad` redirect protects the **route's UI**, not the **data endpoint**. `createServerFn` exposes a callable endpoint that an attacker can hit directly — no need to load the route at all. Auth on the endpoint is the security boundary; auth on the route is UX.
|
|
274
274
|
|
|
275
275
|
```tsx
|
|
276
276
|
// WRONG — the route guard doesn't reach the handler
|
|
@@ -430,4 +430,4 @@ If in doubt: wrap with `useServerFn`. It's a no-op for plain-data functions and
|
|
|
430
430
|
- [start-core/execution-model](../execution-model/SKILL.md) — understanding where code runs
|
|
431
431
|
- [start-core/middleware](../middleware/SKILL.md) — composing server functions with middleware
|
|
432
432
|
- [start-core/auth-server-primitives](../auth-server-primitives/SKILL.md) — sessions, cookies, OAuth, CSRF, rate limiting (the server-side half of auth; `getCurrentUser`/`useSession`-style helpers belong here, not at module scope)
|
|
433
|
-
- [router-core/auth-and-guards](../../../../router-core/skills/router-core/auth-and-guards/SKILL.md) —
|
|
433
|
+
- [router-core/auth-and-guards](../../../../router-core/skills/router-core/auth-and-guards/SKILL.md) — routing-side UX guards; data auth belongs in the server function, server route, or API endpoint handler/middleware
|
package/src/createMiddleware.ts
CHANGED
|
@@ -41,27 +41,21 @@ export const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {
|
|
|
41
41
|
options: resolvedOptions,
|
|
42
42
|
middleware: (middleware: any) => {
|
|
43
43
|
return createMiddleware(
|
|
44
|
-
{}
|
|
44
|
+
{},
|
|
45
45
|
Object.assign(resolvedOptions, { middleware }),
|
|
46
|
-
)
|
|
46
|
+
)
|
|
47
47
|
},
|
|
48
48
|
inputValidator: (inputValidator: any) => {
|
|
49
49
|
return createMiddleware(
|
|
50
|
-
{}
|
|
50
|
+
{},
|
|
51
51
|
Object.assign(resolvedOptions, { inputValidator }),
|
|
52
|
-
)
|
|
52
|
+
)
|
|
53
53
|
},
|
|
54
54
|
client: (client: any) => {
|
|
55
|
-
return createMiddleware(
|
|
56
|
-
{} as any,
|
|
57
|
-
Object.assign(resolvedOptions, { client }),
|
|
58
|
-
) as any
|
|
55
|
+
return createMiddleware({}, Object.assign(resolvedOptions, { client }))
|
|
59
56
|
},
|
|
60
57
|
server: (server: any) => {
|
|
61
|
-
return createMiddleware(
|
|
62
|
-
{} as any,
|
|
63
|
-
Object.assign(resolvedOptions, { server }),
|
|
64
|
-
) as any
|
|
58
|
+
return createMiddleware({}, Object.assign(resolvedOptions, { server }))
|
|
65
59
|
},
|
|
66
60
|
} as any
|
|
67
61
|
}
|
package/src/createServerFn.ts
CHANGED
|
@@ -25,13 +25,10 @@ import type {
|
|
|
25
25
|
AnyFunctionMiddleware,
|
|
26
26
|
AnyRequestMiddleware,
|
|
27
27
|
AssignAllServerFnContext,
|
|
28
|
-
FunctionMiddlewareServerFnResult,
|
|
29
28
|
IntersectAllValidatorInputs,
|
|
30
29
|
IntersectAllValidatorOutputs,
|
|
31
30
|
} from './createMiddleware'
|
|
32
31
|
|
|
33
|
-
type TODO = any
|
|
34
|
-
|
|
35
32
|
export type ServerFnStrict = boolean | { input?: boolean; output?: boolean }
|
|
36
33
|
|
|
37
34
|
export interface ServerFnOptions<
|
|
@@ -109,7 +106,7 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
|
|
|
109
106
|
...resolvedOptions,
|
|
110
107
|
middleware: newMiddleware,
|
|
111
108
|
}
|
|
112
|
-
const res = createServerFn(undefined, newOptions)
|
|
109
|
+
const res = createServerFn(undefined, newOptions)
|
|
113
110
|
res[TSS_SERVER_FUNCTION_FACTORY] = true
|
|
114
111
|
return res
|
|
115
112
|
},
|
|
@@ -150,7 +147,7 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
|
|
|
150
147
|
const result = await executeMiddleware(resolvedMiddleware, 'client', {
|
|
151
148
|
...extractedFn,
|
|
152
149
|
...newOptions,
|
|
153
|
-
data: opts?.data
|
|
150
|
+
data: opts?.data,
|
|
154
151
|
headers: opts?.headers,
|
|
155
152
|
signal: opts?.signal,
|
|
156
153
|
fetch: opts?.fetch,
|
|
@@ -214,7 +211,7 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
|
|
|
214
211
|
...resolvedOptions,
|
|
215
212
|
...options,
|
|
216
213
|
}
|
|
217
|
-
return createServerFn(undefined, newOptions)
|
|
214
|
+
return createServerFn(undefined, newOptions)
|
|
218
215
|
}
|
|
219
216
|
return Object.assign(fun, res) as any
|
|
220
217
|
}
|
|
@@ -914,7 +911,7 @@ function serverFnBaseToMiddleware(
|
|
|
914
911
|
// switch the sendContext over to context
|
|
915
912
|
context: sendContext,
|
|
916
913
|
fetch,
|
|
917
|
-
}
|
|
914
|
+
}
|
|
918
915
|
|
|
919
916
|
// Execute the extracted function
|
|
920
917
|
// but not before serializing the context
|
|
@@ -924,18 +921,12 @@ function serverFnBaseToMiddleware(
|
|
|
924
921
|
},
|
|
925
922
|
server: async ({ next, ...ctx }) => {
|
|
926
923
|
// Execute the server function
|
|
927
|
-
const result = await options.serverFn?.(ctx
|
|
924
|
+
const result = await options.serverFn?.(ctx)
|
|
928
925
|
|
|
929
926
|
return next({
|
|
930
927
|
...ctx,
|
|
931
928
|
result,
|
|
932
|
-
} as any)
|
|
933
|
-
any,
|
|
934
|
-
any,
|
|
935
|
-
any,
|
|
936
|
-
any,
|
|
937
|
-
any
|
|
938
|
-
>
|
|
929
|
+
} as any)
|
|
939
930
|
},
|
|
940
931
|
},
|
|
941
932
|
}
|