"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const store = require("@tanstack/store"); const history = require("@tanstack/history"); const invariant = require("tiny-invariant"); const utils = require("./utils.cjs"); const path = require("./path.cjs"); const notFound = require("./not-found.cjs"); const scrollRestoration = require("./scroll-restoration.cjs"); const searchParams = require("./searchParams.cjs"); const root = require("./root.cjs"); const redirect = require("./redirect.cjs"); function defaultSerializeError(err) { if (err instanceof Error) { const obj = { name: err.name, message: err.message }; if (process.env.NODE_ENV === "development") { obj.stack = err.stack; } return obj; } return { data: err }; } function getLocationChangeInfo(routerState) { const fromLocation = routerState.resolvedLocation; const toLocation = routerState.location; const pathChanged = (fromLocation == null ? void 0 : fromLocation.pathname) !== toLocation.pathname; const hrefChanged = (fromLocation == null ? void 0 : fromLocation.href) !== toLocation.href; const hashChanged = (fromLocation == null ? void 0 : fromLocation.hash) !== toLocation.hash; return { fromLocation, toLocation, pathChanged, hrefChanged, hashChanged }; } class RouterCore { /** * @deprecated Use the `createRouter` function instead */ constructor(options) { this.tempLocationKey = `${Math.round( Math.random() * 1e7 )}`; this.resetNextScroll = true; this.shouldViewTransition = void 0; this.isViewTransitionTypesSupported = void 0; this.subscribers = /* @__PURE__ */ new Set(); this.isScrollRestoring = false; this.isScrollRestorationSetup = false; this.startTransition = (fn) => fn(); this.update = (newOptions) => { var _a; if (newOptions.notFoundRoute) { console.warn( "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." ); } const previousOptions = this.options; this.options = { ...this.options, ...newOptions }; this.isServer = this.options.isServer ?? typeof document === "undefined"; this.pathParamsDecodeCharMap = this.options.pathParamsAllowedCharacters ? new Map( this.options.pathParamsAllowedCharacters.map((char) => [ encodeURIComponent(char), char ]) ) : void 0; if (!this.basepath || newOptions.basepath && newOptions.basepath !== previousOptions.basepath) { if (newOptions.basepath === void 0 || newOptions.basepath === "" || newOptions.basepath === "/") { this.basepath = "/"; } else { this.basepath = `/${path.trimPath(newOptions.basepath)}`; } } if ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition !this.history || this.options.history && this.options.history !== this.history ) { this.history = this.options.history ?? (this.isServer ? history.createMemoryHistory({ initialEntries: [this.basepath || "/"] }) : history.createBrowserHistory()); this.latestLocation = this.parseLocation(); } if (this.options.routeTree !== this.routeTree) { this.routeTree = this.options.routeTree; this.buildRouteTree(); } if (!this.__store) { this.__store = new store.Store(getInitialRouterState(this.latestLocation), { onUpdate: () => { this.__store.state = { ...this.state, cachedMatches: this.state.cachedMatches.filter( (d) => !["redirected"].includes(d.status) ) }; } }); scrollRestoration.setupScrollRestoration(this); } if (typeof window !== "undefined" && "CSS" in window && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition typeof ((_a = window.CSS) == null ? void 0 : _a.supports) === "function") { this.isViewTransitionTypesSupported = window.CSS.supports( "selector(:active-view-transition-type(a)" ); } }; this.buildRouteTree = () => { this.routesById = {}; this.routesByPath = {}; const notFoundRoute = this.options.notFoundRoute; if (notFoundRoute) { notFoundRoute.init({ originalIndex: 99999999999, defaultSsr: this.options.defaultSsr }); this.routesById[notFoundRoute.id] = notFoundRoute; } const recurseRoutes = (childRoutes) => { childRoutes.forEach((childRoute, i) => { childRoute.init({ originalIndex: i, defaultSsr: this.options.defaultSsr }); const existingRoute = this.routesById[childRoute.id]; invariant( !existingRoute, `Duplicate routes found with id: ${String(childRoute.id)}` ); this.routesById[childRoute.id] = childRoute; if (!childRoute.isRoot && childRoute.path) { const trimmedFullPath = path.trimPathRight(childRoute.fullPath); if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith("/")) { this.routesByPath[trimmedFullPath] = childRoute; } } const children = childRoute.children; if (children == null ? void 0 : children.length) { recurseRoutes(children); } }); }; recurseRoutes([this.routeTree]); const scoredRoutes = []; const routes = Object.values(this.routesById); routes.forEach((d, i) => { var _a; if (d.isRoot || !d.path) { return; } const trimmed = path.trimPathLeft(d.fullPath); const parsed = path.parsePathname(trimmed); while (parsed.length > 1 && ((_a = parsed[0]) == null ? void 0 : _a.value) === "/") { parsed.shift(); } const scores = parsed.map((segment) => { if (segment.value === "/") { return 0.75; } if (segment.type === "param") { return 0.5; } if (segment.type === "wildcard") { return 0.25; } return 1; }); scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores }); }); this.flatRoutes = scoredRoutes.sort((a, b) => { const minLength = Math.min(a.scores.length, b.scores.length); for (let i = 0; i < minLength; i++) { if (a.scores[i] !== b.scores[i]) { return b.scores[i] - a.scores[i]; } } if (a.scores.length !== b.scores.length) { return b.scores.length - a.scores.length; } for (let i = 0; i < minLength; i++) { if (a.parsed[i].value !== b.parsed[i].value) { return a.parsed[i].value > b.parsed[i].value ? 1 : -1; } } return a.index - b.index; }).map((d, i) => { d.child.rank = i; return d.child; }); }; this.subscribe = (eventType, fn) => { const listener = { eventType, fn }; this.subscribers.add(listener); return () => { this.subscribers.delete(listener); }; }; this.emit = (routerEvent) => { this.subscribers.forEach((listener) => { if (listener.eventType === routerEvent.type) { listener.fn(routerEvent); } }); }; this.parseLocation = (previousLocation, locationToParse) => { const parse = ({ pathname, search, hash, state }) => { const parsedSearch = this.options.parseSearch(search); const searchStr = this.options.stringifySearch(parsedSearch); return { pathname, searchStr, search: utils.replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch), hash: hash.split("#").reverse()[0] ?? "", href: `${pathname}${searchStr}${hash}`, state: utils.replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.state, state) }; }; const location = parse(locationToParse ?? this.history.location); const { __tempLocation, __tempKey } = location.state; if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) { const parsedTempLocation = parse(__tempLocation); parsedTempLocation.state.key = location.state.key; delete parsedTempLocation.state.__tempLocation; return { ...parsedTempLocation, maskedLocation: location }; } return location; }; this.resolvePathWithBase = (from, path$1) => { const resolvedPath = path.resolvePath({ basepath: this.basepath, base: from, to: path.cleanPath(path$1), trailingSlash: this.options.trailingSlash, caseSensitive: this.options.caseSensitive }); return resolvedPath; }; this.matchRoutes = (pathnameOrNext, locationSearchOrOpts, opts) => { if (typeof pathnameOrNext === "string") { return this.matchRoutesInternal( { pathname: pathnameOrNext, search: locationSearchOrOpts }, opts ); } else { return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts); } }; this.getMatchedRoutes = (next, dest) => { let routeParams = {}; const trimmedPath = path.trimPathRight(next.pathname); const getMatchedParams = (route) => { const result = path.matchPathname(this.basepath, trimmedPath, { to: route.fullPath, caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive, fuzzy: true }); return result; }; let foundRoute = (dest == null ? void 0 : dest.to) !== void 0 ? this.routesByPath[dest.to] : void 0; if (foundRoute) { routeParams = getMatchedParams(foundRoute); } else { foundRoute = this.flatRoutes.find((route) => { const matchedParams = getMatchedParams(route); if (matchedParams) { routeParams = matchedParams; return true; } return false; }); } let routeCursor = foundRoute || this.routesById[root.rootRouteId]; const matchedRoutes = [routeCursor]; while (routeCursor.parentRoute) { routeCursor = routeCursor.parentRoute; matchedRoutes.unshift(routeCursor); } return { matchedRoutes, routeParams, foundRoute }; }; this.cancelMatch = (id) => { const match = this.getMatch(id); if (!match) return; match.abortController.abort(); clearTimeout(match.pendingTimeout); }; this.cancelMatches = () => { var _a; (_a = this.state.pendingMatches) == null ? void 0 : _a.forEach((match) => { this.cancelMatch(match.id); }); }; this.buildLocation = (opts) => { const build = (dest = {}, matchedRoutesResult) => { var _a, _b, _c, _d, _e, _f, _g; const fromMatches = dest._fromLocation ? this.matchRoutes(dest._fromLocation, { _buildLocation: true }) : this.state.matches; const fromMatch = dest.from != null ? fromMatches.find( (d) => path.matchPathname(this.basepath, path.trimPathRight(d.pathname), { to: dest.from, caseSensitive: false, fuzzy: false }) ) : void 0; const fromPath = (fromMatch == null ? void 0 : fromMatch.pathname) || this.latestLocation.pathname; invariant( dest.from == null || fromMatch != null, "Could not find match for from: " + dest.from ); const fromSearch = ((_a = this.state.pendingMatches) == null ? void 0 : _a.length) ? (_b = utils.last(this.state.pendingMatches)) == null ? void 0 : _b.search : ((_c = utils.last(fromMatches)) == null ? void 0 : _c.search) || this.latestLocation.search; const stayingMatches = matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.filter( (d) => fromMatches.find((e) => e.routeId === d.id) ); let pathname; if (dest.to) { const resolvePathTo = (fromMatch == null ? void 0 : fromMatch.fullPath) || ((_d = utils.last(fromMatches)) == null ? void 0 : _d.fullPath) || this.latestLocation.pathname; pathname = this.resolvePathWithBase(resolvePathTo, `${dest.to}`); } else { const fromRouteByFromPathRouteId = this.routesById[(_e = stayingMatches == null ? void 0 : stayingMatches.find((route) => { const interpolatedPath = path.interpolatePath({ path: route.fullPath, params: (matchedRoutesResult == null ? void 0 : matchedRoutesResult.routeParams) ?? {}, decodeCharMap: this.pathParamsDecodeCharMap }).interpolatedPath; const pathname2 = path.joinPaths([this.basepath, interpolatedPath]); return pathname2 === fromPath; })) == null ? void 0 : _e.id]; pathname = this.resolvePathWithBase( fromPath, (fromRouteByFromPathRouteId == null ? void 0 : fromRouteByFromPathRouteId.to) ?? fromPath ); } const prevParams = { ...(_f = utils.last(fromMatches)) == null ? void 0 : _f.params }; let nextParams = (dest.params ?? true) === true ? prevParams : { ...prevParams, ...utils.functionalUpdate(dest.params, prevParams) }; if (Object.keys(nextParams).length > 0) { matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.map((route) => { var _a2; return ((_a2 = route.options.params) == null ? void 0 : _a2.stringify) ?? route.options.stringifyParams; }).filter(Boolean).forEach((fn) => { nextParams = { ...nextParams, ...fn(nextParams) }; }); } pathname = path.interpolatePath({ path: pathname, params: nextParams ?? {}, leaveWildcards: false, leaveParams: opts.leaveParams, decodeCharMap: this.pathParamsDecodeCharMap }).interpolatedPath; let search = fromSearch; if (opts._includeValidateSearch && ((_g = this.options.search) == null ? void 0 : _g.strict)) { let validatedSearch = {}; matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.forEach((route) => { try { if (route.options.validateSearch) { validatedSearch = { ...validatedSearch, ...validateSearch(route.options.validateSearch, { ...validatedSearch, ...search }) ?? {} }; } } catch { } }); search = validatedSearch; } const applyMiddlewares = (search2) => { const allMiddlewares = (matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.reduce( (acc, route) => { var _a2; const middlewares = []; if ("search" in route.options) { if ((_a2 = route.options.search) == null ? void 0 : _a2.middlewares) { middlewares.push(...route.options.search.middlewares); } } else if (route.options.preSearchFilters || route.options.postSearchFilters) { const legacyMiddleware = ({ search: search3, next }) => { let nextSearch = search3; if ("preSearchFilters" in route.options && route.options.preSearchFilters) { nextSearch = route.options.preSearchFilters.reduce( (prev, next2) => next2(prev), search3 ); } const result = next(nextSearch); if ("postSearchFilters" in route.options && route.options.postSearchFilters) { return route.options.postSearchFilters.reduce( (prev, next2) => next2(prev), result ); } return result; }; middlewares.push(legacyMiddleware); } if (opts._includeValidateSearch && route.options.validateSearch) { const validate = ({ search: search3, next }) => { const result = next(search3); try { const validatedSearch = { ...result, ...validateSearch( route.options.validateSearch, result ) ?? {} }; return validatedSearch; } catch { return result; } }; middlewares.push(validate); } return acc.concat(middlewares); }, [] )) ?? []; const final = ({ search: search3 }) => { if (!dest.search) { return {}; } if (dest.search === true) { return search3; } return utils.functionalUpdate(dest.search, search3); }; allMiddlewares.push(final); const applyNext = (index, currentSearch) => { if (index >= allMiddlewares.length) { return currentSearch; } const middleware = allMiddlewares[index]; const next = (newSearch) => { return applyNext(index + 1, newSearch); }; return middleware({ search: currentSearch, next }); }; return applyNext(0, search2); }; search = applyMiddlewares(search); search = utils.replaceEqualDeep(fromSearch, search); const searchStr = this.options.stringifySearch(search); const hash = dest.hash === true ? this.latestLocation.hash : dest.hash ? utils.functionalUpdate(dest.hash, this.latestLocation.hash) : void 0; const hashStr = hash ? `#${hash}` : ""; let nextState = dest.state === true ? this.latestLocation.state : dest.state ? utils.functionalUpdate(dest.state, this.latestLocation.state) : {}; nextState = utils.replaceEqualDeep(this.latestLocation.state, nextState); return { pathname, search, searchStr, state: nextState, hash: hash ?? "", href: `${pathname}${searchStr}${hashStr}`, unmaskOnReload: dest.unmaskOnReload }; }; const buildWithMatches = (dest = {}, maskedDest) => { var _a; const next = build(dest); let maskedNext = maskedDest ? build(maskedDest) : void 0; if (!maskedNext) { let params = {}; const foundMask = (_a = this.options.routeMasks) == null ? void 0 : _a.find((d) => { const match = path.matchPathname(this.basepath, next.pathname, { to: d.from, caseSensitive: false, fuzzy: false }); if (match) { params = match; return true; } return false; }); if (foundMask) { const { from: _from, ...maskProps } = foundMask; maskedDest = { ...utils.pick(opts, ["from"]), ...maskProps, params }; maskedNext = build(maskedDest); } } const nextMatches = this.getMatchedRoutes(next, dest); const final = build(dest, nextMatches); if (maskedNext) { const maskedMatches = this.getMatchedRoutes(maskedNext, maskedDest); const maskedFinal = build(maskedDest, maskedMatches); final.maskedLocation = maskedFinal; } return final; }; if (opts.mask) { return buildWithMatches(opts, { ...utils.pick(opts, ["from"]), ...opts.mask }); } return buildWithMatches(opts); }; this.commitLocation = ({ viewTransition, ignoreBlocker, ...next }) => { const isSameState = () => { const ignoredProps = [ "key", "__TSR_index", "__hashScrollIntoViewOptions" ]; ignoredProps.forEach((prop) => { next.state[prop] = this.latestLocation.state[prop]; }); const isEqual = utils.deepEqual(next.state, this.latestLocation.state); ignoredProps.forEach((prop) => { delete next.state[prop]; }); return isEqual; }; const isSameUrl = this.latestLocation.href === next.href; const previousCommitPromise = this.commitLocationPromise; this.commitLocationPromise = utils.createControlledPromise(() => { previousCommitPromise == null ? void 0 : previousCommitPromise.resolve(); }); if (isSameUrl && isSameState()) { this.load(); } else { let { maskedLocation, hashScrollIntoView, ...nextHistory } = next; if (maskedLocation) { nextHistory = { ...maskedLocation, state: { ...maskedLocation.state, __tempKey: void 0, __tempLocation: { ...nextHistory, search: nextHistory.searchStr, state: { ...nextHistory.state, __tempKey: void 0, __tempLocation: void 0, key: void 0 } } } }; if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) { nextHistory.state.__tempKey = this.tempLocationKey; } } nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true; this.shouldViewTransition = viewTransition; this.history[next.replace ? "replace" : "push"]( nextHistory.href, nextHistory.state, { ignoreBlocker } ); } this.resetNextScroll = next.resetScroll ?? true; if (!this.history.subscribers.size) { this.load(); } return this.commitLocationPromise; }; this.buildAndCommitLocation = ({ replace, resetScroll, hashScrollIntoView, viewTransition, ignoreBlocker, href, ...rest } = {}) => { if (href) { const currentIndex = this.history.location.state.__TSR_index; const parsed = history.parseHref(href, { __TSR_index: replace ? currentIndex : currentIndex + 1 }); rest.to = parsed.pathname; rest.search = this.options.parseSearch(parsed.search); rest.hash = parsed.hash.slice(1); } const location = this.buildLocation({ ...rest, _includeValidateSearch: true }); return this.commitLocation({ ...location, viewTransition, replace, resetScroll, hashScrollIntoView, ignoreBlocker }); }; this.navigate = ({ to, reloadDocument, href, ...rest }) => { if (reloadDocument) { if (!href) { const location = this.buildLocation({ to, ...rest }); href = this.history.createHref(location.href); } if (rest.replace) { window.location.replace(href); } else { window.location.href = href; } return; } return this.buildAndCommitLocation({ ...rest, href, to }); }; this.load = async (opts) => { this.latestLocation = this.parseLocation(this.latestLocation); let redirect$1; let notFound$1; let loadPromise; loadPromise = new Promise((resolve) => { this.startTransition(async () => { var _a; try { const next = this.latestLocation; const prevLocation = this.state.resolvedLocation; this.cancelMatches(); let pendingMatches; store.batch(() => { pendingMatches = this.matchRoutes(next); this.__store.setState((s) => ({ ...s, status: "pending", isLoading: true, location: next, pendingMatches, // If a cached moved to pendingMatches, remove it from cachedMatches cachedMatches: s.cachedMatches.filter((d) => { return !pendingMatches.find((e) => e.id === d.id); }) })); }); if (!this.state.redirect) { this.emit({ type: "onBeforeNavigate", ...getLocationChangeInfo({ resolvedLocation: prevLocation, location: next }) }); } this.emit({ type: "onBeforeLoad", ...getLocationChangeInfo({ resolvedLocation: prevLocation, location: next }) }); await this.loadMatches({ sync: opts == null ? void 0 : opts.sync, matches: pendingMatches, location: next, // eslint-disable-next-line @typescript-eslint/require-await onReady: async () => { this.startViewTransition(async () => { let exitingMatches; let enteringMatches; let stayingMatches; store.batch(() => { this.__store.setState((s) => { const previousMatches = s.matches; const newMatches = s.pendingMatches || s.matches; exitingMatches = previousMatches.filter( (match) => !newMatches.find((d) => d.id === match.id) ); enteringMatches = newMatches.filter( (match) => !previousMatches.find((d) => d.id === match.id) ); stayingMatches = previousMatches.filter( (match) => newMatches.find((d) => d.id === match.id) ); return { ...s, isLoading: false, loadedAt: Date.now(), matches: newMatches, pendingMatches: void 0, cachedMatches: [ ...s.cachedMatches, ...exitingMatches.filter((d) => d.status !== "error") ] }; }); this.clearExpiredCache(); }); [ [exitingMatches, "onLeave"], [enteringMatches, "onEnter"], [stayingMatches, "onStay"] ].forEach(([matches, hook]) => { matches.forEach((match) => { var _a2, _b; (_b = (_a2 = this.looseRoutesById[match.routeId].options)[hook]) == null ? void 0 : _b.call(_a2, match); }); }); }); } }); } catch (err) { if (redirect.isResolvedRedirect(err)) { redirect$1 = err; if (!this.isServer) { this.navigate({ ...redirect$1, replace: true, ignoreBlocker: true }); } } else if (notFound.isNotFound(err)) { notFound$1 = err; } this.__store.setState((s) => ({ ...s, statusCode: redirect$1 ? redirect$1.statusCode : notFound$1 ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200, redirect: redirect$1 })); } if (this.latestLoadPromise === loadPromise) { (_a = this.commitLocationPromise) == null ? void 0 : _a.resolve(); this.latestLoadPromise = void 0; this.commitLocationPromise = void 0; } resolve(); }); }); this.latestLoadPromise = loadPromise; await loadPromise; while (this.latestLoadPromise && loadPromise !== this.latestLoadPromise) { await this.latestLoadPromise; } if (this.hasNotFoundMatch()) { this.__store.setState((s) => ({ ...s, statusCode: 404 })); } }; this.startViewTransition = (fn) => { const shouldViewTransition = this.shouldViewTransition ?? this.options.defaultViewTransition; delete this.shouldViewTransition; if (shouldViewTransition && typeof document !== "undefined" && "startViewTransition" in document && typeof document.startViewTransition === "function") { let startViewTransitionParams; if (typeof shouldViewTransition === "object" && this.isViewTransitionTypesSupported) { startViewTransitionParams = { update: fn, types: shouldViewTransition.types }; } else { startViewTransitionParams = fn; } document.startViewTransition(startViewTransitionParams); } else { fn(); } }; this.updateMatch = (id, updater) => { var _a; let updated; const isPending = (_a = this.state.pendingMatches) == null ? void 0 : _a.find((d) => d.id === id); const isMatched = this.state.matches.find((d) => d.id === id); const isCached = this.state.cachedMatches.find((d) => d.id === id); const matchesKey = isPending ? "pendingMatches" : isMatched ? "matches" : isCached ? "cachedMatches" : ""; if (matchesKey) { this.__store.setState((s) => { var _a2; return { ...s, [matchesKey]: (_a2 = s[matchesKey]) == null ? void 0 : _a2.map( (d) => d.id === id ? updated = updater(d) : d ) }; }); } return updated; }; this.getMatch = (matchId) => { return [ ...this.state.cachedMatches, ...this.state.pendingMatches ?? [], ...this.state.matches ].find((d) => d.id === matchId); }; this.loadMatches = async ({ location, matches, preload: allPreload, onReady, updateMatch = this.updateMatch, sync }) => { let firstBadMatchIndex; let rendered = false; const triggerOnReady = async () => { if (!rendered) { rendered = true; await (onReady == null ? void 0 : onReady()); } }; const resolvePreload = (matchId) => { return !!(allPreload && !this.state.matches.find((d) => d.id === matchId)); }; if (!this.isServer && !this.state.matches.length) { triggerOnReady(); } const handleRedirectAndNotFound = (match, err) => { var _a, _b, _c, _d; if (redirect.isResolvedRedirect(err)) { if (!err.reloadDocument) { throw err; } } if (redirect.isRedirect(err) || notFound.isNotFound(err)) { updateMatch(match.id, (prev) => ({ ...prev, status: redirect.isRedirect(err) ? "redirected" : notFound.isNotFound(err) ? "notFound" : "error", isFetching: false, error: err, beforeLoadPromise: void 0, loaderPromise: void 0 })); if (!err.routeId) { err.routeId = match.routeId; } (_a = match.beforeLoadPromise) == null ? void 0 : _a.resolve(); (_b = match.loaderPromise) == null ? void 0 : _b.resolve(); (_c = match.loadPromise) == null ? void 0 : _c.resolve(); if (redirect.isRedirect(err)) { rendered = true; err = this.resolveRedirect({ ...err, _fromLocation: location }); throw err; } else if (notFound.isNotFound(err)) { this._handleNotFound(matches, err, { updateMatch }); (_d = this.serverSsr) == null ? void 0 : _d.onMatchSettled({ router: this, match: this.getMatch(match.id) }); throw err; } } }; try { await new Promise((resolveAll, rejectAll) => { ; (async () => { var _a, _b, _c, _d; try { const handleSerialError = (index, err, routerCode) => { var _a2, _b2; const { id: matchId, routeId } = matches[index]; const route = this.looseRoutesById[routeId]; if (err instanceof Promise) { throw err; } err.routerCode = routerCode; firstBadMatchIndex = firstBadMatchIndex ?? index; handleRedirectAndNotFound(this.getMatch(matchId), err); try { (_b2 = (_a2 = route.options).onError) == null ? void 0 : _b2.call(_a2, err); } catch (errorHandlerErr) { err = errorHandlerErr; handleRedirectAndNotFound(this.getMatch(matchId), err); } updateMatch(matchId, (prev) => { var _a3, _b3; (_a3 = prev.beforeLoadPromise) == null ? void 0 : _a3.resolve(); (_b3 = prev.loadPromise) == null ? void 0 : _b3.resolve(); return { ...prev, error: err, status: "error", isFetching: false, updatedAt: Date.now(), abortController: new AbortController(), beforeLoadPromise: void 0 }; }); }; for (const [index, { id: matchId, routeId }] of matches.entries()) { const existingMatch = this.getMatch(matchId); const parentMatchId = (_a = matches[index - 1]) == null ? void 0 : _a.id; const route = this.looseRoutesById[routeId]; const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs; const shouldPending = !!(onReady && !this.isServer && !resolvePreload(matchId) && (route.options.loader || route.options.beforeLoad) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? ((_b = this.options) == null ? void 0 : _b.defaultPendingComponent))); let executeBeforeLoad = true; if ( // If we are in the middle of a load, either of these will be present // (not to be confused with `loadPromise`, which is always defined) existingMatch.beforeLoadPromise || existingMatch.loaderPromise ) { if (shouldPending) { setTimeout(() => { try { triggerOnReady(); } catch { } }, pendingMs); } await existingMatch.beforeLoadPromise; executeBeforeLoad = this.getMatch(matchId).status !== "success"; } if (executeBeforeLoad) { try { updateMatch(matchId, (prev) => { const prevLoadPromise = prev.loadPromise; return { ...prev, loadPromise: utils.createControlledPromise(() => { prevLoadPromise == null ? void 0 : prevLoadPromise.resolve(); }), beforeLoadPromise: utils.createControlledPromise() }; }); const abortController = new AbortController(); let pendingTimeout; if (shouldPending) { pendingTimeout = setTimeout(() => { try { triggerOnReady(); } catch { } }, pendingMs); } const { paramsError, searchError } = this.getMatch(matchId); if (paramsError) { handleSerialError(index, paramsError, "PARSE_PARAMS"); } if (searchError) { handleSerialError(index, searchError, "VALIDATE_SEARCH"); } const getParentMatchContext = () => parentMatchId ? this.getMatch(parentMatchId).context : this.options.context ?? {}; updateMatch(matchId, (prev) => ({ ...prev, isFetching: "beforeLoad", fetchCount: prev.fetchCount + 1, abortController, pendingTimeout, context: { ...getParentMatchContext(), ...prev.__routeContext } })); const { search, params, context, cause } = this.getMatch(matchId); const preload = resolvePreload(matchId); const beforeLoadFnContext = { search, abortController, params, preload, context, location, navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }), buildLocation: this.buildLocation, cause: preload ? "preload" : cause, matches }; const beforeLoadContext = await ((_d = (_c = route.options).beforeLoad) == null ? void 0 : _d.call(_c, beforeLoadFnContext)) ?? {}; if (redirect.isRedirect(beforeLoadContext) || notFound.isNotFound(beforeLoadContext)) { handleSerialError(index, beforeLoadContext, "BEFORE_LOAD"); } updateMatch(matchId, (prev) => { return { ...prev, __beforeLoadContext: beforeLoadContext, context: { ...getParentMatchContext(), ...prev.__routeContext, ...beforeLoadContext }, abortController }; }); } catch (err) { handleSerialError(index, err, "BEFORE_LOAD"); } updateMatch(matchId, (prev) => { var _a2; (_a2 = prev.beforeLoadPromise) == null ? void 0 : _a2.resolve(); return { ...prev, beforeLoadPromise: void 0, isFetching: false }; }); } } const validResolvedMatches = matches.slice(0, firstBadMatchIndex); const matchPromises = []; validResolvedMatches.forEach(({ id: matchId, routeId }, index) => { matchPromises.push( (async () => { const { loaderPromise: prevLoaderPromise } = this.getMatch(matchId); let loaderShouldRunAsync = false; let loaderIsRunningAsync = false; if (prevLoaderPromise) { await prevLoaderPromise; const match = this.getMatch(matchId); if (match.error) { handleRedirectAndNotFound(match, match.error); } } else { const parentMatchPromise = matchPromises[index - 1]; const route = this.looseRoutesById[routeId]; const getLoaderContext = () => { const { params, loaderDeps, abortController, context, cause } = this.getMatch(matchId); const preload2 = resolvePreload(matchId); return { params, deps: loaderDeps, preload: !!preload2, parentMatchPromise, abortController, context, location, navigate: (opts) => this.navigate({ ...opts, _fromLocation: location }), cause: preload2 ? "preload" : cause, route }; }; const age = Date.now() - this.getMatch(matchId).updatedAt; const preload = resolvePreload(matchId); const staleAge = preload ? route.options.preloadStaleTime ?? this.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? this.options.defaultStaleTime ?? 0; const shouldReloadOption = route.options.shouldReload; const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(getLoaderContext()) : shouldReloadOption; updateMatch(matchId, (prev) => ({ ...prev, loaderPromise: utils.createControlledPromise(), preload: !!preload && !this.state.matches.find((d) => d.id === matchId) })); const runLoader = async () => { var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k; try { const potentialPendingMinPromise = async () => { const latestMatch = this.getMatch(matchId); if (latestMatch.minPendingPromise) { await latestMatch.minPendingPromise; } }; try { this.loadRouteChunk(route); updateMatch(matchId, (prev) => ({ ...prev, isFetching: "loader" })); const loaderData = await ((_b2 = (_a2 = route.options).loader) == null ? void 0 : _b2.call(_a2, getLoaderContext())); handleRedirectAndNotFound( this.getMatch(matchId), loaderData ); await route._lazyPromise; await potentialPendingMinPromise(); const assetContext = { matches, match: this.getMatch(matchId), params: this.getMatch(matchId).params, loaderData }; const headFnContent = (_d2 = (_c2 = route.options).head) == null ? void 0 : _d2.call(_c2, assetContext); const meta = headFnContent == null ? void 0 : headFnContent.meta; const links = headFnContent == null ? void 0 : headFnContent.links; const headScripts = headFnContent == null ? void 0 : headFnContent.scripts; const scripts = (_f = (_e = route.options).scripts) == null ? void 0 : _f.call(_e, assetContext); const headers = (_h = (_g = route.options).headers) == null ? void 0 : _h.call(_g, { loaderData }); updateMatch(matchId, (prev) => ({ ...prev, error: void 0, status: "success", isFetching: false, updatedAt: Date.now(), loaderData, meta, links, headScripts, headers, scripts })); } catch (e) { let error = e; await potentialPendingMinPromise(); handleRedirectAndNotFound(this.getMatch(matchId), e); try { (_j = (_i = route.options).onError) == null ? void 0 : _j.call(_i, e); } catch (onErrorError) { error = onErrorError; handleRedirectAndNotFound( this.getMatch(matchId), onErrorError ); } updateMatch(matchId, (prev) => ({ ...prev, error, status: "error", isFetching: false })); } (_k = this.serverSsr) == null ? void 0 : _k.onMatchSettled({ router: this, match: this.getMatch(matchId) }); await route._componentsPromise; } catch (err) { updateMatch(matchId, (prev) => ({ ...prev, loaderPromise: void 0 })); handleRedirectAndNotFound(this.getMatch(matchId), err); } }; const { status, invalid } = this.getMatch(matchId); loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge)); if (preload && route.options.preload === false) { } else if (loaderShouldRunAsync && !sync) { loaderIsRunningAsync = true; (async () => { try { await runLoader(); const { loaderPromise, loadPromise } = this.getMatch(matchId); loaderPromise == null ? void 0 : loaderPromise.resolve(); loadPromise == null ? void 0 : loadPromise.resolve(); updateMatch(matchId, (prev) => ({ ...prev, loaderPromise: void 0 })); } catch (err) { if (redirect.isResolvedRedirect(err)) { await this.navigate(err); } } })(); } else if (status !== "success" || loaderShouldRunAsync && sync) { await runLoader(); } } if (!loaderIsRunningAsync) { const { loaderPromise, loadPromise } = this.getMatch(matchId); loaderPromise == null ? void 0 : loaderPromise.resolve(); loadPromise == null ? void 0 : loadPromise.resolve(); } updateMatch(matchId, (prev) => ({ ...prev, isFetching: loaderIsRunningAsync ? prev.isFetching : false, loaderPromise: loaderIsRunningAsync ? prev.loaderPromise : void 0, invalid: false })); return this.getMatch(matchId); })() ); }); await Promise.all(matchPromises); resolveAll(); } catch (err) { rejectAll(err); } })(); }); await triggerOnReady(); } catch (err) { if (redirect.isRedirect(err) || notFound.isNotFound(err)) { if (notFound.isNotFound(err) && !allPreload) { await triggerOnReady(); } throw err; } } return matches; }; this.invalidate = (opts) => { const invalidate = (d) => { var _a; if (((_a = opts == null ? void 0 : opts.filter) == null ? void 0 : _a.call(opts, d)) ?? true) { return { ...d, invalid: true, ...d.status === "error" ? { status: "pending", error: void 0 } : {} }; } return d; }; this.__store.setState((s) => { var _a; return { ...s, matches: s.matches.map(invalidate), cachedMatches: s.cachedMatches.map(invalidate), pendingMatches: (_a = s.pendingMatches) == null ? void 0 : _a.map(invalidate) }; }); return this.load({ sync: opts == null ? void 0 : opts.sync }); }; this.resolveRedirect = (err) => { const redirect2 = err; if (!redirect2.href) { redirect2.href = this.buildLocation(redirect2).href; } return redirect2; }; this.clearCache = (opts) => { const filter = opts == null ? void 0 : opts.filter; if (filter !== void 0) { this.__store.setState((s) => { return { ...s, cachedMatches: s.cachedMatches.filter( (m) => !filter(m) ) }; }); } else { this.__store.setState((s) => { return { ...s, cachedMatches: [] }; }); } }; this.clearExpiredCache = () => { const filter = (d) => { const route = this.looseRoutesById[d.routeId]; if (!route.options.loader) { return true; } const gcTime = (d.preload ? route.options.preloadGcTime ?? this.options.defaultPreloadGcTime : route.options.gcTime ?? this.options.defaultGcTime) ?? 5 * 60 * 1e3; return !(d.status !== "error" && Date.now() - d.updatedAt < gcTime); }; this.clearCache({ filter }); }; this.loadRouteChunk = (route) => { if (route._lazyPromise === void 0) { if (route.lazyFn) { route._lazyPromise = route.lazyFn().then((lazyRoute) => { const { id: _id, ...options2 } = lazyRoute.options; Object.assign(route.options, options2); }); } else { route._lazyPromise = Promise.resolve(); } } if (route._componentsPromise === void 0) { route._componentsPromise = route._lazyPromise.then( () => Promise.all( componentTypes.map(async (type) => { const component = route.options[type]; if (component == null ? void 0 : component.preload) { await component.preload(); } }) ) ); } return route._componentsPromise; }; this.preloadRoute = async (opts) => { const next = this.buildLocation(opts); let matches = this.matchRoutes(next, { throwOnError: true, preload: true, dest: opts }); const activeMatchIds = new Set( [...this.state.matches, ...this.state.pendingMatches ?? []].map( (d) => d.id ) ); const loadedMatchIds = /* @__PURE__ */ new Set([ ...activeMatchIds, ...this.state.cachedMatches.map((d) => d.id) ]); store.batch(() => { matches.forEach((match) => { if (!loadedMatchIds.has(match.id)) { this.__store.setState((s) => ({ ...s, cachedMatches: [...s.cachedMatches, match] })); } }); }); try { matches = await this.loadMatches({ matches, location: next, preload: true, updateMatch: (id, updater) => { if (activeMatchIds.has(id)) { matches = matches.map((d) => d.id === id ? updater(d) : d); } else { this.updateMatch(id, updater); } } }); return matches; } catch (err) { if (redirect.isRedirect(err)) { if (err.reloadDocument) { return void 0; } return await this.preloadRoute({ ...err, _fromLocation: next }); } if (!notFound.isNotFound(err)) { console.error(err); } return void 0; } }; this.matchRoute = (location, opts) => { const matchLocation = { ...location, to: location.to ? this.resolvePathWithBase( location.from || "", location.to ) : void 0, params: location.params || {}, leaveParams: true }; const next = this.buildLocation(matchLocation); if ((opts == null ? void 0 : opts.pending) && this.state.status !== "pending") { return false; } const pending = (opts == null ? void 0 : opts.pending) === void 0 ? !this.state.isLoading : opts.pending; const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location; const match = path.matchPathname(this.basepath, baseLocation.pathname, { ...opts, to: next.pathname }); if (!match) { return false; } if (location.params) { if (!utils.deepEqual(match, location.params, { partial: true })) { return false; } } if (match && ((opts == null ? void 0 : opts.includeSearch) ?? true)) { return utils.deepEqual(baseLocation.search, next.search, { partial: true }) ? match : false; } return match; }; this._handleNotFound = (matches, err, { updateMatch = this.updateMatch } = {}) => { var _a; const routeCursor = this.routesById[err.routeId ?? ""] ?? this.routeTree; const matchesByRouteId = {}; for (const match of matches) { matchesByRouteId[match.routeId] = match; } if (!routeCursor.options.notFoundComponent && ((_a = this.options) == null ? void 0 : _a.defaultNotFoundComponent)) { routeCursor.options.notFoundComponent = this.options.defaultNotFoundComponent; } invariant( routeCursor.options.notFoundComponent, "No notFoundComponent found. Please set a notFoundComponent on your route or provide a defaultNotFoundComponent to the router." ); const matchForRoute = matchesByRouteId[routeCursor.id]; invariant( matchForRoute, "Could not find match for route: " + routeCursor.id ); updateMatch(matchForRoute.id, (prev) => ({ ...prev, status: "notFound", error: err, isFetching: false })); if (err.routerCode === "BEFORE_LOAD" && routeCursor.parentRoute) { err.routeId = routeCursor.parentRoute.id; this._handleNotFound(matches, err, { updateMatch }); } }; this.hasNotFoundMatch = () => { return this.__store.state.matches.some( (d) => d.status === "notFound" || d.globalNotFound ); }; this.update({ defaultPreloadDelay: 50, defaultPendingMs: 1e3, defaultPendingMinMs: 500, context: void 0, ...options, caseSensitive: options.caseSensitive ?? false, notFoundMode: options.notFoundMode ?? "fuzzy", stringifySearch: options.stringifySearch ?? searchParams.defaultStringifySearch, parseSearch: options.parseSearch ?? searchParams.defaultParseSearch }); if (typeof document !== "undefined") { window.__TSR_ROUTER__ = this; } } get state() { return this.__store.state; } get looseRoutesById() { return this.routesById; } matchRoutesInternal(next, opts) { const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes( next, opts == null ? void 0 : opts.dest ); let isGlobalNotFound = false; if ( // If we found a route, and it's not an index route and we have left over path foundRoute ? foundRoute.path !== "/" && routeParams["**"] : ( // Or if we didn't find a route and we have left over path path.trimPathRight(next.pathname) ) ) { if (this.options.notFoundRoute) { matchedRoutes.push(this.options.notFoundRoute); } else { isGlobalNotFound = true; } } const globalNotFoundRouteId = (() => { if (!isGlobalNotFound) { return void 0; } if (this.options.notFoundMode !== "root") { for (let i = matchedRoutes.length - 1; i >= 0; i--) { const route = matchedRoutes[i]; if (route.children) { return route.id; } } } return root.rootRouteId; })(); const parseErrors = matchedRoutes.map((route) => { var _a; let parsedParamsError; const parseParams = ((_a = route.options.params) == null ? void 0 : _a.parse) ?? route.options.parseParams; if (parseParams) { try { const parsedParams = parseParams(routeParams); Object.assign(routeParams, parsedParams); } catch (err) { parsedParamsError = new PathParamError(err.message, { cause: err }); if (opts == null ? void 0 : opts.throwOnError) { throw parsedParamsError; } return parsedParamsError; } } return; }); const matches = []; const getParentContext = (parentMatch) => { const parentMatchId = parentMatch == null ? void 0 : parentMatch.id; const parentContext = !parentMatchId ? this.options.context ?? {} : parentMatch.context ?? this.options.context ?? {}; return parentContext; }; matchedRoutes.forEach((route, index) => { var _a, _b; const parentMatch = matches[index - 1]; const [preMatchSearch, strictMatchSearch, searchError] = (() => { const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? next.search; const parentStrictSearch = (parentMatch == null ? void 0 : parentMatch._strictSearch) ?? {}; try { const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ?? {}; return [ { ...parentSearch, ...strictSearch }, { ...parentStrictSearch, ...strictSearch }, void 0 ]; } catch (err) { let searchParamError = err; if (!(err instanceof SearchParamError)) { searchParamError = new SearchParamError(err.message, { cause: err }); } if (opts == null ? void 0 : opts.throwOnError) { throw searchParamError; } return [parentSearch, {}, searchParamError]; } })(); const loaderDeps = ((_b = (_a = route.options).loaderDeps) == null ? void 0 : _b.call(_a, { search: preMatchSearch })) ?? ""; const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : ""; const { usedParams, interpolatedPath } = path.interpolatePath({ path: route.fullPath, params: routeParams, decodeCharMap: this.pathParamsDecodeCharMap }); const matchId = path.interpolatePath({ path: route.id, params: routeParams, leaveWildcards: true, decodeCharMap: this.pathParamsDecodeCharMap }).interpolatedPath + loaderDepsHash; const existingMatch = this.getMatch(matchId); const previousMatch = this.state.matches.find( (d) => d.routeId === route.id ); const cause = previousMatch ? "stay" : "enter"; let match; if (existingMatch) { match = { ...existingMatch, cause, params: previousMatch ? utils.replaceEqualDeep(previousMatch.params, routeParams) : routeParams, _strictParams: usedParams, search: previousMatch ? utils.replaceEqualDeep(previousMatch.search, preMatchSearch) : utils.replaceEqualDeep(existingMatch.search, preMatchSearch), _strictSearch: strictMatchSearch }; } else { const status = route.options.loader || route.options.beforeLoad || route.lazyFn || routeNeedsPreload(route) ? "pending" : "success"; match = { id: matchId, index, routeId: route.id, params: previousMatch ? utils.replaceEqualDeep(previousMatch.params, routeParams) : routeParams, _strictParams: usedParams, pathname: path.joinPaths([this.basepath, interpolatedPath]), updatedAt: Date.now(), search: previousMatch ? utils.replaceEqualDeep(previousMatch.search, preMatchSearch) : preMatchSearch, _strictSearch: strictMatchSearch, searchError: void 0, status, isFetching: false, error: void 0, paramsError: parseErrors[index], __routeContext: {}, __beforeLoadContext: {}, context: {}, abortController: new AbortController(), fetchCount: 0, cause, loaderDeps: previousMatch ? utils.replaceEqualDeep(previousMatch.loaderDeps, loaderDeps) : loaderDeps, invalid: false, preload: false, links: void 0, scripts: void 0, headScripts: void 0, meta: void 0, staticData: route.options.staticData || {}, loadPromise: utils.createControlledPromise(), fullPath: route.fullPath }; } if (!(opts == null ? void 0 : opts.preload)) { match.globalNotFound = globalNotFoundRouteId === route.id; } match.searchError = searchError; const parentContext = getParentContext(parentMatch); match.context = { ...parentContext, ...match.__routeContext, ...match.__beforeLoadContext }; matches.push(match); }); matches.forEach((match, index) => { var _a, _b, _c, _d, _e, _f, _g, _h; const route = this.looseRoutesById[match.routeId]; const existingMatch = this.getMatch(match.id); if (!existingMatch && (opts == null ? void 0 : opts._buildLocation) !== true) { const parentMatch = matches[index - 1]; const parentContext = getParentContext(parentMatch); const contextFnContext = { deps: match.loaderDeps, params: match.params, context: parentContext, location: next, navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }), buildLocation: this.buildLocation, cause: match.cause, abortController: match.abortController, preload: !!match.preload, matches }; match.__routeContext = ((_b = (_a = route.options).context) == null ? void 0 : _b.call(_a, contextFnContext)) ?? {}; match.context = { ...parentContext, ...match.__routeContext, ...match.__beforeLoadContext }; } if (match.status === "success") { match.headers = (_d = (_c = route.options).headers) == null ? void 0 : _d.call(_c, { loaderData: match.loaderData }); const assetContext = { matches, match, params: match.params, loaderData: match.loaderData }; const headFnContent = (_f = (_e = route.options).head) == null ? void 0 : _f.call(_e, assetContext); match.links = headFnContent == null ? void 0 : headFnContent.links; match.headScripts = headFnContent == null ? void 0 : headFnContent.scripts; match.meta = headFnContent == null ? void 0 : headFnContent.meta; match.scripts = (_h = (_g = route.options).scripts) == null ? void 0 : _h.call(_g, assetContext); } }); return matches; } } class SearchParamError extends Error { } class PathParamError extends Error { } function lazyFn(fn, key) { return async (...args) => { const imported = await fn(); return imported[key || "default"](...args); }; } function getInitialRouterState(location) { return { loadedAt: 0, isLoading: false, isTransitioning: false, status: "idle", resolvedLocation: void 0, location, matches: [], pendingMatches: [], cachedMatches: [], statusCode: 200 }; } function validateSearch(validateSearch2, input) { if (validateSearch2 == null) return {}; if ("~standard" in validateSearch2) { const result = validateSearch2["~standard"].validate(input); if (result instanceof Promise) throw new SearchParamError("Async validation not supported"); if (result.issues) throw new SearchParamError(JSON.stringify(result.issues, void 0, 2), { cause: result }); return result.value; } if ("parse" in validateSearch2) { return validateSearch2.parse(input); } if (typeof validateSearch2 === "function") { return validateSearch2(input); } return {}; } const componentTypes = [ "component", "errorComponent", "pendingComponent", "notFoundComponent" ]; function routeNeedsPreload(route) { var _a; for (const componentType of componentTypes) { if ((_a = route.options[componentType]) == null ? void 0 : _a.preload) { return true; } } return false; } exports.PathParamError = PathParamError; exports.RouterCore = RouterCore; exports.SearchParamError = SearchParamError; exports.componentTypes = componentTypes; exports.defaultSerializeError = defaultSerializeError; exports.getInitialRouterState = getInitialRouterState; exports.getLocationChangeInfo = getLocationChangeInfo; exports.lazyFn = lazyFn; //# sourceMappingURL=router.cjs.map