import type { ConstrainValidator, Method, ServerFnTypeOrTypeFn, } from './createServerFn' import type { Assign, Constrain, Expand, IntersectAssign, ResolveValidatorInput, ResolveValidatorOutput, SerializerStringify, } from '@tanstack/router-core' export type AssignAllMiddleware< TMiddlewares, TType extends keyof AnyMiddleware['_types'], TAcc = undefined, > = TMiddlewares extends readonly [ infer TMiddleware extends AnyMiddleware, ...infer TRest, ] ? AssignAllMiddleware< TRest, TType, Assign > : TAcc /** * Recursively resolve the client context type produced by a sequence of middleware */ export type AssignAllClientContextBeforeNext< TMiddlewares, TClientContext = undefined, > = unknown extends TClientContext ? TClientContext : Assign< AssignAllMiddleware, TClientContext > export type AssignAllClientSendContext< TMiddlewares, TSendContext = undefined, > = unknown extends TSendContext ? TSendContext : Assign< AssignAllMiddleware, TSendContext > export type AssignAllClientContextAfterNext< TMiddlewares, TClientContext = undefined, TSendContext = undefined, > = unknown extends TClientContext ? Assign : Assign< AssignAllMiddleware, Assign > /** * Recursively resolve the server context type produced by a sequence of middleware */ export type AssignAllServerContext< TMiddlewares, TSendContext = undefined, TServerContext = undefined, > = unknown extends TSendContext ? Assign : Assign< AssignAllMiddleware, Assign > export type AssignAllServerSendContext< TMiddlewares, TSendContext = undefined, > = unknown extends TSendContext ? TSendContext : Assign< AssignAllMiddleware, TSendContext > export type IntersectAllMiddleware< TMiddlewares, TType extends keyof AnyMiddleware['_types'], TAcc = undefined, > = TMiddlewares extends readonly [ infer TMiddleware extends AnyMiddleware, ...infer TRest, ] ? IntersectAllMiddleware< TRest, TType, IntersectAssign > : TAcc /** * Recursively resolve the input type produced by a sequence of middleware */ export type IntersectAllValidatorInputs = unknown extends TValidator ? TValidator : IntersectAssign< IntersectAllMiddleware, TValidator extends undefined ? undefined : ResolveValidatorInput > /** * Recursively merge the output type produced by a sequence of middleware */ export type IntersectAllValidatorOutputs = unknown extends TValidator ? TValidator : IntersectAssign< IntersectAllMiddleware, TValidator extends undefined ? undefined : ResolveValidatorOutput > export interface MiddlewareOptions< in out TMiddlewares, in out TValidator, in out TServerContext, in out TClientContext, > { validateClient?: boolean middleware?: TMiddlewares validator?: ConstrainValidator client?: MiddlewareClientFn< TMiddlewares, TValidator, TServerContext, TClientContext > server?: MiddlewareServerFn< TMiddlewares, TValidator, TServerContext, unknown, unknown > } export type MiddlewareServerNextFn = < TNewServerContext = undefined, TSendContext = undefined, >(ctx?: { context?: TNewServerContext sendContext?: SerializerStringify }) => Promise< ServerResultWithContext< TMiddlewares, TServerSendContext, TNewServerContext, TSendContext > > export interface MiddlewareServerFnOptions< in out TMiddlewares, in out TValidator, in out TServerSendContext, > { data: Expand> context: Expand> next: MiddlewareServerNextFn method: Method filename: string functionId: string signal: AbortSignal } export type MiddlewareServerFn< TMiddlewares, TValidator, TServerSendContext, TNewServerContext, TSendContext, > = ( options: MiddlewareServerFnOptions< TMiddlewares, TValidator, TServerSendContext >, ) => MiddlewareServerFnResult< TMiddlewares, TServerSendContext, TNewServerContext, TSendContext > export type MiddlewareServerFnResult< TMiddlewares, TServerSendContext, TServerContext, TSendContext, > = | Promise< ServerResultWithContext< TMiddlewares, TServerSendContext, TServerContext, TSendContext > > | ServerResultWithContext< TMiddlewares, TServerSendContext, TServerContext, TSendContext > export type MiddlewareClientNextFn = < TSendContext = undefined, TNewClientContext = undefined, >(ctx?: { context?: TNewClientContext sendContext?: SerializerStringify headers?: HeadersInit }) => Promise< ClientResultWithContext > export interface MiddlewareClientFnOptions< in out TMiddlewares, in out TValidator, > { data: Expand> context: Expand> sendContext: Expand> method: Method signal: AbortSignal next: MiddlewareClientNextFn filename: string functionId: string type: ServerFnTypeOrTypeFn } export type MiddlewareClientFn< TMiddlewares, TValidator, TSendContext, TClientContext, > = ( options: MiddlewareClientFnOptions, ) => MiddlewareClientFnResult export type MiddlewareClientFnResult< TMiddlewares, TSendContext, TClientContext, > = | Promise> | ClientResultWithContext export type ServerResultWithContext< in out TMiddlewares, in out TServerSendContext, in out TServerContext, in out TSendContext, > = { 'use functions must return the result of next()': true _types: { context: TServerContext sendContext: TSendContext } context: Expand< AssignAllServerContext > sendContext: Expand> } export type ClientResultWithContext< in out TMiddlewares, in out TSendContext, in out TClientContext, > = { 'use functions must return the result of next()': true context: Expand> sendContext: Expand> headers: HeadersInit } export type AnyMiddleware = MiddlewareWithTypes export interface MiddlewareTypes< in out TMiddlewares, in out TValidator, in out TServerContext, in out TServerSendContext, in out TClientContext, in out TClientSendContext, > { middlewares: TMiddlewares input: ResolveValidatorInput allInput: IntersectAllValidatorInputs output: ResolveValidatorOutput allOutput: IntersectAllValidatorOutputs clientContext: TClientContext allClientContextBeforeNext: AssignAllClientContextBeforeNext< TMiddlewares, TClientContext > allClientContextAfterNext: AssignAllClientContextAfterNext< TMiddlewares, TClientContext, TClientSendContext > serverContext: TServerContext serverSendContext: TServerSendContext allServerSendContext: AssignAllServerSendContext< TMiddlewares, TServerSendContext > allServerContext: AssignAllServerContext< TMiddlewares, TServerSendContext, TServerContext > clientSendContext: TClientSendContext allClientSendContext: AssignAllClientSendContext< TMiddlewares, TClientSendContext > validator: TValidator } export interface MiddlewareWithTypes< TMiddlewares, TValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext, > { _types: MiddlewareTypes< TMiddlewares, TValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext > options: MiddlewareOptions< TMiddlewares, TValidator, TServerContext, TClientContext > } export interface MiddlewareAfterValidator extends MiddlewareWithTypes< TMiddlewares, TValidator, undefined, undefined, undefined, undefined >, MiddlewareServer, MiddlewareClient {} export interface MiddlewareValidator { validator: ( input: ConstrainValidator, ) => MiddlewareAfterValidator } export interface MiddlewareAfterServer< TMiddlewares, TValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext, > extends MiddlewareWithTypes< TMiddlewares, TValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext > {} export interface MiddlewareServer< TMiddlewares, TValidator, TServerSendContext, TClientContext, > { server: ( server: MiddlewareServerFn< TMiddlewares, TValidator, TServerSendContext, TNewServerContext, TSendContext >, ) => MiddlewareAfterServer< TMiddlewares, TValidator, TNewServerContext, TServerSendContext, TClientContext, TSendContext > } export interface MiddlewareAfterClient< TMiddlewares, TValidator, TServerSendContext, TClientContext, > extends MiddlewareWithTypes< TMiddlewares, TValidator, undefined, TServerSendContext, TClientContext, undefined >, MiddlewareServer< TMiddlewares, TValidator, TServerSendContext, TClientContext > {} export interface MiddlewareClient { client: ( client: MiddlewareClientFn< TMiddlewares, TValidator, TSendServerContext, TNewClientContext >, ) => MiddlewareAfterClient< TMiddlewares, TValidator, TSendServerContext, TNewClientContext > } export interface MiddlewareAfterMiddleware extends MiddlewareWithTypes< TMiddlewares, undefined, undefined, undefined, undefined, undefined >, MiddlewareServer, MiddlewareClient, MiddlewareValidator {} export interface Middleware extends MiddlewareAfterMiddleware { middleware: ( middlewares: Constrain>, ) => MiddlewareAfterMiddleware } export function createMiddleware( options?: { validateClient?: boolean }, __opts?: MiddlewareOptions, ): Middleware { // const resolvedOptions = (__opts || options) as MiddlewareOptions< const resolvedOptions = __opts || ((options || {}) as MiddlewareOptions< unknown, undefined, undefined, undefined >) return { options: resolvedOptions as any, middleware: (middleware: any) => { return createMiddleware( undefined, Object.assign(resolvedOptions, { middleware }), ) as any }, validator: (validator: any) => { return createMiddleware( undefined, Object.assign(resolvedOptions, { validator }), ) as any }, client: (client: any) => { return createMiddleware( undefined, Object.assign(resolvedOptions, { client }), ) as any }, server: (server: any) => { return createMiddleware( undefined, Object.assign(resolvedOptions, { server }), ) as any }, } as unknown as Middleware }