"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { handleExternalUrl: null, navigateReducer: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { handleExternalUrl: function() { return handleExternalUrl; }, navigateReducer: function() { return navigateReducer; } }); const _approutercontextsharedruntime = require("../../../../shared/lib/app-router-context.shared-runtime"); const _fetchserverresponse = require("../fetch-server-response"); const _createrecordfromthenable = require("../create-record-from-thenable"); const _readrecordvalue = require("../read-record-value"); const _createhreffromurl = require("../create-href-from-url"); const _invalidatecachebelowflightsegmentpath = require("../invalidate-cache-below-flight-segmentpath"); const _fillcachewithdataproperty = require("../fill-cache-with-data-property"); const _createoptimistictree = require("../create-optimistic-tree"); const _applyrouterstatepatchtotree = require("../apply-router-state-patch-to-tree"); const _shouldhardnavigate = require("../should-hard-navigate"); const _isnavigatingtonewrootlayout = require("../is-navigating-to-new-root-layout"); const _routerreducertypes = require("../router-reducer-types"); const _handlemutable = require("../handle-mutable"); const _applyflightdata = require("../apply-flight-data"); const _getprefetchcacheentrystatus = require("../get-prefetch-cache-entry-status"); const _pruneprefetchcache = require("./prune-prefetch-cache"); const _prefetchreducer = require("./prefetch-reducer"); function handleExternalUrl(state, mutable, url, pendingPush) { mutable.previousTree = state.tree; mutable.mpaNavigation = true; mutable.canonicalUrl = url; mutable.pendingPush = pendingPush; mutable.scrollableSegments = undefined; return (0, _handlemutable.handleMutable)(state, mutable); } function generateSegmentsFromPatch(flightRouterPatch) { const segments = []; const [segment, parallelRoutes] = flightRouterPatch; if (Object.keys(parallelRoutes).length === 0) { return [ [ segment ] ]; } for (const [parallelRouteKey, parallelRoute] of Object.entries(parallelRoutes)){ for (const childSegment of generateSegmentsFromPatch(parallelRoute)){ // If the segment is empty, it means we are at the root of the tree if (segment === "") { segments.push([ parallelRouteKey, ...childSegment ]); } else { segments.push([ segment, parallelRouteKey, ...childSegment ]); } } } return segments; } function addRefetchToLeafSegments(newCache, currentCache, flightSegmentPath, treePatch, data) { let appliedPatch = false; newCache.status = _approutercontextsharedruntime.CacheStates.READY; newCache.subTreeData = currentCache.subTreeData; newCache.parallelRoutes = new Map(currentCache.parallelRoutes); const segmentPathsToFill = generateSegmentsFromPatch(treePatch).map((segment)=>[ ...flightSegmentPath, ...segment ]); for (const segmentPaths of segmentPathsToFill){ const res = (0, _fillcachewithdataproperty.fillCacheWithDataProperty)(newCache, currentCache, segmentPaths, data); if (!(res == null ? void 0 : res.bailOptimistic)) { appliedPatch = true; } } return appliedPatch; } function navigateReducer(state, action) { const { url, isExternalUrl, navigateType, cache, mutable, forceOptimisticNavigation, shouldScroll } = action; const { pathname, hash } = url; const href = (0, _createhreffromurl.createHrefFromUrl)(url); const pendingPush = navigateType === "push"; // we want to prune the prefetch cache on every navigation to avoid it growing too large (0, _pruneprefetchcache.prunePrefetchCache)(state.prefetchCache); const isForCurrentTree = JSON.stringify(mutable.previousTree) === JSON.stringify(state.tree); if (isForCurrentTree) { return (0, _handlemutable.handleMutable)(state, mutable); } if (isExternalUrl) { return handleExternalUrl(state, mutable, url.toString(), pendingPush); } let prefetchValues = state.prefetchCache.get((0, _createhreffromurl.createHrefFromUrl)(url, false)); if (forceOptimisticNavigation && (prefetchValues == null ? void 0 : prefetchValues.kind) !== _routerreducertypes.PrefetchKind.TEMPORARY) { const segments = pathname.split("/"); // TODO-APP: figure out something better for index pages segments.push("__PAGE__"); // Optimistic tree case. // If the optimistic tree is deeper than the current state leave that deeper part out of the fetch const optimisticTree = (0, _createoptimistictree.createOptimisticTree)(segments, state.tree, false); // we need a copy of the cache in case we need to revert to it const temporaryCacheNode = { ...cache }; // Copy subTreeData for the root node of the cache. // Note: didn't do it above because typescript doesn't like it. temporaryCacheNode.status = _approutercontextsharedruntime.CacheStates.READY; temporaryCacheNode.subTreeData = state.cache.subTreeData; temporaryCacheNode.parallelRoutes = new Map(state.cache.parallelRoutes); let data; const fetchResponse = ()=>{ if (!data) { data = (0, _createrecordfromthenable.createRecordFromThenable)((0, _fetchserverresponse.fetchServerResponse)(url, optimisticTree, state.nextUrl, state.buildId)); } return data; }; // TODO-APP: segments.slice(1) strips '', we can get rid of '' altogether. // TODO-APP: re-evaluate if we need to strip the last segment const optimisticFlightSegmentPath = segments.slice(1).map((segment)=>[ "children", segment ]).flat(); // Copy existing cache nodes as far as possible and fill in `data` property with the started data fetch. // The `data` property is used to suspend in layout-router during render if it hasn't resolved yet by the time it renders. const res = (0, _fillcachewithdataproperty.fillCacheWithDataProperty)(temporaryCacheNode, state.cache, optimisticFlightSegmentPath, fetchResponse, true); // If optimistic fetch couldn't happen it falls back to the non-optimistic case. if (!(res == null ? void 0 : res.bailOptimistic)) { mutable.previousTree = state.tree; mutable.patchedTree = optimisticTree; mutable.pendingPush = pendingPush; mutable.hashFragment = hash; mutable.shouldScroll = shouldScroll; mutable.scrollableSegments = []; mutable.cache = temporaryCacheNode; mutable.canonicalUrl = href; state.prefetchCache.set((0, _createhreffromurl.createHrefFromUrl)(url, false), { data: (0, _createrecordfromthenable.createRecordFromThenable)(Promise.resolve(data)), // this will make sure that the entry will be discarded after 30s kind: _routerreducertypes.PrefetchKind.TEMPORARY, prefetchTime: Date.now(), treeAtTimeOfPrefetch: state.tree, lastUsedTime: Date.now() }); return (0, _handlemutable.handleMutable)(state, mutable); } } // If we don't have a prefetch value, we need to create one if (!prefetchValues) { const data = (0, _createrecordfromthenable.createRecordFromThenable)((0, _fetchserverresponse.fetchServerResponse)(url, state.tree, state.nextUrl, state.buildId, // in dev, there's never gonna be a prefetch entry so we want to prefetch here // in order to simulate the behavior of the prefetch cache process.env.NODE_ENV === "development" ? _routerreducertypes.PrefetchKind.AUTO : undefined)); const newPrefetchValue = { data: (0, _createrecordfromthenable.createRecordFromThenable)(Promise.resolve(data)), // this will make sure that the entry will be discarded after 30s kind: process.env.NODE_ENV === "development" ? _routerreducertypes.PrefetchKind.AUTO : _routerreducertypes.PrefetchKind.TEMPORARY, prefetchTime: Date.now(), treeAtTimeOfPrefetch: state.tree, lastUsedTime: null }; state.prefetchCache.set((0, _createhreffromurl.createHrefFromUrl)(url, false), newPrefetchValue); prefetchValues = newPrefetchValue; } const prefetchEntryCacheStatus = (0, _getprefetchcacheentrystatus.getPrefetchEntryCacheStatus)(prefetchValues); // The one before last item is the router state tree patch const { treeAtTimeOfPrefetch, data } = prefetchValues; _prefetchreducer.prefetchQueue.bump(data); // Unwrap cache data with `use` to suspend here (in the reducer) until the fetch resolves. const [flightData, canonicalUrlOverride] = (0, _readrecordvalue.readRecordValue)(data); // we only want to mark this once if (!prefetchValues.lastUsedTime) { // important: we should only mark the cache node as dirty after we unsuspend from the call above prefetchValues.lastUsedTime = Date.now(); } // Handle case when navigating to page in `pages` from `app` if (typeof flightData === "string") { return handleExternalUrl(state, mutable, flightData, pendingPush); } let currentTree = state.tree; let currentCache = state.cache; let scrollableSegments = []; for (const flightDataPath of flightData){ const flightSegmentPath = flightDataPath.slice(0, -4); // The one before last item is the router state tree patch const treePatch = flightDataPath.slice(-3)[0]; // TODO-APP: remove '' const flightSegmentPathWithLeadingEmpty = [ "", ...flightSegmentPath ]; // Create new tree based on the flightSegmentPath and router state patch let newTree = (0, _applyrouterstatepatchtotree.applyRouterStatePatchToTree)(// TODO-APP: remove '' flightSegmentPathWithLeadingEmpty, currentTree, treePatch); // If the tree patch can't be applied to the current tree then we use the tree at time of prefetch // TODO-APP: This should instead fill in the missing pieces in `currentTree` with the data from `treeAtTimeOfPrefetch`, then apply the patch. if (newTree === null) { newTree = (0, _applyrouterstatepatchtotree.applyRouterStatePatchToTree)(// TODO-APP: remove '' flightSegmentPathWithLeadingEmpty, treeAtTimeOfPrefetch, treePatch); } if (newTree !== null) { if ((0, _isnavigatingtonewrootlayout.isNavigatingToNewRootLayout)(currentTree, newTree)) { return handleExternalUrl(state, mutable, href, pendingPush); } let applied = (0, _applyflightdata.applyFlightData)(currentCache, cache, flightDataPath, prefetchValues.kind === "auto" && prefetchEntryCacheStatus === _getprefetchcacheentrystatus.PrefetchCacheEntryStatus.reusable); if (!applied && prefetchEntryCacheStatus === _getprefetchcacheentrystatus.PrefetchCacheEntryStatus.stale) { applied = addRefetchToLeafSegments(cache, currentCache, flightSegmentPath, treePatch, // eslint-disable-next-line no-loop-func ()=>(0, _fetchserverresponse.fetchServerResponse)(url, currentTree, state.nextUrl, state.buildId)); } const hardNavigate = (0, _shouldhardnavigate.shouldHardNavigate)(// TODO-APP: remove '' flightSegmentPathWithLeadingEmpty, currentTree); if (hardNavigate) { cache.status = _approutercontextsharedruntime.CacheStates.READY; // Copy subTreeData for the root node of the cache. cache.subTreeData = currentCache.subTreeData; (0, _invalidatecachebelowflightsegmentpath.invalidateCacheBelowFlightSegmentPath)(cache, currentCache, flightSegmentPath); // Ensure the existing cache value is used when the cache was not invalidated. mutable.cache = cache; } else if (applied) { mutable.cache = cache; } currentCache = cache; currentTree = newTree; for (const subSegment of generateSegmentsFromPatch(treePatch)){ const scrollableSegmentPath = [ ...flightSegmentPath, ...subSegment ]; // Filter out the __DEFAULT__ paths as they shouldn't be scrolled to in this case. if (scrollableSegmentPath[scrollableSegmentPath.length - 1] !== "__DEFAULT__") { scrollableSegments.push(scrollableSegmentPath); } } } } mutable.previousTree = state.tree; mutable.patchedTree = currentTree; mutable.canonicalUrl = canonicalUrlOverride ? (0, _createhreffromurl.createHrefFromUrl)(canonicalUrlOverride) : href; mutable.pendingPush = pendingPush; mutable.scrollableSegments = scrollableSegments; mutable.hashFragment = hash; mutable.shouldScroll = shouldScroll; return (0, _handlemutable.handleMutable)(state, mutable); } if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') { Object.defineProperty(exports.default, '__esModule', { value: true }); Object.assign(exports.default, exports); module.exports = exports.default; } //# sourceMappingURL=navigate-reducer.js.map