UNPKG

@tanstack/router-core

Version:

Modern and scalable routing for React applications

1 lines 116 kB
{"version":3,"file":"router.cjs","names":[],"sources":["../../src/router.ts"],"sourcesContent":["import { createBrowserHistory, parseHref } from '@tanstack/history'\nimport { isServer, loadServerRoute } from '@tanstack/router-core/isServer'\nimport {\n DEFAULT_PROTOCOL_ALLOWLIST,\n decodePath,\n deepEqual,\n encodePathLikeUrl,\n findLast,\n functionalUpdate,\n hasKeys,\n isDangerousProtocol,\n last,\n nullReplaceEqualDeep,\n replaceEqualDeep,\n} from './utils'\nimport {\n buildRouteBranch,\n findFlatMatch,\n findRouteMatch,\n findSingleMatch,\n processRouteMasks,\n processRouteTree,\n} from './new-process-route-tree'\nimport {\n cleanPath,\n compileDecodeCharMap,\n interpolatePath,\n resolvePath,\n trimPath,\n trimPathRight,\n} from './path'\nimport { createLRUCache } from './lru-cache'\nimport { isNotFound } from './not-found'\nimport { setupScrollRestoration } from './scroll-restoration'\nimport { defaultParseSearch, defaultStringifySearch } from './searchParams'\nimport { rootRouteId } from './root'\nimport { isRedirect } from './redirect'\nimport {\n loadClientRoute,\n loadRouteChunk,\n preloadClientRoute,\n refreshClientRoute,\n replaceRouteChunk,\n transferMatchResources,\n} from './load-client'\nimport {\n composeRewrites,\n executeRewriteInput,\n executeRewriteOutput,\n rewriteBasepath,\n} from './rewrite'\nimport { createRouterStores } from './stores'\nimport type { LRUCache } from './lru-cache'\nimport type {\n ProcessRouteTreeResult,\n ProcessedTree,\n} from './new-process-route-tree'\nimport type { SearchParser, SearchSerializer } from './searchParams'\nimport type { AnyRedirect, ResolvedRedirect } from './redirect'\nimport type {\n ActivePreload,\n LoadTransaction,\n LoaderFlight,\n PendingSession,\n} from './load-client'\nimport type { ServerLoadResult } from './load-server'\nimport type {\n HistoryAction,\n HistoryLocation,\n HistoryState,\n ParsedHistoryState,\n RouterHistory,\n} from '@tanstack/history'\n\nimport type {\n Awaitable,\n Constrain,\n NoInfer,\n NonNullableUpdater,\n PickAsRequired,\n Updater,\n} from './utils'\nimport type { ParsedLocation } from './location'\nimport type {\n AnyContext,\n AnyRoute,\n AnyRouteWithContext,\n LoaderStaleReloadMode,\n MakeRemountDepsOptionsUnion,\n RouteMask,\n SearchMiddleware,\n SearchMiddlewareMeta,\n} from './route'\nimport type {\n FullSearchSchema,\n RouteById,\n RoutePaths,\n RoutesById,\n RoutesByPath,\n} from './routeInfo'\nimport type {\n AnyRouteMatch,\n MakeRouteMatch,\n MakeRouteMatchUnion,\n MatchRouteOptions,\n} from './Matches'\nimport type {\n BuildLocationFn,\n CommitLocationOptions,\n NavigateFn,\n} from './RouterProvider'\nimport type {\n Manifest,\n ManifestRouteAssets,\n RouterManagedTag,\n} from './manifest'\nimport type { AnySchema, AnyValidator } from './validators'\nimport type { NavigateOptions, ResolveRelativePath, ToOptions } from './link'\nimport type {\n AnySerializationAdapter,\n ValidateSerializableInput,\n} from './ssr/serializer/transformer'\nimport type { GetStoreConfig, RouterStores } from './stores'\n\nexport type ControllablePromise<T = any> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value?: any) => void\n}\n\nexport type InjectedHtmlEntry = Promise<string>\n\nexport interface Register {\n // Lots of things on here like...\n // router\n // config\n // ssr\n}\n\nexport type RegisteredSsr<TRegister = Register> = TRegister extends {\n ssr: infer TSSR\n}\n ? TSSR\n : false\n\nexport type RegisteredRouter<TRegister = Register> = TRegister extends {\n router: infer TRouter\n}\n ? TRouter\n : AnyRouter\n\nexport type RegisteredConfigType<TRegister, TKey> = TRegister extends {\n config: infer TConfig\n}\n ? TConfig extends {\n '~types': infer TTypes\n }\n ? TKey extends keyof TTypes\n ? TTypes[TKey]\n : unknown\n : unknown\n : unknown\n\nexport type DefaultRemountDepsFn<TRouteTree extends AnyRoute> = (\n opts: MakeRemountDepsOptionsUnion<TRouteTree>,\n) => any\n\nexport interface DefaultRouterOptionsExtensions {}\n\nexport interface RouterOptionsExtensions extends DefaultRouterOptionsExtensions {}\n\nexport type SSROption = boolean | 'data-only'\n\nexport interface RouterOptions<\n TRouteTree extends AnyRoute,\n TTrailingSlashOption extends TrailingSlashOption,\n TDefaultStructuralSharingOption extends boolean = false,\n TRouterHistory extends RouterHistory = RouterHistory,\n TDehydrated = undefined,\n> extends RouterOptionsExtensions {\n /**\n * The history object that will be used to manage the browser history.\n *\n * If not provided, a new createBrowserHistory instance will be created and used.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#history-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/history-types)\n */\n history?: TRouterHistory\n /**\n * A function that will be used to stringify search params when generating links.\n *\n * @default defaultStringifySearch\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#stringifysearch-method)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization)\n */\n stringifySearch?: SearchSerializer\n /**\n * A function that will be used to parse search params when parsing the current location.\n *\n * @default defaultParseSearch\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#parsesearch-method)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization)\n */\n parseSearch?: SearchParser\n /**\n * If `false`, routes will not be preloaded by default in any way.\n *\n * If `'intent'`, routes will be preloaded by default when the user hovers over a link or a `touchstart` event is detected on a `<Link>`.\n *\n * If `'viewport'`, routes will be preloaded by default when they are within the viewport.\n *\n * @default false\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreload-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading)\n */\n defaultPreload?: false | 'intent' | 'viewport' | 'render'\n /**\n * The delay in milliseconds that a route must be hovered over or touched before it is preloaded.\n *\n * @default 50\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreloaddelay-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading#preload-delay)\n */\n defaultPreloadDelay?: number\n /**\n * The default `preloadIntentProximity` a route should use if no preloadIntentProximity is provided.\n *\n * @default 0\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreloadintentproximity-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading#preload-intent-proximity)\n */\n defaultPreloadIntentProximity?: number\n /**\n * The default `pendingMs` a route should use if no pendingMs is provided.\n *\n * @default 1000\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpendingms-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#avoiding-pending-component-flash)\n */\n defaultPendingMs?: number\n /**\n * The default `pendingMinMs` a route should use if no pendingMinMs is provided.\n *\n * @default 500\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpendingminms-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#avoiding-pending-component-flash)\n */\n defaultPendingMinMs?: number\n /**\n * The default `staleTime` a route should use if no staleTime is provided. This is the time in milliseconds that a route will be considered fresh.\n *\n * @default 0\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultstaletime-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#key-options)\n */\n defaultStaleTime?: number\n /**\n * The default stale reload mode a route loader should use if no `loader.staleReloadMode` is provided.\n *\n * `'background'` preserves the current stale-while-revalidate behavior.\n * `'blocking'` waits for stale loader reloads to complete before resolving navigation.\n *\n * @default 'background'\n */\n defaultStaleReloadMode?: LoaderStaleReloadMode\n /**\n * The default `preloadStaleTime` a route should use if no preloadStaleTime is provided.\n *\n * @default 30_000 `(30 seconds)`\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreloadstaletime-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading)\n */\n defaultPreloadStaleTime?: number\n /**\n * The default `preloadGcTime` a route should use if none is provided.\n *\n * @default 300_000 `(5 minutes)`\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultpreloadgctime-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/preloading)\n */\n defaultPreloadGcTime?: number\n /**\n * If `true`, route navigations will called using `document.startViewTransition()`.\n *\n * If the browser does not support this api, this option will be ignored.\n *\n * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition) for more information on how this function works.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultviewtransition-property)\n */\n defaultViewTransition?: boolean | ViewTransitionOptions\n /**\n * The default `hashScrollIntoView` a route should use if no hashScrollIntoView is provided while navigating\n *\n * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) for more information on `ScrollIntoViewOptions`.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaulthashscrollintoview-property)\n */\n defaultHashScrollIntoView?: boolean | ScrollIntoViewOptions\n /**\n * @default 'fuzzy'\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#notfoundmode-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/not-found-errors#the-notfoundmode-option)\n */\n notFoundMode?: 'root' | 'fuzzy'\n /**\n * The default `gcTime` a route should use if no gcTime is provided.\n *\n * @default 300_000 `(5 minutes)`\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultgctime-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#key-options)\n */\n defaultGcTime?: number\n /**\n * If `true`, all routes will be matched as case-sensitive.\n *\n * @default false\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#casesensitive-property)\n */\n caseSensitive?: boolean\n /**\n *\n * The route tree that will be used to configure the router instance.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#routetree-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/routing/route-trees)\n */\n routeTree?: TRouteTree\n /**\n * The basepath for then entire router. This is useful for mounting a router instance at a subpath.\n * ```\n * @default '/'\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#basepath-property)\n */\n basepath?: string\n /**\n * The root context that will be provided to all routes in the route tree.\n *\n * This can be used to provide a context to all routes in the tree without having to provide it to each route individually.\n *\n * Optional or required if the root route was created with [`createRootRouteWithContext()`](https://tanstack.com/router/latest/docs/framework/react/api/router/createRootRouteWithContextFunction).\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#context-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/router-context)\n */\n context?: InferRouterContext<TRouteTree>\n\n additionalContext?: any\n\n /**\n * A function that will be called when the router is dehydrated.\n *\n * The return value of this function will be serialized and stored in the router's dehydrated state.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)\n */\n dehydrate?: () => Awaitable<\n Constrain<TDehydrated, ValidateSerializableInput<Register, TDehydrated>>\n >\n /**\n * A function that will be called when the router is hydrated.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#hydrate-method)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)\n */\n hydrate?: (dehydrated: TDehydrated) => Awaitable<void>\n /**\n * An array of route masks that will be used to mask routes in the route tree.\n *\n * Route masking is when you display a route at a different path than the one it is configured to match, like a modal popup that when shared will unmask to the modal's content instead of the modal's context.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#routemasks-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/route-masking)\n */\n routeMasks?: Array<RouteMask<TRouteTree>>\n /**\n * If `true`, route masks will, by default, be removed when the page is reloaded.\n *\n * This can be overridden on a per-mask basis by setting the `unmaskOnReload` option on the mask, or on a per-navigation basis by setting the `unmaskOnReload` option in the `Navigate` options.\n *\n * @default false\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#unmaskonreload-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/route-masking#unmasking-on-page-reload)\n */\n unmaskOnReload?: boolean\n\n /**\n * Use `notFoundComponent` instead.\n *\n * @deprecated\n * See https://tanstack.com/router/v1/docs/guide/not-found-errors#migrating-from-notfoundroute for more info.\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#notfoundroute-property)\n */\n notFoundRoute?: AnyRoute\n /**\n * Configures how trailing slashes are treated.\n *\n * - `'always'` will add a trailing slash if not present\n * - `'never'` will remove the trailing slash if present\n * - `'preserve'` will not modify the trailing slash.\n *\n * @default 'never'\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#trailingslash-property)\n */\n trailingSlash?: TTrailingSlashOption\n /**\n * While usually automatic, sometimes it can be useful to force the router into a server-side state, e.g. when using the router in a non-browser environment that has access to a global.document object.\n *\n * @default typeof document !== 'undefined'\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#isserver-property)\n */\n isServer?: boolean\n\n /**\n * @default false\n */\n isShell?: boolean\n\n /**\n * @default false\n */\n isPrerendering?: boolean\n\n /**\n * The default `ssr` a route should use if no `ssr` is provided.\n *\n * @default true\n */\n defaultSsr?: SSROption\n\n search?: {\n /**\n * Configures how unknown search params (= not returned by any `validateSearch`) are treated.\n *\n * @default false\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#search.strict-property)\n */\n strict?: boolean\n }\n\n /**\n * Configures whether structural sharing is enabled by default for fine-grained selectors.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultstructuralsharing-property)\n */\n defaultStructuralSharing?: TDefaultStructuralSharingOption\n\n /**\n * Configures which URI characters are allowed in path params that would ordinarily be escaped by encodeURIComponent.\n *\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#pathparamsallowedcharacters-property)\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/path-params#allowed-characters)\n */\n pathParamsAllowedCharacters?: Array<\n ';' | ':' | '@' | '&' | '=' | '+' | '$' | ','\n >\n\n defaultRemountDeps?: DefaultRemountDepsFn<TRouteTree>\n\n /**\n * If `true`, scroll restoration will be enabled\n *\n * @default false\n */\n scrollRestoration?:\n | boolean\n | ((opts: { location: ParsedLocation }) => boolean)\n\n /**\n * A function that will be called to get the key for the scroll restoration cache.\n *\n * @default (location) => location.href\n */\n getScrollRestorationKey?: (location: ParsedLocation) => string\n /**\n * The default behavior for scroll restoration.\n *\n * @default 'auto'\n */\n scrollRestorationBehavior?: ScrollBehavior\n /**\n * An array of selectors that will be used to scroll to the top of the page in addition to `window`\n *\n * @default ['window']\n */\n scrollToTopSelectors?: Array<string | (() => Element | null | undefined)>\n\n /**\n * When `true`, disables the global catch boundary that normally wraps all route matches.\n * This allows unhandled errors to bubble up to top-level error handlers in the browser.\n *\n * Useful for testing tools (like Storybook Test Runner), error reporting services,\n * and debugging scenarios where you want errors to reach the browser's global error handlers.\n *\n * @default false\n */\n disableGlobalCatchBoundary?: boolean\n\n /**\n * An array of URL protocols to allow in links, redirects, and navigation.\n * Absolute URLs with protocols not in this list will be rejected.\n *\n * @default DEFAULT_PROTOCOL_ALLOWLIST (http:, https:, mailto:, tel:)\n * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#protocolallowlist-property)\n */\n protocolAllowlist?: Array<string>\n\n serializationAdapters?: ReadonlyArray<AnySerializationAdapter>\n /**\n * Configures how the router will rewrite the location between the actual href and the internal href of the router.\n *\n * @default undefined\n * @description You can provide a custom rewrite pair (in/out).\n * This is useful for shifting data from the origin to the path (for things like subdomain routing), or other advanced use cases.\n */\n rewrite?: LocationRewrite\n origin?: string\n ssr?: {\n nonce?: string\n }\n}\n\nexport type LocationRewrite = {\n /**\n * A function that will be called to rewrite the URL before it is interpreted by the router from the history instance.\n *\n * @default undefined\n */\n input?: LocationRewriteFunction\n /**\n * A function that will be called to rewrite the URL before it is committed to the actual history instance from the router.\n *\n * @default undefined\n */\n output?: LocationRewriteFunction\n}\n\n/**\n * A function that will be called to rewrite the URL.\n *\n * @param url The URL to rewrite.\n * @returns The rewritten URL (as a URL instance or full href string) or undefined if no rewrite is needed.\n */\nexport type LocationRewriteFunction = ({\n url,\n}: {\n url: URL\n}) => undefined | string | URL\n\nexport interface RouterState<\n in out TRouteTree extends AnyRoute = AnyRoute,\n in out TRouteMatch = MakeRouteMatchUnion,\n> {\n status: 'pending' | 'idle'\n isLoading: boolean\n matches: Array<TRouteMatch>\n location: ParsedLocation<FullSearchSchema<TRouteTree>>\n resolvedLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>\n}\n\nexport interface BuildNextOptions {\n to?: string | number | null\n params?: true | Updater<unknown>\n search?: true | Updater<unknown>\n hash?: true | Updater<string>\n state?: true | NonNullableUpdater<ParsedHistoryState, HistoryState>\n mask?: {\n to?: string | number | null\n params?: true | Updater<unknown>\n search?: true | Updater<unknown>\n hash?: true | Updater<string>\n state?: true | NonNullableUpdater<ParsedHistoryState, HistoryState>\n unmaskOnReload?: boolean\n }\n from?: string\n href?: string\n _fromLocation?: ParsedLocation\n unsafeRelative?: 'path'\n _isNavigate?: boolean\n}\n\ntype NavigationEventInfo = {\n fromLocation?: ParsedLocation\n toLocation: ParsedLocation\n pathChanged: boolean\n hrefChanged: boolean\n hashChanged: boolean\n}\n\nexport interface RouterEvents {\n onBeforeNavigate: {\n type: 'onBeforeNavigate'\n } & NavigationEventInfo\n onBeforeLoad: {\n type: 'onBeforeLoad'\n } & NavigationEventInfo\n onLoad: {\n type: 'onLoad'\n } & NavigationEventInfo\n onResolved: {\n type: 'onResolved'\n } & NavigationEventInfo\n onBeforeRouteMount: {\n type: 'onBeforeRouteMount'\n } & NavigationEventInfo\n onRendered: {\n type: 'onRendered'\n } & NavigationEventInfo\n}\n\nexport type RouterEvent = RouterEvents[keyof RouterEvents]\n\nexport type ListenerFn<TEvent extends RouterEvent> = (event: TEvent) => void\n\nexport type RouterListener<TRouterEvent extends RouterEvent> = {\n eventType: TRouterEvent['type']\n fn: ListenerFn<TRouterEvent>\n}\n\nexport type SubscribeFn = <TType extends keyof RouterEvents>(\n eventType: TType,\n fn: ListenerFn<RouterEvents[TType]>,\n) => () => void\n\nexport interface MatchRoutesOpts {\n throwOnError?: boolean\n /** @internal */\n _controller?: AbortController\n /** @internal */\n _rematerialize?: boolean\n}\n\nfunction routeNeedsLoad(route: AnyRoute): unknown {\n return (\n route.options.loader ||\n route.options.beforeLoad ||\n route.lazyFn ||\n (route.options.component as any)?.preload ||\n (route.options.pendingComponent as any)?.preload\n )\n}\n\nexport type InferRouterContext<TRouteTree extends AnyRoute> =\n TRouteTree['types']['routerContext']\n\nexport type RouterContextOptions<TRouteTree extends AnyRoute> =\n AnyContext extends InferRouterContext<TRouteTree>\n ? {\n context?: InferRouterContext<TRouteTree>\n }\n : {\n context: InferRouterContext<TRouteTree>\n }\n\nexport type RouterConstructorOptions<\n TRouteTree extends AnyRoute,\n TTrailingSlashOption extends TrailingSlashOption,\n TDefaultStructuralSharingOption extends boolean,\n TRouterHistory extends RouterHistory,\n TDehydrated extends Record<string, any>,\n> = Omit<\n RouterOptions<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n >,\n 'context' | 'serializationAdapters' | 'defaultSsr'\n> &\n RouterContextOptions<TRouteTree>\n\nexport type PreloadRouteFn<\n TRouteTree extends AnyRoute,\n TTrailingSlashOption extends TrailingSlashOption,\n TDefaultStructuralSharingOption extends boolean,\n TRouterHistory extends RouterHistory,\n> = <\n TFrom extends RoutePaths<TRouteTree> | string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom,\n TMaskTo extends string = '',\n>(\n opts: NavigateOptions<\n RouterCore<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory\n >,\n TFrom,\n TTo,\n TMaskFrom,\n TMaskTo\n > & {\n /**\n * @internal\n * A **trusted** built location that can be used to redirect to.\n */\n _builtLocation?: ParsedLocation\n },\n) => Promise<Array<AnyRouteMatch> | undefined>\n\nexport type MatchRouteFn<\n TRouteTree extends AnyRoute,\n TTrailingSlashOption extends TrailingSlashOption,\n TDefaultStructuralSharingOption extends boolean,\n TRouterHistory extends RouterHistory,\n> = <\n TFrom extends RoutePaths<TRouteTree> = '/',\n TTo extends string | undefined = undefined,\n TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>,\n>(\n location: ToOptions<\n RouterCore<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory\n >,\n TFrom,\n TTo\n >,\n opts?: MatchRouteOptions,\n) => false | RouteById<TRouteTree, TResolved>['types']['allParams']\n\nexport type UpdateFn<\n TRouteTree extends AnyRoute,\n TTrailingSlashOption extends TrailingSlashOption,\n TDefaultStructuralSharingOption extends boolean,\n TRouterHistory extends RouterHistory,\n TDehydrated extends Record<string, any>,\n> = (\n newOptions: RouterConstructorOptions<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n >,\n) => void\n\nexport type InvalidateFn<TRouter extends AnyRouter> = (opts?: {\n filter?: (d: MakeRouteMatchUnion<TRouter>) => boolean\n sync?: boolean\n forcePending?: boolean\n}) => Promise<void>\n\nexport type ParseLocationFn<TRouteTree extends AnyRoute> = (\n locationToParse: HistoryLocation,\n previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>,\n) => ParsedLocation<FullSearchSchema<TRouteTree>>\n\nexport type GetMatchRoutesFn = (pathname: string) => {\n matchedRoutes: ReadonlyArray<AnyRoute>\n /** exhaustive params, still in their string form */\n routeParams: Record<string, string>\n foundRoute: AnyRoute | undefined\n parseError?: unknown\n}\n\nexport type EmitFn = (routerEvent: RouterEvent) => void\n\nexport type LoadFn = (opts?: {\n sync?: boolean\n action?: { type: HistoryAction }\n _signal?: AbortSignal\n _dedupe?: boolean\n}) => Promise<void>\n\nexport type CommitLocationFn = ({\n viewTransition,\n ignoreBlocker,\n ...next\n}: ParsedLocation & CommitLocationOptions) => Promise<void>\n\nexport type StartTransitionFn = (\n fn: () => void,\n expected: Array<AnyRouteMatch>,\n urgent?: boolean,\n) => Promise<boolean>\n\nexport interface MatchRoutesFn {\n (\n pathname: string,\n locationSearch?: AnySchema,\n opts?: MatchRoutesOpts,\n ): Array<MakeRouteMatchUnion>\n /**\n * @deprecated use the following signature instead\n */\n (next: ParsedLocation, opts?: MatchRoutesOpts): Array<AnyRouteMatch>\n (\n pathnameOrNext: string | ParsedLocation,\n locationSearchOrOpts?: AnySchema | MatchRoutesOpts,\n opts?: MatchRoutesOpts,\n ): Array<AnyRouteMatch>\n}\n\nexport type LoadRouteChunkFn = (route: AnyRoute) => Promise<Array<void>>\n\nexport type ResolveRedirect = (err: AnyRedirect) => ResolvedRedirect\n\nexport type ClearCacheFn<TRouter extends AnyRouter> = (opts?: {\n filter?: (d: MakeRouteMatchUnion<TRouter>) => boolean\n}) => void\n\nexport interface ServerSsr {\n /** Framework-only: injects router-owned HTML into the SSR stream. */\n injectHtml: (html: string) => void\n /** Framework-only: injects a router-owned script tag into the SSR stream. */\n injectScript: (script: string) => void\n isDehydrated: () => boolean\n isSerializationFinished: () => boolean\n /** Framework-only: atomically reserves the pass-through stream path if safe. */\n reserveStreamFastPath: () => boolean\n /** Framework-only. */\n onInjectedHtml: (listener: () => void) => () => void\n /** Framework-only. */\n onRenderFinished: (listener: () => void) => void\n /** Framework-only. */\n setRenderFinished: () => void\n /** Framework-only. */\n cleanup: () => void\n /**\n * Register a listener invoked when the SSR request lifecycle ends (success,\n * error, abort, or stream lifetime expiry). Use to tear down per-request\n * resources whose references would otherwise pin the router (e.g. query\n * cache subscriptions, gcTime timers, abort controllers).\n *\n * Listeners run synchronously and exactly once. Errors are caught and logged.\n */\n onCleanup: (listener: () => void) => void\n /** Framework-only. */\n onSerializationFinished: (listener: () => void) => () => void\n /** Framework-only. */\n dehydrate: (opts?: { requestAssets?: ManifestRouteAssets }) => Promise<void>\n /** Framework-only. */\n takeBufferedScripts: () => RouterManagedTag | undefined\n /** Framework-only: takes buffered router-owned HTML. */\n takeBufferedHtml: () => string | undefined\n /** Framework-only. */\n liftScriptBarrier: () => void\n}\n\nexport interface RouterSsrLifecycle {\n onServerSsrAttach?: Array<(serverSsr: ServerSsr) => void>\n}\n\nexport type AnyRouterWithContext<TContext> = RouterCore<\n AnyRouteWithContext<TContext>,\n any,\n any,\n any,\n any\n>\n\nexport type AnyRouter = RouterCore<any, any, any, any, any>\n\nexport interface ViewTransitionOptions {\n types:\n | Array<string>\n | ((locationChangeInfo: {\n fromLocation?: ParsedLocation\n toLocation: ParsedLocation\n pathChanged: boolean\n hrefChanged: boolean\n hashChanged: boolean\n }) => Array<string> | false)\n}\n\n// TODO where is this used? can we remove this?\n/**\n * Convert an unknown error into a minimal, serializable object.\n * Includes name and message (and stack in development).\n */\nexport function defaultSerializeError(err: unknown) {\n if (err instanceof Error) {\n const obj = {\n name: err.name,\n message: err.message,\n }\n\n if (process.env.NODE_ENV === 'development') {\n ;(obj as any).stack = err.stack\n }\n\n return obj\n }\n\n return {\n data: err,\n }\n}\n\n/** Options for configuring trailing-slash behavior. */\nexport const trailingSlashOptions = {\n always: 'always',\n never: 'never',\n preserve: 'preserve',\n} as const\n\nexport type TrailingSlashOption =\n (typeof trailingSlashOptions)[keyof typeof trailingSlashOptions]\n\n/**\n * Compute whether path, href or hash changed between previous and current\n * resolved locations.\n */\nexport function getLocationChangeInfo(\n location: ParsedLocation,\n resolvedLocation?: ParsedLocation,\n) {\n return {\n fromLocation: resolvedLocation,\n toLocation: location,\n pathChanged: resolvedLocation?.pathname !== location.pathname,\n hrefChanged: resolvedLocation?.href !== location.href,\n hashChanged: resolvedLocation?.hash !== location.hash,\n }\n}\n\n/**\n * Return only state owned by the application, excluding volatile history\n * bookkeeping. Mask payloads (`__tempLocation`/`__tempKey`) are kept: they\n * distinguish otherwise-identical locations.\n */\nexport function _getUserHistoryState({\n key: _key,\n __TSR_key: _tsrKey,\n __TSR_index: _tsrIndex,\n __hashScrollIntoViewOptions: _hashScroll,\n ...state\n}: ParsedHistoryState): HistoryState {\n return state\n}\n\n/** Run route lifecycle callbacks in leave/enter/stay phases. */\nexport function runRouteLifecycle(\n router: AnyRouter,\n previous: Array<AnyRouteMatch>,\n matches: Array<AnyRouteMatch>,\n isCurrent?: () => boolean,\n): void {\n for (const match of previous) {\n if (isCurrent?.() === false) {\n return\n }\n if (!matches.some((candidate) => candidate.routeId === match.routeId)) {\n ;(router.routesById as Record<string, AnyRoute>)[\n match.routeId\n ]!.options.onLeave?.(match)\n }\n }\n for (const match of matches) {\n if (isCurrent?.() === false) {\n return\n }\n const route = (router.routesById as Record<string, AnyRoute>)[\n match.routeId\n ]!\n route.options[\n previous.some((candidate) => candidate.routeId === match.routeId)\n ? 'onStay'\n : 'onEnter'\n ]?.(match)\n }\n}\n\ntype LightweightRouteMatchResult = {\n matchedRoutes: ReadonlyArray<AnyRoute>\n fullPath: string\n search: Record<string, unknown>\n params: Record<string, unknown>\n}\n\ntype LightweightRouteMatchCacheEntry = [\n lastMatchId: string | undefined,\n result: LightweightRouteMatchResult,\n]\n\nexport type CreateRouterFn = <\n TRouteTree extends AnyRoute,\n TTrailingSlashOption extends TrailingSlashOption = 'never',\n TDefaultStructuralSharingOption extends boolean = false,\n TRouterHistory extends RouterHistory = RouterHistory,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>(\n options: undefined extends number\n ? 'strictNullChecks must be enabled in tsconfig.json'\n : RouterConstructorOptions<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n >,\n) => RouterCore<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n>\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __TSR_CACHE__:\n | {\n routeTree: AnyRoute\n processRouteTreeResult: ProcessRouteTreeResult<AnyRoute>\n resolvePathCache: LRUCache<string, string>\n }\n | undefined\n}\n\nexport interface RouterCore<\n in out TRouteTree extends AnyRoute,\n in out TTrailingSlashOption extends TrailingSlashOption,\n in out TDefaultStructuralSharingOption extends boolean,\n in out TRouterHistory extends RouterHistory = RouterHistory,\n in out TDehydrated extends Record<string, any> = Record<string, any>,\n> {\n shouldViewTransition?: boolean | ViewTransitionOptions\n /** Current client load transaction and owner of navigation writes. */\n _tx?: LoadTransaction\n /** Joinable in-flight loader generations keyed by match ID. */\n _flights?: Map<string, LoaderFlight>\n /** Whole speculative lanes that an identical navigation may adopt. */\n _preloads?: Map<string, ActivePreload>\n /** Owns cancellable work before a client transaction publishes. */\n _preflight?: AbortController\n /** Transfers one reconstructed SSR prefix into its initial client load. */\n _handoff?: HydrationHandoff\n /** Pending-boundary reveal and minimum-visible timing state. */\n _pending?: PendingSession\n /** Result of the latest server load, used to render or redirect. */\n _serverResult?: ServerLoadResult\n /** Framework callback that acknowledges an exact matches publication. */\n _rendered?: (matches: Array<AnyRouteMatch>) => void\n /** Development-only HMR reload for a route and its descendants. */\n _refreshRoute: (() => Promise<void>) | undefined\n /** Development-only replacement for a route's lazy chunk owner. */\n _replaceRouteChunk:\n | ((route: AnyRoute, lazyFn: AnyRoute['lazyFn']) => void)\n | undefined\n}\n\nexport type HydrationHandoff = [\n claim: () => AbortController | undefined,\n finish: (matches?: Array<AnyRouteMatch>) => number | undefined,\n]\n\n/**\n * Core, framework-agnostic router engine that powers TanStack Router.\n *\n * Provides navigation, matching, loading, preloading, caching and event APIs\n * used by framework adapters (React/Solid). Prefer framework helpers like\n * `createRouter` in app code.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/RouterType\n */\nexport class RouterCore<\n in out TRouteTree extends AnyRoute,\n in out TTrailingSlashOption extends TrailingSlashOption,\n in out TDefaultStructuralSharingOption extends boolean,\n in out TRouterHistory extends RouterHistory = RouterHistory,\n in out TDehydrated extends Record<string, any> = Record<string, any>,\n> {\n // Option-independent properties\n tempLocationKey: string | undefined = `${Math.round(\n Math.random() * 10000000,\n )}`\n _scroll: {\n next: boolean\n // True until the current PUSH/REPLACE renders, so its hash owns window scroll.\n hash?: boolean\n restoring?: boolean\n restoration?: boolean\n reset?: boolean\n } = { next: true }\n subscribers = new Set<RouterListener<RouterEvent>>()\n /** Accepted off-screen loader generations keyed by match ID. */\n _cache = new Map<string, AnyRouteMatch>()\n /** Accepted semantic lane, excluding temporary pending presentation. */\n _committed: Array<AnyRouteMatch> = []\n\n // Must build in constructor\n stores!: RouterStores<TRouteTree>\n private getStoreConfig!: GetStoreConfig\n batch!: (fn: () => void) => void\n\n options!: PickAsRequired<\n RouterOptions<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n >,\n 'stringifySearch' | 'parseSearch' | 'context'\n >\n history!: TRouterHistory\n rewrite?: LocationRewrite\n origin?: string\n latestLocation!: ParsedLocation<FullSearchSchema<TRouteTree>>\n _pendingLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>\n basepath!: string\n routeTree!: TRouteTree\n routesById!: RoutesById<TRouteTree>\n routesByPath!: RoutesByPath<TRouteTree>\n processedTree!: ProcessedTree<TRouteTree, any, any>\n resolvePathCache!: LRUCache<string, string>\n private routeBranchCache = new WeakMap<AnyRoute, ReadonlyArray<AnyRoute>>()\n private lightweightCache = new WeakMap<\n ParsedLocation,\n LightweightRouteMatchCacheEntry\n >()\n isServer!: boolean\n pathParamsDecoder?: (encoded: string) => string\n protocolAllowlist!: Set<string>\n\n /**\n * @deprecated Use the `createRouter` function instead\n */\n constructor(\n options: RouterConstructorOptions<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n >,\n getStoreConfig: GetStoreConfig,\n ) {\n this.getStoreConfig = getStoreConfig\n\n this.update({\n defaultPreloadDelay: 50,\n defaultPendingMs: 1000,\n defaultPendingMinMs: 500,\n context: undefined!,\n ...options,\n caseSensitive: options.caseSensitive ?? false,\n notFoundMode: options.notFoundMode ?? 'fuzzy',\n stringifySearch: options.stringifySearch ?? defaultStringifySearch,\n parseSearch: options.parseSearch ?? defaultParseSearch,\n protocolAllowlist:\n options.protocolAllowlist ?? DEFAULT_PROTOCOL_ALLOWLIST,\n })\n\n if (!(isServer ?? typeof document === 'undefined')) {\n self.__TSR_ROUTER__ = this\n }\n }\n\n startTransition: StartTransitionFn = async (fn) => {\n fn()\n return false\n }\n isShell() {\n return !!this.options.isShell\n }\n\n update: UpdateFn<\n TRouteTree,\n TTrailingSlashOption,\n TDefaultStructuralSharingOption,\n TRouterHistory,\n TDehydrated\n > = (newOptions) => {\n if (process.env.NODE_ENV !== 'production') {\n if (newOptions.notFoundRoute) {\n console.warn(\n 'The notFoundRoute API is deprecated and will be removed in the next major version. See https://tanstack.com/router/v1/docs/framework/react/guide/not-found-errors#migrating-from-notfoundroute for more info.',\n )\n }\n }\n\n const prevOptions = this.options\n const prevBasepath = this.basepath ?? prevOptions?.basepath ?? '/'\n const basepathWasUnset = this.basepath === undefined\n const prevRewriteOption = prevOptions?.rewrite\n\n this.options = {\n ...prevOptions,\n ...newOptions,\n }\n\n this.isServer =\n this.options.isServer ?? isServer ?? typeof document === 'undefined'\n\n this.protocolAllowlist = new Set(this.options.protocolAllowlist)\n\n if (this.options.pathParamsAllowedCharacters)\n this.pathParamsDecoder = compileDecodeCharMap(\n this.options.pathParamsAllowedCharacters,\n )\n\n if (\n !this.history ||\n (this.options.history && this.options.history !== this.history)\n ) {\n if (!this.options.history) {\n if (!(isServer ?? this.isServer)) {\n this.history = createBrowserHistory() as TRouterHistory\n }\n } else {\n this.history = this.options.history\n }\n }\n\n this.origin = this.options.origin\n if (!this.origin) {\n if (\n !(isServer ?? this.isServer) &&\n window?.origin &&\n window.origin !== 'null'\n ) {\n this.origin = window.origin\n } else {\n // fallback for the server, can be overridden by calling router.update({origin}) on the server\n this.origin = 'http://localhost'\n }\n }\n\n if (this.history) {\n this.updateLatestLocation()\n }\n\n if (this.options.routeTree !== this.routeTree) {\n this.routeTree = this.options.routeTree as TRouteTree\n let processRouteTreeResult: ProcessRouteTreeResult<TRouteTree>\n if (\n (isServer ?? this.isServer) &&\n process.env.NODE_ENV !== 'development' &&\n globalThis.__TSR_CACHE__ &&\n globalThis.__TSR_CACHE__.routeTree === this.routeTree\n ) {\n const cached = globalThis.__TSR_CACHE__\n this.resolvePathCache = cached.resolvePathCache\n processRouteTreeResult = cached.processRouteTreeResult as any\n } else {\n this.resolvePathCache = createLRUCache(1000)\n processRouteTreeResult = this.buildRouteTree()\n // only cache if nothing else is cached yet\n if (\n (isServer ?? this.isServer) &&\n process.env.NODE_ENV !== 'development' &&\n globalThis.__TSR_CACHE__ === undefined\n ) {\n globalThis.__TSR_CACHE__ = {\n routeTree: this.routeTree,\n processRouteTreeResult: processRouteTreeResult as any,\n resolvePathCache: this.resolvePathCache,\n }\n }\n }\n this.setRoutes(processRouteTreeResult)\n }\n\n if (!this.stores && this.latestLocation) {\n const config = this.getStoreConfig(this)\n this.batch = config.batch\n this.stores = createRouterStores(this.latestLocation, config)\n\n if (!(isServer ?? this.isServer)) {\n setupScrollRestoration(this)\n }\n }\n\n const nextBasepath = this.options.basepath ?? '/'\n const nextRewriteOption = this.options.rewrite\n const basepathChanged = basepathWasUnset || prevBasepath !== nextBasepath\n const rewriteChanged = prevRewriteOption !== nextRewriteOption\n\n if (basepathChanged || rewriteChanged) {\n this.basepath = nextBasepath\n\n const rewrites: Array<LocationRewrite> = []\n const trimmed = trimPath(nextBasepath)\n if (trimmed && trimmed !== '/') {\n rewrites.push(\n rewriteBasepath({\n basepath: nextBasepath,\n }),\n )\n }\n if (nextRewriteOption) {\n rewrites.push(nextRewriteOption)\n }\n\n this.rewrite =\n rewrites.length === 0\n ? undefined\n : rewrites.length === 1\n ? rewrites[0]\n : composeRewrites(rewrites)\n\n if (this.history) {\n this.updateLatestLocation()\n }\n\n if (this.stores) {\n this.stores.location.set(this.latestLocation)\n }\n }\n }\n\n get state(): RouterState<TRouteTree> {\n return this.stores.__store.get()\n }\n\n updateLatestLocation = () => {\n this.latestLocation = this.parseLocation(\n this.history.location,\n this.latestLocation,\n )\n }\n\n buildRouteTree = () => {\n const result = processRouteTree(\n this.routeTree,\n this.options.caseSensitive,\n (route, i) => {\n route.init({\n originalIndex: i,\n })\n },\n )\n if (this.options.routeMasks) {\n processRouteMasks(this.options.routeMasks, result.processedTree)\n }\n\n return result\n }\n\n setRoutes({\n routesById,\n routesByPath,\n processedTree,\n }: ProcessRouteTreeResult<TRouteTree>) {\n this.routesById = routesById as RoutesById<TRouteTree>\n this.routesByPath = routesByPath as RoutesByPath<TRouteTree>\n this.processedTree = processedTree\n\n const notFoundRoute = this.options.notFoundRoute\n\n if (notFoundRoute) {\n notFoundRoute.init({\n originalIndex: 99999999999,\n })\n this.routesById[notFoundRoute.id] = notFoundRoute\n }\n }\n\n /**\n * Subscribe to router lifecycle events like `onBeforeNavigate`, `onLoad`,\n * `onResolved`, etc. Returns an unsubscribe function.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/RouterEventsType\n */\n subscribe: SubscribeFn = (eventType, fn) => {\n const listener: RouterListener<any> = {\n eventType,\n fn,\n }\n\n this.subscribers.add(listener)\n\n return () => {\n this.subscribers.delete(listener)\n }\n }\n\n emit: EmitFn = (routerEvent) => {\n for (const listener of this.subscribers) {\n if (listener.eventType === routerEvent.type) {\n try {\n listener.fn(routerEvent)\n } catch (e) {\n console.error(e)\n }\n }\n }\n }\n\n /**\n * Parse a HistoryLocation into a strongly-typed ParsedLocation using the\n * current router options, rewrite rules and search parser/stringifier.\n */\n parseLocation: ParseLocationFn<TRouteTree> = (\n locationToParse,\n previousLocation,\n ) => {\n const parse = ({\n pathname,\n search,\n hash,\n href,\n state,\n }: HistoryLocation): ParsedLocation<FullSearchSchema<TRouteTree>> => {\n // Fast path: no rewrite configured and pathname doesn't need encoding\n // Characters that need encoding: space, high unicode, control chars\n // eslint-disable-next-line no-control-regex\n if (!this.rewrite && !/[ \\x00-\\x1f\\x7f\\u0080-\\uffff]/.test(pathname)) {\n const parsedSearch = this.options.parseSearch(search)\n const searchStr = this.options.stringifySearch(parsedSearch)\n\n return {\n href: pathname + searchStr + hash,\n publicHref: pathname + searchStr + hash,\n pathname: decodePath(pathname).path,\n external: false,\n searchStr,\n search: nullReplaceEqualDeep(\n previousLocation?.search,\n parsedSearch,\n ) as any,\n hash: decodePath(hash.slice(1)).path,\n state: replaceEqualDeep(previousLocation?.state, state),\n }\n }\n\n // Before we do any processing, we need to allow rewrites to modify the URL\n // build up the full URL by combining the href from history with the router's origin\n const fullUrl = new URL(href, this.origin)\n\n const url = executeRewriteInput(this.rewrite, fullUrl)\n\n const parsedSearch = this.options.parseSearch(url.search)\n const searchStr = this.options.stringifySearch(parsedSearch)\n // Make sure our final url uses the re-stringified pathname, search, and has for consistency\n // (We were already doing this, so just keeping it for now)\n url.search = searchStr\n\n const fullPath = url.href.replace(url.origin, '')\n\n return {\n href: fullPath,\n publicHref: href,\n pathname: decodePath(url.pathname).path,\n external: !!this.rewrite && url.origin !== this.origin,\n searchStr,\n search: nullReplaceEqualDeep(\n previousLocation?.search,\n parsedSearch,\n ) as any,\n hash: decodePath(url.hash.slice(1)).path,\n state: replaceEqualDeep(previousLocation?.state, state),\n }\n }\n\n const location = parse(locationToParse)\n\n const { __tempLocation, __tempKey } = location.state\n\n if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {\n // Sync up the location keys\n const parsedTempLocation = parse(__tempLocation) as any\n parsedTempLocation.state.key = location.state.key // TODO: Remove in v2 - use __TSR_key instead\n parsedTempLocation.state.__TSR_key = location.state.__TSR_key\n\n delete parsedTempLocation.state.__tempLocation\n\n return {\n ...parsedTempLocation,\n maskedLocation: location,\n }\n }\n return location\n }\n\n /** Resolve a path using the router's trailing-slash policy. */\n resolvePathWithBase = (from: string, path: string) => {\n return resolvePath({\n base: from,\n to: path.includes('//') ? cleanPath(path) : path,\n trailingSlash: this.options.trailingSlash,\n cache: this.resolvePathCache,\n })\n }\n\n private getRouteBranch(route: AnyRoute) {\n let branch = this.routeBranchCache.get(route)\n if (!branch) {\n branch = buildRouteBranch(route)\n this.routeBranchCache.set(route, branch)\n }\n return branch\n }\n\n matchRoutes: MatchRoutesFn = (\n pathnameOrNext: string | ParsedLocation,\n locationSearchOrOpts?: AnySchema | MatchRoutesOpts,\n opts?: MatchRoutesOpts,\n ) => {\n if (typeof pathnameOrNext === 'string') {\n return this.matchRou