UNPKG

@tanstack/start-client-core

Version:

Modern and scalable routing for React applications

825 lines (768 loc) 21.1 kB
import type { StartInstanceOptions } from './createStart' import type { AnyServerFn, ConstrainValidator, CustomFetch, Method, } from './createServerFn' import type { ClientFnMeta, ServerFnMeta } from './constants' import type { AnyContext, Assign, Constrain, Expand, IntersectAssign, Register, ResolveValidatorInput, ResolveValidatorOutput, ValidateSerializableInput, } from '@tanstack/router-core' export type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>( options?: { type?: TType }, __opts?: FunctionMiddlewareOptions< TRegister, unknown, undefined, undefined, undefined >, ) => CreateMiddlewareResult<TRegister, TType> export const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => { const resolvedOptions = { type: 'request', ...(__opts || options), } return { options: resolvedOptions, middleware: (middleware: any) => { return createMiddleware( {} as any, Object.assign(resolvedOptions, { middleware }), ) as any }, inputValidator: (inputValidator: any) => { return createMiddleware( {} as any, Object.assign(resolvedOptions, { inputValidator }), ) as any }, client: (client: any) => { return createMiddleware( {} as any, Object.assign(resolvedOptions, { client }), ) as any }, server: (server: any) => { return createMiddleware( {} as any, Object.assign(resolvedOptions, { server }), ) as any }, } as any } export type MiddlewareType = 'request' | 'function' export type CreateMiddlewareResult< TRegister, TType extends MiddlewareType, > = 'request' extends TType ? RequestMiddleware<TRegister> : FunctionMiddleware<TRegister> export interface FunctionMiddleware< TRegister, > extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> { middleware: <const TNewMiddlewares = undefined>( middlewares: Constrain< TNewMiddlewares, ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware> >, ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares> } export interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares> extends FunctionMiddlewareWithTypes< TRegister, TMiddlewares, undefined, undefined, undefined, undefined, undefined >, FunctionMiddlewareServer< TRegister, TMiddlewares, undefined, undefined, undefined >, FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>, FunctionMiddlewareValidator<TRegister, TMiddlewares> {} export interface FunctionMiddlewareWithTypes< TRegister, TMiddlewares, TInputValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext, > { '~types': FunctionMiddlewareTypes< TRegister, TMiddlewares, TInputValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext > options: FunctionMiddlewareOptions< TRegister, TMiddlewares, TInputValidator, TServerContext, TClientContext > } export interface FunctionMiddlewareTypes< in out TRegister, in out TMiddlewares, in out TInputValidator, in out TServerContext, in out TServerSendContext, in out TClientContext, in out TClientSendContext, > { type: 'function' middlewares: TMiddlewares input: ResolveValidatorInput<TInputValidator> allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator> output: ResolveValidatorOutput<TInputValidator> allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> clientContext: TClientContext allClientContextBeforeNext: AssignAllClientContextBeforeNext< TMiddlewares, TClientContext > allClientContextAfterNext: AssignAllClientContextAfterNext< TMiddlewares, TClientContext, TClientSendContext > serverContext: TServerContext serverSendContext: TServerSendContext allServerSendContext: AssignAllServerSendContext< TMiddlewares, TServerSendContext > allServerContext: AssignAllServerFnContext< TRegister, TMiddlewares, TServerSendContext, TServerContext > clientSendContext: TClientSendContext allClientSendContext: AssignAllClientSendContext< TMiddlewares, TClientSendContext > inputValidator: TInputValidator } /** * Recursively resolve the input type produced by a sequence of middleware */ export type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> = unknown extends TInputValidator ? TInputValidator : TInputValidator extends undefined ? IntersectAllMiddleware<TMiddlewares, 'allInput'> : IntersectAssign< IntersectAllMiddleware<TMiddlewares, 'allInput'>, ResolveValidatorInput<TInputValidator> > export type IntersectAllMiddleware< TMiddlewares, TType extends | keyof AnyFunctionMiddleware['~types'] | keyof AnyRequestMiddleware['~types'] | keyof AnyServerFn['~types'], TAcc = undefined, > = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest] ? TMiddleware extends | AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn ? IntersectAllMiddleware< TRest, TType, IntersectAssign< TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']] > > : TAcc : TAcc export type AnyFunctionMiddleware = FunctionMiddlewareWithTypes< any, any, any, any, any, any, any > /** * Recursively merge the output type produced by a sequence of middleware */ export type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> = unknown extends TInputValidator ? TInputValidator : TInputValidator extends undefined ? IntersectAllMiddleware<TMiddlewares, 'allOutput'> : IntersectAssign< IntersectAllMiddleware<TMiddlewares, 'allOutput'>, Awaited<ResolveValidatorOutput<TInputValidator>> > /** * Recursively resolve the client context type produced by a sequence of middleware */ export type AssignAllClientContextBeforeNext< TMiddlewares, TClientContext = undefined, > = unknown extends TClientContext ? TClientContext : Assign< AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>, TClientContext > export type AssignAllMiddleware< TMiddlewares, TType extends | keyof AnyFunctionMiddleware['~types'] | keyof AnyRequestMiddleware['~types'] | keyof AnyServerFn['~types'], TAcc = undefined, > = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest] ? TMiddleware extends | AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn ? AssignAllMiddleware< TRest, TType, Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]> > : TAcc : TAcc export type AssignAllClientContextAfterNext< TMiddlewares, TClientContext = undefined, TSendContext = undefined, > = unknown extends TClientContext ? Assign<TClientContext, TSendContext> : Assign< AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>, Assign<TClientContext, TSendContext> > export type AssignAllServerSendContext< TMiddlewares, TSendContext = undefined, > = unknown extends TSendContext ? TSendContext : Assign< AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>, TSendContext > export type AssignAllServerRequestContext< TRegister, TMiddlewares, TSendContext = undefined, TServerContext = undefined, > = Assign< // Fetch Request Context GlobalFetchRequestContext, Assign< GlobalServerRequestContext<TRegister>, __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext> > > // export type GlobalFetchRequestContext<TRegister> = AnyContext export type GlobalFetchRequestContext = Register extends { server: { requestContext: infer TRequestContext } } ? TRequestContext : AnyContext export type GlobalServerRequestContext<TRegister> = TRegister extends { config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any> } ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'> : AnyContext type __AssignAllServerRequestContext< TMiddlewares, TSendContext = undefined, TServerContext = undefined, > = unknown extends TSendContext ? Assign<TSendContext, TServerContext> : Assign< AssignAllMiddleware<TMiddlewares, 'allServerContext'>, Assign<TSendContext, TServerContext> > export type AssignAllServerFnContext< TRegister, TMiddlewares, TSendContext = undefined, TServerContext = undefined, > = Assign< GlobalFetchRequestContext, Assign< GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware // type inference, but creates a circular types issue. No idea how to fix this. // AnyContext, Assign< GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware // type inference, but creates a circular types issue. No idea how to fix this. // AnyContext,/ __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext> > > > type GlobalServerFnContext<TRegister> = TRegister extends { config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares> } ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'> : AnyContext type __AssignAllServerFnContext< TMiddlewares, TSendContext = undefined, TServerContext = undefined, > = unknown extends TSendContext ? Assign<TSendContext, TServerContext> : Assign< AssignAllMiddleware<TMiddlewares, 'allServerContext'>, Assign<TSendContext, TServerContext> > export type AssignAllClientSendContext< TMiddlewares, TSendContext = undefined, > = unknown extends TSendContext ? TSendContext : Assign< AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>, TSendContext > export interface FunctionMiddlewareOptions< in out TRegister, in out TMiddlewares, in out TInputValidator, in out TServerContext, in out TClientContext, > { middleware?: TMiddlewares inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator> client?: FunctionMiddlewareClientFn< TRegister, TMiddlewares, TInputValidator, TServerContext, TClientContext > server?: FunctionMiddlewareServerFn< TRegister, TMiddlewares, TInputValidator, TServerContext, unknown, unknown > } export type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = < TSendContext = undefined, TNewClientContext = undefined, >(ctx?: { context?: TNewClientContext sendContext?: ValidateSerializableInput<TRegister, TSendContext> headers?: HeadersInit fetch?: CustomFetch }) => Promise< FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext> > export interface FunctionMiddlewareServer< TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext, > { server: <TNewServerContext = undefined, TSendContext = undefined>( server: FunctionMiddlewareServerFn< TRegister, TMiddlewares, TInputValidator, TServerSendContext, TNewServerContext, TSendContext >, ) => FunctionMiddlewareAfterServer< TRegister, TMiddlewares, TInputValidator, TNewServerContext, TServerSendContext, TClientContext, TSendContext > } export type FunctionMiddlewareServerFn< TRegister, TMiddlewares, TInputValidator, TServerSendContext, TNewServerContext, TSendContext, > = ( options: FunctionMiddlewareServerFnOptions< TRegister, TMiddlewares, TInputValidator, TServerSendContext >, ) => FunctionMiddlewareServerFnResult< TRegister, TMiddlewares, TServerSendContext, TNewServerContext, TSendContext > export type FunctionMiddlewareServerNextFn< TRegister, TMiddlewares, TServerSendContext, > = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: { context?: TNewServerContext sendContext?: ValidateSerializableInput<TRegister, TSendContext> }) => Promise< FunctionServerResultWithContext< TRegister, TMiddlewares, TServerSendContext, TNewServerContext, TSendContext > > export type FunctionServerResultWithContext< in out TRegister, 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< AssignAllServerFnContext< TRegister, TMiddlewares, TServerSendContext, TServerContext > > sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>> } export interface FunctionMiddlewareServerFnOptions< in out TRegister, in out TMiddlewares, in out TInputValidator, in out TServerSendContext, > { data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>> context: Expand< AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext> > next: FunctionMiddlewareServerNextFn< TRegister, TMiddlewares, TServerSendContext > method: Method serverFnMeta: ServerFnMeta signal: AbortSignal } export type FunctionMiddlewareServerFnResult< TRegister, TMiddlewares, TServerSendContext, TServerContext, TSendContext, > = | Promise< FunctionServerResultWithContext< TRegister, TMiddlewares, TServerSendContext, TServerContext, TSendContext > > | FunctionServerResultWithContext< TRegister, TMiddlewares, TServerSendContext, TServerContext, TSendContext > export interface FunctionMiddlewareAfterServer< TRegister, TMiddlewares, TInputValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext, > extends FunctionMiddlewareWithTypes< TRegister, TMiddlewares, TInputValidator, TServerContext, TServerSendContext, TClientContext, TClientSendContext > {} export interface FunctionMiddlewareClient< TRegister, TMiddlewares, TInputValidator, > { client: <TSendServerContext = undefined, TNewClientContext = undefined>( client: FunctionMiddlewareClientFn< TRegister, TMiddlewares, TInputValidator, TSendServerContext, TNewClientContext >, ) => FunctionMiddlewareAfterClient< TRegister, TMiddlewares, TInputValidator, TSendServerContext, TNewClientContext > } export type FunctionMiddlewareClientFn< TRegister, TMiddlewares, TInputValidator, TSendContext, TClientContext, > = ( options: FunctionMiddlewareClientFnOptions< TRegister, TMiddlewares, TInputValidator >, ) => FunctionMiddlewareClientFnResult< TMiddlewares, TSendContext, TClientContext > export interface FunctionMiddlewareClientFnOptions< in out TRegister, in out TMiddlewares, in out TInputValidator, > { data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>> context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>> sendContext: Expand<AssignAllServerSendContext<TMiddlewares>> method: Method signal: AbortSignal serverFnMeta: ClientFnMeta next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> filename: string fetch?: CustomFetch } export type FunctionMiddlewareClientFnResult< TMiddlewares, TSendContext, TClientContext, > = | Promise< FunctionClientResultWithContext< TMiddlewares, TSendContext, TClientContext > > | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext> export type FunctionClientResultWithContext< in out TMiddlewares, in out TSendContext, in out TClientContext, > = { 'use functions must return the result of next()': true context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>> sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>> headers: HeadersInit fetch?: CustomFetch } export interface FunctionMiddlewareAfterClient< TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext, > extends FunctionMiddlewareWithTypes< TRegister, TMiddlewares, TInputValidator, undefined, TServerSendContext, TClientContext, undefined >, FunctionMiddlewareServer< TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext > {} export interface FunctionMiddlewareValidator<TRegister, TMiddlewares> { inputValidator: <TNewValidator>( inputValidator: ConstrainValidator<TRegister, 'GET', TNewValidator>, ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator> } export interface FunctionMiddlewareAfterValidator< TRegister, TMiddlewares, TInputValidator, > extends FunctionMiddlewareWithTypes< TRegister, TMiddlewares, TInputValidator, undefined, undefined, undefined, undefined >, FunctionMiddlewareServer< TRegister, TMiddlewares, TInputValidator, undefined, undefined >, FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {} export interface RequestMiddleware< TRegister, > extends RequestMiddlewareAfterMiddleware<TRegister, undefined> { middleware: <const TMiddlewares = undefined>( middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>, ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares> } export type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any> export interface RequestMiddlewareWithTypes< TRegister, TMiddlewares, TServerContext, > { '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext> options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext> } export interface RequestMiddlewareOptions< in out TRegister, in out TMiddlewares, in out TServerContext, > { middleware?: TMiddlewares server?: RequestServerFn<TRegister, TMiddlewares, TServerContext> } export interface RequestMiddlewareTypes< TRegister, TMiddlewares, TServerContext, > { type: 'request' // this only exists so we can use request middlewares in server functions allInput: undefined // this only exists so we can use request middlewares in server functions allOutput: undefined middlewares: TMiddlewares serverContext: TServerContext allServerContext: AssignAllServerRequestContext< TRegister, TMiddlewares, undefined, TServerContext > } export interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>, RequestMiddlewareServer<TRegister, TMiddlewares> {} export interface RequestMiddlewareServer<TRegister, TMiddlewares> { server: <TServerContext = undefined>( fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>, ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext> } export type RequestServerFn<TRegister, TMiddlewares, TServerContext> = ( options: RequestServerOptions<TRegister, TMiddlewares>, ) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext> export interface RequestServerOptions<TRegister, TMiddlewares> { request: Request pathname: string context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>> next: RequestServerNextFn<TRegister, TMiddlewares> /** * Metadata about the server function being invoked. * This is only present when the request is handling a server function call. * For regular page requests, this will be undefined. */ serverFnMeta?: ServerFnMeta } export type RequestServerNextFn<TRegister, TMiddlewares> = < TServerContext = undefined, >( options?: RequestServerNextFnOptions<TServerContext>, ) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> export interface RequestServerNextFnOptions<TServerContext> { context?: TServerContext } export type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> = | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>> | RequestServerResult<TRegister, TMiddlewares, TServerContext> export type RequestMiddlewareServerFnResult< TRegister, TMiddlewares, TServerContext, > = | Promise< RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response > | RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response export interface RequestServerResult<TRegister, TMiddlewares, TServerContext> { request: Request pathname: string context: Expand< AssignAllServerRequestContext< TRegister, TMiddlewares, undefined, TServerContext > > response: Response } export interface RequestMiddlewareAfterServer< TRegister, TMiddlewares, TServerContext, > extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}