{"version":3,"sources":["../../../../src/client/components/router-reducer/aliased-prefetch-navigations.ts"],"sourcesContent":["import type {\n CacheNodeSeedData,\n FlightRouterState,\n FlightSegmentPath,\n} from '../../../shared/lib/app-router-types'\nimport type { CacheNode } from '../../../shared/lib/app-router-types'\nimport {\n addSearchParamsIfPageSegment,\n DEFAULT_SEGMENT_KEY,\n PAGE_SEGMENT_KEY,\n} from '../../../shared/lib/segment'\nimport type { NormalizedFlightData } from '../../flight-data-helpers'\nimport { createEmptyCacheNode } from '../app-router'\nimport { applyRouterStatePatchToTree } from './apply-router-state-patch-to-tree'\nimport { createHrefFromUrl } from './create-href-from-url'\nimport { createRouterCacheKey } from './create-router-cache-key'\nimport { fillCacheWithNewSubTreeDataButOnlyLoading } from './fill-cache-with-new-subtree-data'\nimport { handleMutable } from './handle-mutable'\nimport { generateSegmentsFromPatch } from './reducers/navigate-reducer'\nimport type { Mutable, ReadonlyReducerState } from './router-reducer-types'\n\n/**\n * This is a stop-gap until per-segment caching is implemented. It leverages the `aliased` flag that is added\n * to prefetch entries when it's determined that the loading state from that entry should be used for this navigation.\n * This function takes the aliased entry and only applies the loading state to the updated cache node.\n * We should remove this once per-segment fetching is implemented as ideally the prefetch cache will contain a\n * more granular segment map and so the router will be able to simply re-use the loading segment for the new navigation.\n */\nexport function handleAliasedPrefetchEntry(\n navigatedAt: number,\n state: ReadonlyReducerState,\n flightData: string | NormalizedFlightData[],\n url: URL,\n renderedSearch: string,\n mutable: Mutable\n) {\n let currentTree = state.tree\n let currentCache = state.cache\n const href = createHrefFromUrl(url)\n let applied\n let scrollableSegments: FlightSegmentPath[] = []\n\n if (typeof flightData === 'string') {\n return false\n }\n\n for (const normalizedFlightData of flightData) {\n // If the segment doesn't have a loading component, we don't need to do anything.\n if (!hasLoadingComponentInSeedData(normalizedFlightData.seedData)) {\n continue\n }\n\n let treePatch = normalizedFlightData.tree\n // Segments are keyed by searchParams (e.g. __PAGE__?{\"foo\":\"bar\"}). We might return a less specific, param-less entry,\n // so we ensure that the final tree contains the correct searchParams (reflected in the URL) are provided in the updated FlightRouterState tree.\n // We only do this on the first read, as otherwise we'd be overwriting the searchParams that may have already been set\n treePatch = addSearchParamsToPageSegments(\n treePatch,\n Object.fromEntries(url.searchParams)\n )\n\n const { seedData, isRootRender, pathToSegment } = normalizedFlightData\n // TODO-APP: remove ''\n const flightSegmentPathWithLeadingEmpty = ['', ...pathToSegment]\n\n // Segments are keyed by searchParams (e.g. __PAGE__?{\"foo\":\"bar\"}). We might return a less specific, param-less entry,\n // so we ensure that the final tree contains the correct searchParams (reflected in the URL) are provided in the updated FlightRouterState tree.\n // We only do this on the first read, as otherwise we'd be overwriting the searchParams that may have already been set\n treePatch = addSearchParamsToPageSegments(\n treePatch,\n Object.fromEntries(url.searchParams)\n )\n\n let newTree = applyRouterStatePatchToTree(\n flightSegmentPathWithLeadingEmpty,\n currentTree,\n treePatch,\n href\n )\n\n const newCache = createEmptyCacheNode()\n\n // The prefetch cache entry was aliased -- this signals that we only fill in the cache with the\n // loading state and not the actual parallel route seed data.\n if (isRootRender && seedData) {\n // Fill in the cache with the new loading / rsc data\n const rsc = seedData[0]\n const loading = seedData[2]\n newCache.loading = loading\n newCache.rsc = rsc\n\n // Construct a new tree and apply the aliased loading state for each parallel route\n fillNewTreeWithOnlyLoadingSegments(\n navigatedAt,\n newCache,\n currentCache,\n treePatch,\n seedData\n )\n } else {\n // Copy rsc for the root node of the cache.\n newCache.rsc = currentCache.rsc\n newCache.prefetchRsc = currentCache.prefetchRsc\n newCache.loading = currentCache.loading\n newCache.parallelRoutes = new Map(currentCache.parallelRoutes)\n\n // copy the loading state only into the leaf node (the part that changed)\n fillCacheWithNewSubTreeDataButOnlyLoading(\n navigatedAt,\n newCache,\n currentCache,\n normalizedFlightData\n )\n }\n\n // If we don't have an updated tree, there's no reason to update the cache, as the tree\n // dictates what cache nodes to render.\n if (newTree) {\n currentTree = newTree\n currentCache = newCache\n applied = true\n }\n\n for (const subSegment of generateSegmentsFromPatch(treePatch)) {\n const scrollableSegmentPath = [\n ...normalizedFlightData.pathToSegment,\n ...subSegment,\n ]\n // Filter out the __DEFAULT__ paths as they shouldn't be scrolled to in this case.\n if (\n scrollableSegmentPath[scrollableSegmentPath.length - 1] !==\n DEFAULT_SEGMENT_KEY\n ) {\n scrollableSegments.push(scrollableSegmentPath)\n }\n }\n }\n\n if (!applied) {\n return false\n }\n\n mutable.patchedTree = currentTree\n mutable.renderedSearch = renderedSearch\n mutable.cache = currentCache\n mutable.canonicalUrl = href\n mutable.hashFragment = url.hash\n mutable.scrollableSegments = scrollableSegments\n\n return handleMutable(state, mutable)\n}\n\nfunction hasLoadingComponentInSeedData(seedData: CacheNodeSeedData | null) {\n if (!seedData) return false\n\n const parallelRoutes = seedData[1]\n const loading = seedData[2]\n\n if (loading) {\n return true\n }\n\n for (const key in parallelRoutes) {\n if (hasLoadingComponentInSeedData(parallelRoutes[key])) {\n return true\n }\n }\n\n return false\n}\n\nfunction fillNewTreeWithOnlyLoadingSegments(\n navigatedAt: number,\n newCache: CacheNode,\n existingCache: CacheNode,\n routerState: FlightRouterState,\n cacheNodeSeedData: CacheNodeSeedData | null\n) {\n const isLastSegment = Object.keys(routerState[1]).length === 0\n if (isLastSegment) {\n return\n }\n\n for (const key in routerState[1]) {\n const parallelRouteState = routerState[1][key]\n const segmentForParallelRoute = parallelRouteState[0]\n const cacheKey = createRouterCacheKey(segmentForParallelRoute)\n\n const parallelSeedData =\n cacheNodeSeedData !== null && cacheNodeSeedData[1][key] !== undefined\n ? cacheNodeSeedData[1][key]\n : null\n\n let newCacheNode: CacheNode\n if (parallelSeedData !== null) {\n // New data was sent from the server.\n const rsc = parallelSeedData[0]\n const loading = parallelSeedData[2]\n newCacheNode = {\n lazyData: null,\n // copy the layout but null the page segment as that's not meant to be used\n rsc: segmentForParallelRoute.includes(PAGE_SEGMENT_KEY) ? null : rsc,\n prefetchRsc: null,\n head: null,\n prefetchHead: null,\n parallelRoutes: new Map(),\n loading,\n navigatedAt,\n }\n } else {\n // No data available for this node. This will trigger a lazy fetch\n // during render.\n newCacheNode = {\n lazyData: null,\n rsc: null,\n prefetchRsc: null,\n head: null,\n prefetchHead: null,\n parallelRoutes: new Map(),\n loading: null,\n navigatedAt: -1,\n }\n }\n\n const existingParallelRoutes = newCache.parallelRoutes.get(key)\n if (existingParallelRoutes) {\n existingParallelRoutes.set(cacheKey, newCacheNode)\n } else {\n newCache.parallelRoutes.set(key, new Map([[cacheKey, newCacheNode]]))\n }\n\n fillNewTreeWithOnlyLoadingSegments(\n navigatedAt,\n newCacheNode,\n existingCache,\n parallelRouteState,\n parallelSeedData\n )\n }\n}\n\n/**\n * Add search params to the page segments in the flight router state\n * Page segments that are associated with search params have a page segment key\n * followed by a query string. This function will add those params to the page segment.\n * This is useful if we return an aliased prefetch entry (ie, won't have search params)\n * but the canonical router URL has search params.\n */\nexport function addSearchParamsToPageSegments(\n flightRouterState: FlightRouterState,\n searchParams: Record\n): FlightRouterState {\n const [segment, parallelRoutes, ...rest] = flightRouterState\n\n // If it's a page segment, modify the segment by adding search params\n if (segment.includes(PAGE_SEGMENT_KEY)) {\n const newSegment = addSearchParamsIfPageSegment(segment, searchParams)\n return [newSegment, parallelRoutes, ...rest]\n }\n\n // Otherwise, recurse through the parallel routes and return a new tree\n const updatedParallelRoutes: { [key: string]: FlightRouterState } = {}\n\n for (const [key, parallelRoute] of Object.entries(parallelRoutes)) {\n updatedParallelRoutes[key] = addSearchParamsToPageSegments(\n parallelRoute,\n searchParams\n )\n }\n\n return [segment, updatedParallelRoutes, ...rest]\n}\n"],"names":["addSearchParamsToPageSegments","handleAliasedPrefetchEntry","navigatedAt","state","flightData","url","renderedSearch","mutable","currentTree","tree","currentCache","cache","href","createHrefFromUrl","applied","scrollableSegments","normalizedFlightData","hasLoadingComponentInSeedData","seedData","treePatch","Object","fromEntries","searchParams","isRootRender","pathToSegment","flightSegmentPathWithLeadingEmpty","newTree","applyRouterStatePatchToTree","newCache","createEmptyCacheNode","rsc","loading","fillNewTreeWithOnlyLoadingSegments","prefetchRsc","parallelRoutes","Map","fillCacheWithNewSubTreeDataButOnlyLoading","subSegment","generateSegmentsFromPatch","scrollableSegmentPath","length","DEFAULT_SEGMENT_KEY","push","patchedTree","canonicalUrl","hashFragment","hash","handleMutable","key","existingCache","routerState","cacheNodeSeedData","isLastSegment","keys","parallelRouteState","segmentForParallelRoute","cacheKey","createRouterCacheKey","parallelSeedData","undefined","newCacheNode","lazyData","includes","PAGE_SEGMENT_KEY","head","prefetchHead","existingParallelRoutes","get","set","flightRouterState","segment","rest","newSegment","addSearchParamsIfPageSegment","updatedParallelRoutes","parallelRoute","entries"],"mappings":"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","ignoreList":[0]}