UNPKG

@tanstack/router-core

Version:

Modern and scalable routing for React applications

2,104 lines (1,965 loc) 50.6 kB
import invariant from 'tiny-invariant' import { joinPaths, trimPathLeft, trimPathRight } from './path' import { notFound } from './not-found' import { redirect } from './redirect' import { rootRouteId } from './root' import type { LazyRoute } from './fileRoute' import type { NotFoundError } from './not-found' import type { RedirectFnRoute } from './redirect' import type { NavigateOptions, ParsePathParams } from './link' import type { ParsedLocation } from './location' import type { AnyRouteMatch, MakePreValidationErrorHandlingRouteMatchUnion, MakeRouteMatchFromRoute, MakeRouteMatchUnion, RouteMatch, } from './Matches' import type { RootRouteId } from './root' import type { ParseRoute, RouteById, RouteIds, RoutePaths } from './routeInfo' import type { AnyRouter, Register, RegisteredRouter, SSROption } from './router' import type { BuildLocationFn, NavigateFn } from './RouterProvider' import type { Assign, Awaitable, Constrain, Expand, IntersectAssign, LooseAsyncReturnType, LooseReturnType, NoInfer, } from './utils' import type { AnySchema, AnyStandardSchemaValidator, AnyValidator, AnyValidatorAdapter, AnyValidatorObj, DefaultValidator, ResolveSearchValidatorInput, ResolveValidatorOutput, StandardSchemaValidator, ValidatorAdapter, ValidatorFn, ValidatorObj, } from './validators' import type { ValidateSerializableLifecycleResult } from './ssr/serializer/transformer' export type AnyPathParams = {} export type SearchSchemaInput = { __TSearchSchemaInput__: 'TSearchSchemaInput' } export type AnyContext = {} export interface RouteContext {} export type PreloadableObj = { preload?: () => Promise<void> } export type RoutePathOptions<TCustomId, TPath> = | { path: TPath } | { id: TCustomId } export interface StaticDataRouteOption {} export type RoutePathOptionsIntersection<TCustomId, TPath> = { path: TPath id: TCustomId } export type SearchFilter<TInput, TResult = TInput> = (prev: TInput) => TResult export type SearchMiddlewareContext<TSearchSchema> = { search: TSearchSchema next: (newSearch: TSearchSchema) => TSearchSchema } export type SearchMiddleware<TSearchSchema> = ( ctx: SearchMiddlewareContext<TSearchSchema>, ) => TSearchSchema export type ResolveId< TParentRoute, TCustomId extends string, TPath extends string, > = TParentRoute extends { id: infer TParentId extends string } ? RoutePrefix<TParentId, string extends TCustomId ? TPath : TCustomId> : RootRouteId export type InferFullSearchSchema<TRoute> = TRoute extends { types: { fullSearchSchema: infer TFullSearchSchema } } ? TFullSearchSchema : {} export type InferFullSearchSchemaInput<TRoute> = TRoute extends { types: { fullSearchSchemaInput: infer TFullSearchSchemaInput } } ? TFullSearchSchemaInput : {} export type InferAllParams<TRoute> = TRoute extends { types: { allParams: infer TAllParams } } ? TAllParams : {} export type InferAllContext<TRoute> = unknown extends TRoute ? TRoute : TRoute extends { types: { allContext: infer TAllContext } } ? TAllContext : {} export type ResolveSearchSchemaFnInput<TSearchValidator> = TSearchValidator extends (input: infer TSearchSchemaInput) => any ? TSearchSchemaInput extends SearchSchemaInput ? Omit<TSearchSchemaInput, keyof SearchSchemaInput> : ResolveSearchSchemaFn<TSearchValidator> : AnySchema export type ResolveSearchSchemaInput<TSearchValidator> = TSearchValidator extends AnyStandardSchemaValidator ? NonNullable<TSearchValidator['~standard']['types']>['input'] : TSearchValidator extends AnyValidatorAdapter ? TSearchValidator['types']['input'] : TSearchValidator extends AnyValidatorObj ? ResolveSearchSchemaFnInput<TSearchValidator['parse']> : ResolveSearchSchemaFnInput<TSearchValidator> export type ResolveSearchSchemaFn<TSearchValidator> = TSearchValidator extends ( ...args: any ) => infer TSearchSchema ? TSearchSchema : AnySchema export type ResolveSearchSchema<TSearchValidator> = unknown extends TSearchValidator ? TSearchValidator : TSearchValidator extends AnyStandardSchemaValidator ? NonNullable<TSearchValidator['~standard']['types']>['output'] : TSearchValidator extends AnyValidatorAdapter ? TSearchValidator['types']['output'] : TSearchValidator extends AnyValidatorObj ? ResolveSearchSchemaFn<TSearchValidator['parse']> : ResolveSearchSchemaFn<TSearchValidator> export type ResolveRequiredParams<TPath extends string, T> = { [K in ParsePathParams<TPath>['required']]: T } export type ResolveOptionalParams<TPath extends string, T> = { [K in ParsePathParams<TPath>['optional']]?: T | undefined } export type ResolveParams< TPath extends string, T = string, > = ResolveRequiredParams<TPath, T> & ResolveOptionalParams<TPath, T> export type ParseParamsFn<in out TPath extends string, in out TParams> = ( rawParams: Expand<ResolveParams<TPath>>, ) => TParams extends ResolveParams<TPath, any> ? TParams : ResolveParams<TPath, any> export type StringifyParamsFn<in out TPath extends string, in out TParams> = ( params: TParams, ) => ResolveParams<TPath> export type ParamsOptions<in out TPath extends string, in out TParams> = { params?: { parse?: ParseParamsFn<TPath, TParams> stringify?: StringifyParamsFn<TPath, TParams> } /** @deprecated Use params.parse instead */ parseParams?: ParseParamsFn<TPath, TParams> /** @deprecated Use params.stringify instead */ stringifyParams?: StringifyParamsFn<TPath, TParams> } interface RequiredStaticDataRouteOption { staticData: StaticDataRouteOption } interface OptionalStaticDataRouteOption { staticData?: StaticDataRouteOption } export type UpdatableStaticRouteOption = {} extends StaticDataRouteOption ? OptionalStaticDataRouteOption : RequiredStaticDataRouteOption export type MetaDescriptor = | { charSet: 'utf-8' } | { title: string } | { name: string; content: string } | { property: string; content: string } | { httpEquiv: string; content: string } | { 'script:ld+json': LdJsonObject } | { tagName: 'meta' | 'link'; [name: string]: string } | Record<string, unknown> type LdJsonObject = { [Key in string]: LdJsonValue } & { [Key in string]?: LdJsonValue | undefined } type LdJsonArray = Array<LdJsonValue> | ReadonlyArray<LdJsonValue> type LdJsonPrimitive = string | number | boolean | null type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray export type RouteLinkEntry = {} export type SearchValidator<TInput, TOutput> = | ValidatorObj<TInput, TOutput> | ValidatorFn<TInput, TOutput> | ValidatorAdapter<TInput, TOutput> | StandardSchemaValidator<TInput, TOutput> | undefined export type AnySearchValidator = SearchValidator<any, any> export type DefaultSearchValidator = SearchValidator< Record<string, unknown>, AnySchema > export type RoutePrefix< TPrefix extends string, TPath extends string, > = string extends TPath ? RootRouteId : TPath extends string ? TPrefix extends RootRouteId ? TPath extends '/' ? '/' : `/${TrimPath<TPath>}` : `${TPrefix}/${TPath}` extends '/' ? '/' : `/${TrimPathLeft<`${TrimPathRight<TPrefix>}/${TrimPath<TPath>}`>}` : never export type TrimPath<T extends string> = '' extends T ? '' : TrimPathRight<TrimPathLeft<T>> export type TrimPathLeft<T extends string> = T extends `${RootRouteId}/${infer U}` ? TrimPathLeft<U> : T extends `/${infer U}` ? TrimPathLeft<U> : T export type TrimPathRight<T extends string> = T extends '/' ? '/' : T extends `${infer U}/` ? TrimPathRight<U> : T export type ContextReturnType<TContextFn> = unknown extends TContextFn ? TContextFn : LooseReturnType<TContextFn> extends never ? AnyContext : LooseReturnType<TContextFn> export type ContextAsyncReturnType<TContextFn> = unknown extends TContextFn ? TContextFn : LooseAsyncReturnType<TContextFn> extends never ? AnyContext : LooseAsyncReturnType<TContextFn> export type ResolveRouteContext<TRouteContextFn, TBeforeLoadFn> = Assign< ContextReturnType<TRouteContextFn>, ContextAsyncReturnType<TBeforeLoadFn> > export type ResolveRouteLoaderFn<TLoaderFn> = TLoaderFn extends { handler: infer THandler } ? THandler : TLoaderFn export type RouteLoaderObject< TRegister, TParentRoute extends AnyRoute = AnyRoute, TId extends string = string, TParams = {}, TLoaderDeps = {}, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TServerMiddlewares = unknown, THandlers = undefined, > = { handler: RouteLoaderFn< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers > staleReloadMode?: LoaderStaleReloadMode } export type ResolveLoaderData<TLoaderFn> = unknown extends TLoaderFn ? TLoaderFn : LooseAsyncReturnType<ResolveRouteLoaderFn<TLoaderFn>> extends never ? undefined : LooseAsyncReturnType<ResolveRouteLoaderFn<TLoaderFn>> export type ResolveFullSearchSchema< TParentRoute extends AnyRoute, TSearchValidator, > = unknown extends TParentRoute ? ResolveValidatorOutput<TSearchValidator> : IntersectAssign< InferFullSearchSchema<TParentRoute>, ResolveValidatorOutput<TSearchValidator> > export type ResolveFullSearchSchemaInput< TParentRoute extends AnyRoute, TSearchValidator, > = IntersectAssign< InferFullSearchSchemaInput<TParentRoute>, ResolveSearchValidatorInput<TSearchValidator> > export type ResolveAllParamsFromParent< TParentRoute extends AnyRoute, TParams, > = Assign<InferAllParams<TParentRoute>, TParams> export type RouteContextParameter< TParentRoute extends AnyRoute, TRouterContext, > = unknown extends TParentRoute ? TRouterContext : Assign<TRouterContext, InferAllContext<TParentRoute>> export type BeforeLoadContextParameter< TParentRoute extends AnyRoute, TRouterContext, TRouteContextFn, > = Assign< RouteContextParameter<TParentRoute, TRouterContext>, ContextReturnType<TRouteContextFn> > export type ResolveAllContext< TParentRoute extends AnyRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn, > = Assign< BeforeLoadContextParameter<TParentRoute, TRouterContext, TRouteContextFn>, ContextAsyncReturnType<TBeforeLoadFn> > export interface FullSearchSchemaOption< in out TParentRoute extends AnyRoute, in out TSearchValidator, > { search: Expand<ResolveFullSearchSchema<TParentRoute, TSearchValidator>> } export interface RemountDepsOptions< in out TRouteId, in out TFullSearchSchema, in out TAllParams, in out TLoaderDeps, > { routeId: TRouteId search: TFullSearchSchema params: TAllParams loaderDeps: TLoaderDeps } export type MakeRemountDepsOptionsUnion< TRouteTree extends AnyRoute = RegisteredRouter['routeTree'], > = ParseRoute<TRouteTree> extends infer TRoute extends AnyRoute ? TRoute extends any ? RemountDepsOptions< TRoute['id'], TRoute['types']['fullSearchSchema'], TRoute['types']['allParams'], TRoute['types']['loaderDeps'] > : never : never export interface RouteTypes< in out TRegister, in out TParentRoute extends AnyRoute, in out TPath extends string, in out TFullPath extends string, in out TCustomId extends string, in out TId extends string, in out TSearchValidator, in out TParams, in out TRouterContext, in out TRouteContextFn, in out TBeforeLoadFn, in out TLoaderDeps, in out TLoaderFn, in out TChildren, in out TFileRouteTypes, in out TSSR, in out TServerMiddlewares, in out THandlers, > { parentRoute: TParentRoute path: TPath to: TrimPathRight<TFullPath> fullPath: TFullPath customId: TCustomId id: TId searchSchema: ResolveValidatorOutput<TSearchValidator> searchSchemaInput: ResolveSearchValidatorInput<TSearchValidator> searchValidator: TSearchValidator fullSearchSchema: ResolveFullSearchSchema<TParentRoute, TSearchValidator> fullSearchSchemaInput: ResolveFullSearchSchemaInput< TParentRoute, TSearchValidator > params: TParams allParams: ResolveAllParamsFromParent<TParentRoute, TParams> routerContext: TRouterContext routeContext: ResolveRouteContext<TRouteContextFn, TBeforeLoadFn> routeContextFn: TRouteContextFn beforeLoadFn: TBeforeLoadFn allContext: ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn > children: TChildren loaderData: ResolveLoaderData<TLoaderFn> loaderDeps: TLoaderDeps fileRouteTypes: TFileRouteTypes ssr: ResolveSSR<TSSR> allSsr: ResolveAllSSR<TParentRoute, TSSR> } export type ResolveSSR<TSSR> = TSSR extends (...args: ReadonlyArray<any>) => any ? LooseReturnType<TSSR> : TSSR export type ResolveAllSSR< TParentRoute extends AnyRoute, TSSR, > = unknown extends TParentRoute ? ResolveSSR<TSSR> : unknown extends TSSR ? TParentRoute['types']['allSsr'] : ResolveSSR<TSSR> export type ResolveFullPath< TParentRoute extends AnyRoute, TPath extends string, TPrefixed = RoutePrefix<TParentRoute['fullPath'], TPath>, > = TPrefixed extends RootRouteId ? '/' : TPrefixed export interface RouteExtensions<in out TId, in out TFullPath> { id: TId fullPath: TFullPath } export type RouteLazyFn<TRoute extends AnyRoute> = ( lazyFn: () => Promise<LazyRoute<TRoute>>, ) => TRoute export type RouteAddChildrenFn< in out TRegister, in out TParentRoute extends AnyRoute, in out TPath extends string, in out TFullPath extends string, in out TCustomId extends string, in out TId extends string, in out TSearchValidator, in out TParams, in out TRouterContext, in out TRouteContextFn, in out TBeforeLoadFn, in out TLoaderDeps extends Record<string, any>, in out TLoaderFn, in out TFileRouteTypes, in out TSSR, in out TServerMiddlewares, in out THandlers, > = <const TNewChildren>( children: Constrain< TNewChildren, ReadonlyArray<AnyRoute> | Record<string, AnyRoute> >, ) => Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TNewChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > export type RouteAddFileChildrenFn< in out TRegister, in out TParentRoute extends AnyRoute, in out TPath extends string, in out TFullPath extends string, in out TCustomId extends string, in out TId extends string, in out TSearchValidator, in out TParams, in out TRouterContext, in out TRouteContextFn, in out TBeforeLoadFn, in out TLoaderDeps extends Record<string, any>, in out TLoaderFn, in out TFileRouteTypes, in out TSSR, in out TServerMiddlewares, in out THandlers, > = <const TNewChildren>( children: TNewChildren, ) => Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TNewChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > export type RouteAddFileTypesFn< TRegister, TParentRoute extends AnyRoute, TPath extends string, TFullPath extends string, TCustomId extends string, TId extends string, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps extends Record<string, any>, TLoaderFn, TChildren, TSSR, TServerMiddlewares, THandlers, > = <TNewFileRouteTypes>() => Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TNewFileRouteTypes, TSSR, TServerMiddlewares, THandlers > export interface Route< in out TRegister, in out TParentRoute extends AnyRoute, in out TPath extends string, in out TFullPath extends string, in out TCustomId extends string, in out TId extends string, in out TSearchValidator, in out TParams, in out TRouterContext, in out TRouteContextFn, in out TBeforeLoadFn, in out TLoaderDeps extends Record<string, any>, in out TLoaderFn, in out TChildren, in out TFileRouteTypes, in out TSSR, in out TServerMiddlewares, in out THandlers, > extends RouteExtensions<TId, TFullPath> { path: TPath parentRoute: TParentRoute children?: TChildren types: RouteTypes< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > options: RouteOptions< TRegister, TParentRoute, TId, TCustomId, TFullPath, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TSSR, TServerMiddlewares, THandlers > isRoot: TParentRoute extends AnyRoute ? true : false /** @internal */ _componentsPromise?: Promise<void> /** @internal */ _componentsLoaded?: boolean lazyFn?: () => Promise< LazyRoute< Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > > > /** @internal */ _lazyPromise?: Promise<void> /** @internal */ _lazyLoaded?: boolean rank: number to: TrimPathRight<TFullPath> init: (opts: { originalIndex: number }) => void update: ( options: UpdatableRouteOptions< TParentRoute, TCustomId, TFullPath, TParams, TSearchValidator, TLoaderFn, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn >, ) => this lazy: RouteLazyFn< Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > > addChildren: RouteAddChildrenFn< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > _addFileChildren: RouteAddFileChildrenFn< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > _addFileTypes: RouteAddFileTypesFn< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TSSR, TServerMiddlewares, THandlers > /** * Create a redirect with `from` automatically set to this route's path. * Enables relative redirects like `Route.redirect({ to: './overview' })`. * @param opts Redirect options (same as `redirect()` but without `from`) * @returns A redirect Response that can be thrown from loaders/beforeLoad * @link https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction */ redirect: RedirectFnRoute<TFullPath> } export type AnyRoute = Route< any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any > export type AnyRouteWithContext<TContext> = AnyRoute & { types: { allContext: TContext } } export type RouteOptions< TRegister, TParentRoute extends AnyRoute = AnyRoute, TId extends string = string, TCustomId extends string = string, TFullPath extends string = string, TPath extends string = string, TSearchValidator = undefined, TParams = AnyPathParams, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TSSR = unknown, TServerMiddlewares = unknown, THandlers = undefined, > = BaseRouteOptions< TRegister, TParentRoute, TId, TCustomId, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TSSR, TServerMiddlewares, THandlers > & UpdatableRouteOptions< NoInfer<TParentRoute>, NoInfer<TCustomId>, NoInfer<TFullPath>, NoInfer<TParams>, NoInfer<TSearchValidator>, NoInfer<TLoaderFn>, NoInfer<TLoaderDeps>, NoInfer<TRouterContext>, NoInfer<TRouteContextFn>, NoInfer<TBeforeLoadFn> > export type RouteContextFn< in out TParentRoute extends AnyRoute, in out TSearchValidator, in out TParams, in out TRouterContext, in out TRouteId, > = ( ctx: RouteContextOptions< TParentRoute, TSearchValidator, TParams, TRouterContext, TRouteId >, ) => any export type FileBaseRouteOptions< TRegister, TParentRoute extends AnyRoute = AnyRoute, TId extends string = string, TPath extends string = string, TSearchValidator = undefined, TParams = {}, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TRemountDepsFn = AnyContext, TSSR = unknown, TServerMiddlewares = unknown, THandlers = undefined, > = ParamsOptions<TPath, TParams> & FilebaseRouteOptionsInterface< TRegister, TParentRoute, TId, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TRemountDepsFn, TSSR, TServerMiddlewares, THandlers > export interface FilebaseRouteOptionsInterface< TRegister, TParentRoute extends AnyRoute = AnyRoute, TId extends string = string, TPath extends string = string, TSearchValidator = undefined, TParams = {}, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TRemountDepsFn = AnyContext, TSSR = unknown, TServerMiddlewares = unknown, THandlers = undefined, > { validateSearch?: Constrain<TSearchValidator, AnyValidator, DefaultValidator> shouldReload?: | boolean | (( match: LoaderFnContext< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers >, ) => any) context?: Constrain< TRouteContextFn, ( ctx: RouteContextOptions< TParentRoute, TParams, TRouterContext, TLoaderDeps, TId >, ) => any > ssr?: Constrain< TSSR, | undefined | SSROption | (( ctx: SsrContextOptions<TParentRoute, TSearchValidator, TParams>, ) => Awaitable<undefined | SSROption>) > // This async function is called before a route is loaded. // If an error is thrown here, the route's loader will not be called. // If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onError` function. // If thrown during a preload event, the error will be logged to the console. beforeLoad?: Constrain< TBeforeLoadFn, ( ctx: BeforeLoadContextOptions< TRegister, TParentRoute, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TId, TServerMiddlewares, THandlers >, ) => ValidateSerializableLifecycleResult< TRegister, TParentRoute, TSSR, TBeforeLoadFn > > loaderDeps?: ( opts: FullSearchSchemaOption<TParentRoute, TSearchValidator>, ) => TLoaderDeps remountDeps?: Constrain< TRemountDepsFn, ( opt: RemountDepsOptions< TId, ResolveFullSearchSchema<TParentRoute, TSearchValidator>, Expand<ResolveAllParamsFromParent<TParentRoute, TParams>>, TLoaderDeps >, ) => any > loader?: Constrain< TLoaderFn, | RouteLoaderFn< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers > | RouteLoaderObject< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers > > } export type BaseRouteOptions< TRegister, TParentRoute extends AnyRoute = AnyRoute, TId extends string = string, TCustomId extends string = string, TPath extends string = string, TSearchValidator = undefined, TParams = {}, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TSSR = unknown, TServerMiddlewares = unknown, THandlers = undefined, > = RoutePathOptions<TCustomId, TPath> & FileBaseRouteOptions< TRegister, TParentRoute, TId, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, AnyContext, TSSR, TServerMiddlewares, THandlers > & { getParentRoute: () => TParentRoute } export interface ContextOptions< in out TParentRoute extends AnyRoute, in out TParams, in out TRouteId, > { abortController: AbortController preload: boolean params: Expand<ResolveAllParamsFromParent<TParentRoute, TParams>> location: ParsedLocation /** * @deprecated Use `throw redirect({ to: '/somewhere' })` instead **/ navigate: NavigateFn buildLocation: BuildLocationFn cause: 'preload' | 'enter' | 'stay' matches: Array<MakeRouteMatchUnion> routeId: TRouteId } export interface RouteContextOptions< in out TParentRoute extends AnyRoute, in out TParams, in out TRouterContext, in out TLoaderDeps, in out TRouteId, > extends ContextOptions<TParentRoute, TParams, TRouteId> { deps: TLoaderDeps context: Expand<RouteContextParameter<TParentRoute, TRouterContext>> } export interface SsrContextOptions< in out TParentRoute extends AnyRoute, in out TSearchValidator, in out TParams, > { params: | { status: 'success' value: Expand<ResolveAllParamsFromParent<TParentRoute, TParams>> } | { status: 'error'; error: unknown } search: | { status: 'success' value: Expand<ResolveFullSearchSchema<TParentRoute, TSearchValidator>> } | { status: 'error'; error: unknown } location: ParsedLocation matches: Array<MakePreValidationErrorHandlingRouteMatchUnion> } export interface BeforeLoadContextOptions< in out TRegister, in out TParentRoute extends AnyRoute, in out TSearchValidator, in out TParams, in out TRouterContext, in out TRouteContextFn, in out TRouteId, in out TServerMiddlewares, in out THandlers, > extends ContextOptions<TParentRoute, TParams, TRouteId>, FullSearchSchemaOption<TParentRoute, TSearchValidator> { context: Expand< BeforeLoadContextParameter<TParentRoute, TRouterContext, TRouteContextFn> > } type AssetFnContextOptions< in out TRouteId, in out TFullPath, in out TParentRoute extends AnyRoute, in out TParams, in out TSearchValidator, in out TLoaderFn, in out TRouterContext, in out TRouteContextFn, in out TBeforeLoadFn, in out TLoaderDeps, > = { ssr?: { nonce?: string } matches: Array< RouteMatch< TRouteId, TFullPath, ResolveAllParamsFromParent<TParentRoute, TParams>, ResolveFullSearchSchema<TParentRoute, TSearchValidator>, ResolveLoaderData<TLoaderFn>, ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn >, TLoaderDeps > > match: RouteMatch< TRouteId, TFullPath, ResolveAllParamsFromParent<TParentRoute, TParams>, ResolveFullSearchSchema<TParentRoute, TSearchValidator>, ResolveLoaderData<TLoaderFn>, ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn >, TLoaderDeps > params: ResolveAllParamsFromParent<TParentRoute, TParams> loaderData?: ResolveLoaderData<TLoaderFn> } export interface DefaultUpdatableRouteOptionsExtensions { component?: unknown errorComponent?: unknown notFoundComponent?: unknown pendingComponent?: unknown } export interface UpdatableRouteOptionsExtensions extends DefaultUpdatableRouteOptionsExtensions {} export interface UpdatableRouteOptions< in out TParentRoute extends AnyRoute, in out TRouteId, in out TFullPath, in out TParams, in out TSearchValidator, in out TLoaderFn, in out TLoaderDeps, in out TRouterContext, in out TRouteContextFn, in out TBeforeLoadFn, > extends UpdatableStaticRouteOption, UpdatableRouteOptionsExtensions { /** * Options to control route matching behavior with runtime code. * * @experimental 🚧 this feature is subject to change * * @link https://tanstack.com/router/latest/docs/framework/react/api/router/RouteOptionsType */ skipRouteOnParseError?: { /** * If `true`, skip this route during matching if `params.parse` fails. * * Without this option, a `/$param` route could match *any* value for `param`, * and only later during the route lifecycle would `params.parse` run and potentially * show the `errorComponent` if validation failed. * * With this option enabled, the route will only match if `params.parse` succeeds. * If it fails, the router will continue trying to match other routes, potentially * finding a different route that works, or ultimately showing the `notFoundComponent`. * * @default false */ params?: boolean /** * In cases where multiple routes would need to run `params.parse` during matching * to determine which route to pick, this priority number can be used as a tie-breaker * for which route to try first. Higher number = higher priority. * * @default 0 */ priority?: number } /** * If true, this route will be matched as case-sensitive * * @default false */ caseSensitive?: boolean /** * If true, this route will be forcefully wrapped in a suspense boundary */ wrapInSuspense?: boolean // The content to be rendered when the route is matched. If no component is provided, defaults to `<Outlet />` pendingMs?: number pendingMinMs?: number staleTime?: number gcTime?: number preload?: boolean preloadStaleTime?: number preloadGcTime?: number search?: { middlewares?: Array< SearchMiddleware< ResolveFullSearchSchemaInput<TParentRoute, TSearchValidator> > > } /** @deprecated Use search.middlewares instead */ preSearchFilters?: Array< SearchFilter<ResolveFullSearchSchema<TParentRoute, TSearchValidator>> > /** @deprecated Use search.middlewares instead */ postSearchFilters?: Array< SearchFilter<ResolveFullSearchSchema<TParentRoute, TSearchValidator>> > onCatch?: (error: Error) => void onError?: (err: any) => void // These functions are called as route matches are loaded, stick around and leave the active // matches onEnter?: ( match: RouteMatch< TRouteId, TFullPath, ResolveAllParamsFromParent<TParentRoute, TParams>, ResolveFullSearchSchema<TParentRoute, TSearchValidator>, ResolveLoaderData<TLoaderFn>, ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn >, TLoaderDeps >, ) => void onStay?: ( match: RouteMatch< TRouteId, TFullPath, ResolveAllParamsFromParent<TParentRoute, TParams>, ResolveFullSearchSchema<TParentRoute, TSearchValidator>, ResolveLoaderData<TLoaderFn>, ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn >, TLoaderDeps >, ) => void onLeave?: ( match: RouteMatch< TRouteId, TFullPath, ResolveAllParamsFromParent<TParentRoute, TParams>, ResolveFullSearchSchema<TParentRoute, TSearchValidator>, ResolveLoaderData<TLoaderFn>, ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn >, TLoaderDeps >, ) => void headers?: ( ctx: AssetFnContextOptions< TRouteId, TFullPath, TParentRoute, TParams, TSearchValidator, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps >, ) => Awaitable<Record<string, string> | undefined> head?: ( ctx: AssetFnContextOptions< TRouteId, TFullPath, TParentRoute, TParams, TSearchValidator, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps >, ) => Awaitable<{ links?: AnyRouteMatch['links'] scripts?: AnyRouteMatch['headScripts'] meta?: AnyRouteMatch['meta'] styles?: AnyRouteMatch['styles'] }> scripts?: ( ctx: AssetFnContextOptions< TRouteId, TFullPath, TParentRoute, TParams, TSearchValidator, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps >, ) => Awaitable<AnyRouteMatch['scripts']> codeSplitGroupings?: Array< Array< | 'loader' | 'component' | 'pendingComponent' | 'notFoundComponent' | 'errorComponent' > > } export type RouteLoaderFn< in out TRegister, in out TParentRoute extends AnyRoute = AnyRoute, in out TId extends string = string, in out TParams = {}, in out TLoaderDeps = {}, in out TRouterContext = {}, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TServerMiddlewares = unknown, in out THandlers = undefined, > = ( match: LoaderFnContext< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers >, ) => any export type LoaderStaleReloadMode = 'background' | 'blocking' export type RouteLoaderEntry< TRegister, TParentRoute extends AnyRoute = AnyRoute, TId extends string = string, TParams = {}, TLoaderDeps = {}, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TServerMiddlewares = unknown, THandlers = undefined, > = | RouteLoaderFn< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers > | RouteLoaderObject< TRegister, TParentRoute, TId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn, TServerMiddlewares, THandlers > export interface LoaderFnContext< in out TRegister = unknown, in out TParentRoute extends AnyRoute = AnyRoute, in out TId extends string = string, in out TParams = {}, in out TLoaderDeps = {}, in out TRouterContext = {}, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TServerMiddlewares = unknown, in out THandlers = undefined, > { abortController: AbortController preload: boolean params: Expand<ResolveAllParamsFromParent<TParentRoute, TParams>> deps: TLoaderDeps context: Expand< ResolveAllContext< TParentRoute, TRouterContext, TRouteContextFn, TBeforeLoadFn > > location: ParsedLocation // Do not supply search schema here so as to demotivate people from trying to shortcut loaderDeps /** * @deprecated Use `throw redirect({ to: '/somewhere' })` instead **/ navigate: (opts: NavigateOptions<AnyRouter>) => Promise<void> | void // root route does not have a parent match parentMatchPromise: TId extends RootRouteId ? never : Promise<MakeRouteMatchFromRoute<TParentRoute>> cause: 'preload' | 'enter' | 'stay' route: AnyRoute } export interface DefaultRootRouteOptionsExtensions { shellComponent?: unknown } export interface RootRouteOptionsExtensions extends DefaultRootRouteOptionsExtensions {} export interface RootRouteOptions< TRegister = unknown, TSearchValidator = undefined, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TSSR = unknown, TServerMiddlewares = unknown, THandlers = undefined, > extends Omit< RouteOptions< TRegister, any, // TParentRoute RootRouteId, // TId RootRouteId, // TCustomId '', // TFullPath '', // TPath TSearchValidator, {}, // TParams TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TSSR, TServerMiddlewares, THandlers >, | 'path' | 'id' | 'getParentRoute' | 'caseSensitive' | 'parseParams' | 'stringifyParams' | 'params' >, RootRouteOptionsExtensions {} export type RouteConstraints = { TParentRoute: AnyRoute TPath: string TFullPath: string TCustomId: string TId: string TSearchSchema: AnySchema TFullSearchSchema: AnySchema TParams: Record<string, any> TAllParams: Record<string, any> TParentContext: AnyContext TRouteContext: RouteContext TAllContext: AnyContext TRouterContext: AnyContext TChildren: unknown TRouteTree: AnyRoute } export type RouteTypesById<TRouter extends AnyRouter, TId> = RouteById< TRouter['routeTree'], TId >['types'] export type RouteMask<TRouteTree extends AnyRoute> = { routeTree: TRouteTree from: RoutePaths<TRouteTree> to?: any params?: any search?: any hash?: any state?: any unmaskOnReload?: boolean } /** * @deprecated Use `ErrorComponentProps` instead. */ export type ErrorRouteProps = { error: unknown info?: { componentStack: string } reset: () => void } export type ErrorComponentProps<TError = Error> = { error: TError info?: { componentStack: string } reset: () => void } export type NotFoundRouteProps = { data?: unknown isNotFound: boolean routeId: RouteIds<RegisteredRouter['routeTree']> } export class BaseRoute< in out TRegister = Register, in out TParentRoute extends AnyRoute = AnyRoute, in out TPath extends string = '/', in out TFullPath extends string = ResolveFullPath<TParentRoute, TPath>, in out TCustomId extends string = string, in out TId extends string = ResolveId<TParentRoute, TCustomId, TPath>, in out TSearchValidator = undefined, in out TParams = ResolveParams<TPath>, in out TRouterContext = AnyContext, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TLoaderDeps extends Record<string, any> = {}, in out TLoaderFn = undefined, in out TChildren = unknown, in out TFileRouteTypes = unknown, in out TSSR = unknown, in out TServerMiddlewares = unknown, in out THandlers = undefined, > { isRoot: TParentRoute extends AnyRoute ? true : false options: RouteOptions< TRegister, TParentRoute, TId, TCustomId, TFullPath, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TSSR, TServerMiddlewares, THandlers > // The following properties are set up in this.init() parentRoute!: TParentRoute private _id!: TId private _path!: TPath private _fullPath!: TFullPath private _to!: TrimPathRight<TFullPath> public get to() { return this._to } public get id() { return this._id } public get path() { return this._path } public get fullPath() { return this._fullPath } // Optional children?: TChildren originalIndex?: number rank!: number lazyFn?: () => Promise< LazyRoute< Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > > > /** @internal */ _lazyPromise?: Promise<void> /** @internal */ _componentsPromise?: Promise<void> constructor( options?: RouteOptions< TRegister, TParentRoute, TId, TCustomId, TFullPath, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TSSR, TServerMiddlewares, THandlers >, ) { this.options = (options as any) || {} this.isRoot = !options?.getParentRoute as any if ((options as any)?.id && (options as any)?.path) { throw new Error(`Route cannot have both an 'id' and a 'path' option.`) } } types!: RouteTypes< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > init = (opts: { originalIndex: number }): void => { this.originalIndex = opts.originalIndex const options = this.options as | (RouteOptions< TRegister, TParentRoute, TId, TCustomId, TFullPath, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn, TSSR, TServerMiddlewares > & RoutePathOptionsIntersection<TCustomId, TPath>) | undefined const isRoot = !options?.path && !options?.id this.parentRoute = this.options.getParentRoute?.() if (isRoot) { this._path = rootRouteId as TPath } else if (!this.parentRoute) { invariant( false, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`, ) } let path: undefined | string = isRoot ? rootRouteId : options?.path // If the path is anything other than an index path, trim it up if (path && path !== '/') { path = trimPathLeft(path) } const customId = options?.id || path // Strip the parentId prefix from the first level of children let id = isRoot ? rootRouteId : joinPaths([ this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId, ]) if (path === rootRouteId) { path = '/' } if (id !== rootRouteId) { id = joinPaths(['/', id]) } const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]) this._path = path as TPath this._id = id as TId this._fullPath = fullPath as TFullPath this._to = trimPathRight(fullPath) as TrimPathRight<TFullPath> } addChildren: RouteAddChildrenFn< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > = (children) => { return this._addFileChildren(children) as any } _addFileChildren: RouteAddFileChildrenFn< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > = (children) => { if (Array.isArray(children)) { this.children = children as TChildren } if (typeof children === 'object' && children !== null) { this.children = Object.values(children) as TChildren } return this as any } _addFileTypes: RouteAddFileTypesFn< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TSSR, TServerMiddlewares, THandlers > = () => { return this as any } updateLoader = <TNewLoaderFn>(options: { loader: Constrain< TNewLoaderFn, RouteLoaderFn< TRegister, TParentRoute, TCustomId, TParams, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn > > }) => { Object.assign(this.options, options) return this as unknown as BaseRoute< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TNewLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > } update = ( options: UpdatableRouteOptions< TParentRoute, TCustomId, TFullPath, TParams, TSearchValidator, TLoaderFn, TLoaderDeps, TRouterContext, TRouteContextFn, TBeforeLoadFn >, ): this => { Object.assign(this.options, options) return this } lazy: RouteLazyFn< Route< TRegister, TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > > = (lazyFn) => { this.lazyFn = lazyFn return this } /** * Create a redirect with `from` automatically set to this route's fullPath. * Enables relative redirects like `Route.redirect({ to: './overview' })`. * @param opts Redirect options (same as `redirect()` but without `from`) * @returns A redirect Response that can be thrown from loaders/beforeLoad * @link https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction */ redirect: RedirectFnRoute<TFullPath> = (opts) => redirect({ from: this.fullPath, ...opts } as any) } export class BaseRouteApi<TId, TRouter extends AnyRouter = RegisteredRouter> { id: TId constructor({ id }: { id: TId }) { this.id = id } notFound = (opts?: NotFoundError) => { return notFound({ routeId: this.id as string, ...opts }) } /** * Create a redirect with `from` automatically set to this route's path. * Enables relative redirects like `routeApi.redirect({ to: './overview' })`. * @param opts Redirect options (same as `redirect()` but without `from`) * @returns A redirect Response that can be thrown from loaders/beforeLoad * @link https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction */ redirect: RedirectFnRoute<RouteTypesById<TRouter, TId>['fullPath']> = ( opts, ) => redirect({ from: this.id as string, ...opts } as any) } export interface RootRoute< in out TRegister, in out TSearchValidator = undefined, in out TRouterContext = {}, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TLoaderDeps extends Record<string, any> = {}, in out TLoaderFn = undefined, in out TChildren = unknown, in out TFileRouteTypes = unknown, in out TSSR = unknown, in out TServerMiddlewares = unknown, in out THandlers = undefined, > extends Route< TRegister, any, // TParentRoute '/', // TPath '/', // TFullPath string, // TCustomId RootRouteId, // TId TSearchValidator, // TSearchValidator {}, // TParams TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, // TChildren TFileRouteTypes, TSSR, TServerMiddlewares, THandlers > {} export class BaseRootRoute< in out TRegister = Register, in out TSearchValidator = undefined, in out TRouterContext = {}, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TLoaderDeps extends Record<string, any> = {}, in out TLoaderFn = undefined, in out TChildren = unknown, in out TFileRouteTypes = unknown, in out TSSR = unknown, in out TServerMiddlewares = unknown, in out THandlers = undefined, > extends BaseRoute< TRegister, any, // TParentRoute '/', // TPath '/', // TFullPath string, // TCustomId RootRouteId, // TId TSearchValidator, // TSearchValidator {}, // TParams TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, // TChildren TFileRouteTypes, TSS