module.exports = [ "[project]/node_modules/lucide-react/dist/esm/icons/clock.mjs [app-ssr] (ecmascript)", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "__iconNode", ()=>__iconNode, "default", ()=>Clock ]); /** * @license lucide-react v1.14.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */ var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/createLucideIcon.mjs [app-ssr] (ecmascript)"); ; const __iconNode = [ [ "circle", { cx: "12", cy: "12", r: "10", key: "1mglay" } ], [ "path", { d: "M12 6v6l4 2", key: "mmk7yg" } ] ]; const Clock = (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"])("clock", __iconNode); ; }), "[project]/node_modules/lucide-react/dist/esm/icons/clock.mjs [app-ssr] (ecmascript) ", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "Clock", ()=>__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$clock$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"] ]); var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$clock$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/icons/clock.mjs [app-ssr] (ecmascript)"); }), "[project]/node_modules/lucide-react/dist/esm/icons/activity.mjs [app-ssr] (ecmascript)", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "__iconNode", ()=>__iconNode, "default", ()=>Activity ]); /** * @license lucide-react v1.14.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */ var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/createLucideIcon.mjs [app-ssr] (ecmascript)"); ; const __iconNode = [ [ "path", { d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2", key: "169zse" } ] ]; const Activity = (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"])("activity", __iconNode); ; }), "[project]/node_modules/lucide-react/dist/esm/icons/activity.mjs [app-ssr] (ecmascript) ", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "Activity", ()=>__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$activity$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"] ]); var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$activity$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/icons/activity.mjs [app-ssr] (ecmascript)"); }), "[project]/node_modules/lucide-react/dist/esm/icons/arrow-right.mjs [app-ssr] (ecmascript)", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "__iconNode", ()=>__iconNode, "default", ()=>ArrowRight ]); /** * @license lucide-react v1.14.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */ var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/createLucideIcon.mjs [app-ssr] (ecmascript)"); ; const __iconNode = [ [ "path", { d: "M5 12h14", key: "1ays0h" } ], [ "path", { d: "m12 5 7 7-7 7", key: "xquz4c" } ] ]; const ArrowRight = (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"])("arrow-right", __iconNode); ; }), "[project]/node_modules/lucide-react/dist/esm/icons/arrow-right.mjs [app-ssr] (ecmascript) ", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "ArrowRight", ()=>__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$arrow$2d$right$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"] ]); var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$arrow$2d$right$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/icons/arrow-right.mjs [app-ssr] (ecmascript)"); }), "[project]/node_modules/lucide-react/dist/esm/icons/plus.mjs [app-ssr] (ecmascript)", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "__iconNode", ()=>__iconNode, "default", ()=>Plus ]); /** * @license lucide-react v1.14.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */ var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/createLucideIcon.mjs [app-ssr] (ecmascript)"); ; const __iconNode = [ [ "path", { d: "M5 12h14", key: "1ays0h" } ], [ "path", { d: "M12 5v14", key: "s699le" } ] ]; const Plus = (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"])("plus", __iconNode); ; }), "[project]/node_modules/lucide-react/dist/esm/icons/plus.mjs [app-ssr] (ecmascript) ", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "Plus", ()=>__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$plus$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"] ]); var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$plus$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/icons/plus.mjs [app-ssr] (ecmascript)"); }), "[project]/node_modules/lucide-react/dist/esm/icons/circle-check.mjs [app-ssr] (ecmascript)", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "__iconNode", ()=>__iconNode, "default", ()=>CircleCheck ]); /** * @license lucide-react v1.14.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. */ var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/createLucideIcon.mjs [app-ssr] (ecmascript)"); ; const __iconNode = [ [ "circle", { cx: "12", cy: "12", r: "10", key: "1mglay" } ], [ "path", { d: "m9 12 2 2 4-4", key: "dzmm74" } ] ]; const CircleCheck = (0, __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$createLucideIcon$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"])("circle-check", __iconNode); ; }), "[project]/node_modules/lucide-react/dist/esm/icons/circle-check.mjs [app-ssr] (ecmascript) ", ((__turbopack_context__) => { "use strict"; __turbopack_context__.s([ "CheckCircle2", ()=>__TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$circle$2d$check$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"] ]); var __TURBOPACK__imported__module__$5b$project$5d2f$node_modules$2f$lucide$2d$react$2f$dist$2f$esm$2f$icons$2f$circle$2d$check$2e$mjs__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/node_modules/lucide-react/dist/esm/icons/circle-check.mjs [app-ssr] (ecmascript)"); }), "[project]/node_modules/next/dist/shared/lib/router/utils/querystring.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { assign: null, searchParamsToUrlQuery: null, urlQueryToSearchParams: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { assign: function() { return assign; }, searchParamsToUrlQuery: function() { return searchParamsToUrlQuery; }, urlQueryToSearchParams: function() { return urlQueryToSearchParams; } }); function searchParamsToUrlQuery(searchParams) { const query = {}; for (const [key, value] of searchParams.entries()){ const existing = query[key]; if (typeof existing === 'undefined') { query[key] = value; } else if (Array.isArray(existing)) { existing.push(value); } else { query[key] = [ existing, value ]; } } return query; } function stringifyUrlQueryParam(param) { if (typeof param === 'string') { return param; } if (typeof param === 'number' && !isNaN(param) || typeof param === 'boolean') { return String(param); } else { return ''; } } function urlQueryToSearchParams(query) { const searchParams = new URLSearchParams(); for (const [key, value] of Object.entries(query)){ if (Array.isArray(value)) { for (const item of value){ searchParams.append(key, stringifyUrlQueryParam(item)); } } else { searchParams.set(key, stringifyUrlQueryParam(value)); } } return searchParams; } function assign(target, ...searchParamsList) { for (const searchParams of searchParamsList){ for (const key of searchParams.keys()){ target.delete(key); } for (const [key, value] of searchParams.entries()){ target.append(key, value); } } return target; } }), "[project]/node_modules/next/dist/shared/lib/router/utils/format-url.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; // Format function modified from nodejs // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { formatUrl: null, formatWithValidation: null, urlObjectKeys: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { formatUrl: function() { return formatUrl; }, formatWithValidation: function() { return formatWithValidation; }, urlObjectKeys: function() { return urlObjectKeys; } }); const _interop_require_wildcard = __turbopack_context__.r("[project]/node_modules/@swc/helpers/cjs/_interop_require_wildcard.cjs [app-ssr] (ecmascript)"); const _querystring = /*#__PURE__*/ _interop_require_wildcard._(__turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/querystring.js [app-ssr] (ecmascript)")); const slashedProtocols = /https?|ftp|gopher|file/; function formatUrl(urlObj) { let { auth, hostname } = urlObj; let protocol = urlObj.protocol || ''; let pathname = urlObj.pathname || ''; let hash = urlObj.hash || ''; let query = urlObj.query || ''; let host = false; auth = auth ? encodeURIComponent(auth).replace(/%3A/i, ':') + '@' : ''; if (urlObj.host) { host = auth + urlObj.host; } else if (hostname) { host = auth + (~hostname.indexOf(':') ? `[${hostname}]` : hostname); if (urlObj.port) { host += ':' + urlObj.port; } } if (query && typeof query === 'object') { query = String(_querystring.urlQueryToSearchParams(query)); } let search = urlObj.search || query && `?${query}` || ''; if (protocol && !protocol.endsWith(':')) protocol += ':'; if (urlObj.slashes || (!protocol || slashedProtocols.test(protocol)) && host !== false) { host = '//' + (host || ''); if (pathname && pathname[0] !== '/') pathname = '/' + pathname; } else if (!host) { host = ''; } if (hash && hash[0] !== '#') hash = '#' + hash; if (search && search[0] !== '?') search = '?' + search; pathname = pathname.replace(/[?#]/g, encodeURIComponent); search = search.replace('#', '%23'); return `${protocol}${host}${pathname}${search}${hash}`; } const urlObjectKeys = [ 'auth', 'hash', 'host', 'hostname', 'href', 'path', 'pathname', 'port', 'protocol', 'query', 'search', 'slashes' ]; function formatWithValidation(url) { if ("TURBOPACK compile-time truthy", 1) { if (url !== null && typeof url === 'object') { Object.keys(url).forEach((key)=>{ if (!urlObjectKeys.includes(key)) { console.warn(`Unknown key passed via urlObject into url.format: ${key}`); } }); } } return formatUrl(url); } }), "[project]/node_modules/next/dist/client/use-merged-ref.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "useMergedRef", { enumerable: true, get: function() { return useMergedRef; } }); const _react = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js [app-ssr] (ecmascript)"); function useMergedRef(refA, refB) { const cleanupA = (0, _react.useRef)(null); const cleanupB = (0, _react.useRef)(null); // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null. // (this happens often if the user doesn't pass a ref to Link/Form/Image) // But this can cause us to leak a cleanup-ref into user code (previously via ``), // and the user might pass that ref into ref-merging library that doesn't support cleanup refs // (because it hasn't been updated for React 19) // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`. // So in practice, it's safer to be defensive and always wrap the ref, even on React 19. return (0, _react.useCallback)((current)=>{ if (current === null) { const cleanupFnA = cleanupA.current; if (cleanupFnA) { cleanupA.current = null; cleanupFnA(); } const cleanupFnB = cleanupB.current; if (cleanupFnB) { cleanupB.current = null; cleanupFnB(); } } else { if (refA) { cleanupA.current = applyRef(refA, current); } if (refB) { cleanupB.current = applyRef(refB, current); } } }, [ refA, refB ]); } function applyRef(refA, current) { if (typeof refA === 'function') { const cleanup = refA(current); if (typeof cleanup === 'function') { return cleanup; } else { return ()=>refA(null); } } else { refA.current = current; return ()=>{ refA.current = null; }; } } 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; } }), "[project]/node_modules/next/dist/shared/lib/utils.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { DecodeError: null, MiddlewareNotFoundError: null, MissingStaticPage: null, NormalizeError: null, PageNotFoundError: null, SP: null, ST: null, WEB_VITALS: null, execOnce: null, getDisplayName: null, getLocationOrigin: null, getURL: null, isAbsoluteUrl: null, isResSent: null, loadGetInitialProps: null, normalizeRepeatedSlashes: null, stringifyError: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { DecodeError: function() { return DecodeError; }, MiddlewareNotFoundError: function() { return MiddlewareNotFoundError; }, MissingStaticPage: function() { return MissingStaticPage; }, NormalizeError: function() { return NormalizeError; }, PageNotFoundError: function() { return PageNotFoundError; }, SP: function() { return SP; }, ST: function() { return ST; }, WEB_VITALS: function() { return WEB_VITALS; }, execOnce: function() { return execOnce; }, getDisplayName: function() { return getDisplayName; }, getLocationOrigin: function() { return getLocationOrigin; }, getURL: function() { return getURL; }, isAbsoluteUrl: function() { return isAbsoluteUrl; }, isResSent: function() { return isResSent; }, loadGetInitialProps: function() { return loadGetInitialProps; }, normalizeRepeatedSlashes: function() { return normalizeRepeatedSlashes; }, stringifyError: function() { return stringifyError; } }); const WEB_VITALS = [ 'CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB' ]; function execOnce(fn) { let used = false; let result; return (...args)=>{ if (!used) { used = true; result = fn(...args); } return result; }; } // Scheme: https://tools.ietf.org/html/rfc3986#section-3.1 // Absolute URL: https://tools.ietf.org/html/rfc3986#section-4.3 const ABSOLUTE_URL_REGEX = /^[a-zA-Z][a-zA-Z\d+\-.]*?:/; const isAbsoluteUrl = (url)=>ABSOLUTE_URL_REGEX.test(url); function getLocationOrigin() { const { protocol, hostname, port } = window.location; return `${protocol}//${hostname}${port ? ':' + port : ''}`; } function getURL() { const { href } = window.location; const origin = getLocationOrigin(); return href.substring(origin.length); } function getDisplayName(Component) { return typeof Component === 'string' ? Component : Component.displayName || Component.name || 'Unknown'; } function isResSent(res) { return res.finished || res.headersSent; } function normalizeRepeatedSlashes(url) { const urlParts = url.split('?'); const urlNoQuery = urlParts[0]; return urlNoQuery // first we replace any non-encoded backslashes with forward // then normalize repeated forward slashes .replace(/\\/g, '/').replace(/\/\/+/g, '/') + (urlParts[1] ? `?${urlParts.slice(1).join('?')}` : ''); } async function loadGetInitialProps(App, ctx) { if ("TURBOPACK compile-time truthy", 1) { if (App.prototype?.getInitialProps) { const message = `"${getDisplayName(App)}.getInitialProps()" is defined as an instance method - visit https://nextjs.org/docs/messages/get-initial-props-as-an-instance-method for more information.`; throw Object.defineProperty(new Error(message), "__NEXT_ERROR_CODE", { value: "E1035", enumerable: false, configurable: true }); } } // when called from _app `ctx` is nested in `ctx` const res = ctx.res || ctx.ctx && ctx.ctx.res; if (!App.getInitialProps) { if (ctx.ctx && ctx.Component) { // @ts-ignore pageProps default return { pageProps: await loadGetInitialProps(ctx.Component, ctx.ctx) }; } return {}; } const props = await App.getInitialProps(ctx); if (res && isResSent(res)) { return props; } if (!props) { const message = `"${getDisplayName(App)}.getInitialProps()" should resolve to an object. But found "${props}" instead.`; throw Object.defineProperty(new Error(message), "__NEXT_ERROR_CODE", { value: "E1025", enumerable: false, configurable: true }); } if ("TURBOPACK compile-time truthy", 1) { if (Object.keys(props).length === 0 && !ctx.ctx) { console.warn(`${getDisplayName(App)} returned an empty object from \`getInitialProps\`. This de-optimizes and prevents automatic static optimization. https://nextjs.org/docs/messages/empty-object-getInitialProps`); } } return props; } const SP = typeof performance !== 'undefined'; const ST = SP && [ 'mark', 'measure', 'getEntriesByName' ].every((method)=>typeof performance[method] === 'function'); class DecodeError extends Error { } class NormalizeError extends Error { } class PageNotFoundError extends Error { constructor(page){ super(); this.code = 'ENOENT'; this.name = 'PageNotFoundError'; this.message = `Cannot find module for page: ${page}`; } } class MissingStaticPage extends Error { constructor(page, message){ super(); this.message = `Failed to load static file for page: ${page} ${message}`; } } class MiddlewareNotFoundError extends Error { constructor(){ super(); this.code = 'ENOENT'; this.message = `Cannot find the middleware module`; } } function stringifyError(error) { return JSON.stringify({ message: error.message, stack: error.stack }); } }), "[project]/node_modules/next/dist/shared/lib/router/utils/parse-path.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Given a path this function will find the pathname, query and hash and return * them. This is useful to parse full paths on the client side. * @param path A path to parse e.g. /foo/bar?id=1#hash */ Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "parsePath", { enumerable: true, get: function() { return parsePath; } }); function parsePath(path) { const hashIndex = path.indexOf('#'); const queryIndex = path.indexOf('?'); const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex); if (hasQuery || hashIndex > -1) { return { pathname: path.substring(0, hasQuery ? queryIndex : hashIndex), query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : '', hash: hashIndex > -1 ? path.slice(hashIndex) : '' }; } return { pathname: path, query: '', hash: '' }; } }), "[project]/node_modules/next/dist/shared/lib/router/utils/add-path-prefix.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "addPathPrefix", { enumerable: true, get: function() { return addPathPrefix; } }); const _parsepath = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/parse-path.js [app-ssr] (ecmascript)"); function addPathPrefix(path, prefix) { if (!path.startsWith('/') || !prefix) { return path; } const { pathname, query, hash } = (0, _parsepath.parsePath)(path); return `${prefix}${pathname}${query}${hash}`; } }), "[project]/node_modules/next/dist/shared/lib/router/utils/remove-trailing-slash.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Removes the trailing slash for a given route or page path. Preserves the * root page. Examples: * - `/foo/bar/` -> `/foo/bar` * - `/foo/bar` -> `/foo/bar` * - `/` -> `/` */ Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "removeTrailingSlash", { enumerable: true, get: function() { return removeTrailingSlash; } }); function removeTrailingSlash(route) { return route.replace(/\/$/, '') || '/'; } }), "[project]/node_modules/next/dist/client/normalize-trailing-slash.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "normalizePathTrailingSlash", { enumerable: true, get: function() { return normalizePathTrailingSlash; } }); const _removetrailingslash = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/remove-trailing-slash.js [app-ssr] (ecmascript)"); const _parsepath = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/parse-path.js [app-ssr] (ecmascript)"); const normalizePathTrailingSlash = (path)=>{ if (!path.startsWith('/') || ("TURBOPACK compile-time value", void 0)) { return path; } const { pathname, query, hash } = (0, _parsepath.parsePath)(path); if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; return `${(0, _removetrailingslash.removeTrailingSlash)(pathname)}${query}${hash}`; }; 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; } }), "[project]/node_modules/next/dist/client/add-base-path.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "addBasePath", { enumerable: true, get: function() { return addBasePath; } }); const _addpathprefix = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/add-path-prefix.js [app-ssr] (ecmascript)"); const _normalizetrailingslash = __turbopack_context__.r("[project]/node_modules/next/dist/client/normalize-trailing-slash.js [app-ssr] (ecmascript)"); const basePath = ("TURBOPACK compile-time value", "") || ''; function addBasePath(path, required) { return (0, _normalizetrailingslash.normalizePathTrailingSlash)(("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : (0, _addpathprefix.addPathPrefix)(path, basePath)); } 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; } }), "[project]/node_modules/next/dist/shared/lib/utils/warn-once.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "warnOnce", { enumerable: true, get: function() { return warnOnce; } }); let warnOnce = (_)=>{}; if ("TURBOPACK compile-time truthy", 1) { const warnings = new Set(); warnOnce = (msg)=>{ if (!warnings.has(msg)) { console.warn(msg); } warnings.add(msg); }; } }), "[project]/node_modules/next/dist/client/components/router-reducer/router-reducer-types.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { ACTION_HMR_REFRESH: null, ACTION_NAVIGATE: null, ACTION_REFRESH: null, ACTION_RESTORE: null, ACTION_SERVER_ACTION: null, ACTION_SERVER_PATCH: null, PrefetchKind: null, ScrollBehavior: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { ACTION_HMR_REFRESH: function() { return ACTION_HMR_REFRESH; }, ACTION_NAVIGATE: function() { return ACTION_NAVIGATE; }, ACTION_REFRESH: function() { return ACTION_REFRESH; }, ACTION_RESTORE: function() { return ACTION_RESTORE; }, ACTION_SERVER_ACTION: function() { return ACTION_SERVER_ACTION; }, ACTION_SERVER_PATCH: function() { return ACTION_SERVER_PATCH; }, PrefetchKind: function() { return PrefetchKind; }, ScrollBehavior: function() { return ScrollBehavior; } }); const ACTION_REFRESH = 'refresh'; const ACTION_NAVIGATE = 'navigate'; const ACTION_RESTORE = 'restore'; const ACTION_SERVER_PATCH = 'server-patch'; const ACTION_HMR_REFRESH = 'hmr-refresh'; const ACTION_SERVER_ACTION = 'server-action'; var PrefetchKind = /*#__PURE__*/ function(PrefetchKind) { PrefetchKind["AUTO"] = "auto"; PrefetchKind["FULL"] = "full"; return PrefetchKind; }({}); var ScrollBehavior = /*#__PURE__*/ function(ScrollBehavior) { /** Use per-node ScrollRef to decide whether to scroll. */ ScrollBehavior[ScrollBehavior["Default"] = 0] = "Default"; /** Suppress scroll entirely (e.g. scroll={false} on Link or router.push). */ ScrollBehavior[ScrollBehavior["NoScroll"] = 1] = "NoScroll"; return ScrollBehavior; }({}); 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Shared types and constants for the Segment Cache. */ Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { FetchStrategy: null, NavigationResultTag: null, PrefetchPriority: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { FetchStrategy: function() { return FetchStrategy; }, NavigationResultTag: function() { return NavigationResultTag; }, PrefetchPriority: function() { return PrefetchPriority; } }); var NavigationResultTag = /*#__PURE__*/ function(NavigationResultTag) { NavigationResultTag[NavigationResultTag["MPA"] = 0] = "MPA"; NavigationResultTag[NavigationResultTag["Success"] = 1] = "Success"; NavigationResultTag[NavigationResultTag["NoOp"] = 2] = "NoOp"; NavigationResultTag[NavigationResultTag["Async"] = 3] = "Async"; return NavigationResultTag; }({}); var PrefetchPriority = /*#__PURE__*/ function(PrefetchPriority) { /** * Assigned to the most recently hovered/touched link. Special network * bandwidth is reserved for this task only. There's only ever one Intent- * priority task at a time; when a new Intent task is scheduled, the previous * one is bumped down to Default. */ PrefetchPriority[PrefetchPriority["Intent"] = 2] = "Intent"; /** * The default priority for prefetch tasks. */ PrefetchPriority[PrefetchPriority["Default"] = 1] = "Default"; /** * Assigned to tasks when they spawn non-blocking background work, like * revalidating a partially cached entry to see if more data is available. */ PrefetchPriority[PrefetchPriority["Background"] = 0] = "Background"; return PrefetchPriority; }({}); var FetchStrategy = /*#__PURE__*/ function(FetchStrategy) { // Deliberately ordered so we can easily compare two segments // and determine if one segment is "more specific" than another // (i.e. if it's likely that it contains more data) FetchStrategy[FetchStrategy["LoadingBoundary"] = 0] = "LoadingBoundary"; FetchStrategy[FetchStrategy["PPR"] = 1] = "PPR"; FetchStrategy[FetchStrategy["PPRRuntime"] = 2] = "PPRRuntime"; FetchStrategy[FetchStrategy["Full"] = 3] = "Full"; return FetchStrategy; }({}); 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/cache-key.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; // TypeScript trick to simulate opaque types, like in Flow. Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "createCacheKey", { enumerable: true, get: function() { return createCacheKey; } }); function createCacheKey(originalHref, nextUrl) { const originalUrl = new URL(originalHref); const cacheKey = { pathname: originalUrl.pathname, search: originalUrl.search, nextUrl: nextUrl }; return cacheKey; } 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; } }), "[project]/node_modules/next/dist/shared/lib/app-router-types.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * App Router types - Client-safe types for the Next.js App Router * * This file contains type definitions that can be safely imported * by both client-side and server-side code without circular dependencies. */ Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "PrefetchHint", { enumerable: true, get: function() { return PrefetchHint; } }); var PrefetchHint = /*#__PURE__*/ function(PrefetchHint) { // This segment has a runtime prefetch enabled (via unstable_instant with // prefetch: 'runtime'). Per-segment only, does not propagate to ancestors. PrefetchHint[PrefetchHint["HasRuntimePrefetch"] = 1] = "HasRuntimePrefetch"; // This segment or one of its descendants has an instant config defined // (any truthy unstable_instant, regardless of prefetch mode). Propagates // upward so the root segment reflects the entire subtree. PrefetchHint[PrefetchHint["SubtreeHasInstant"] = 2] = "SubtreeHasInstant"; // This segment itself has a loading.tsx boundary. PrefetchHint[PrefetchHint["SegmentHasLoadingBoundary"] = 4] = "SegmentHasLoadingBoundary"; // A descendant segment (but not this one) has a loading.tsx boundary. // Propagates upward so the root reflects the entire subtree. PrefetchHint[PrefetchHint["SubtreeHasLoadingBoundary"] = 8] = "SubtreeHasLoadingBoundary"; // This segment is the root layout of the application. PrefetchHint[PrefetchHint["IsRootLayout"] = 16] = "IsRootLayout"; // This segment's response includes its parent's data inlined into it. // Set at build time by the segment size measurement pass. PrefetchHint[PrefetchHint["ParentInlinedIntoSelf"] = 32] = "ParentInlinedIntoSelf"; // This segment's data is inlined into one of its children — don't fetch // it separately. Set at build time by the segment size measurement pass. PrefetchHint[PrefetchHint["InlinedIntoChild"] = 64] = "InlinedIntoChild"; // On a __PAGE__: this page's response includes the head (metadata/viewport) // at the end of its SegmentPrefetch[] array. PrefetchHint[PrefetchHint["HeadInlinedIntoSelf"] = 128] = "HeadInlinedIntoSelf"; // On the root hint node: the head was NOT inlined into any page — fetch // it separately. Absence of this bit means the head is bundled into a page. PrefetchHint[PrefetchHint["HeadOutlined"] = 256] = "HeadOutlined"; return PrefetchHint; }({}); }), "[project]/node_modules/next/dist/client/components/match-segments.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "matchSegment", { enumerable: true, get: function() { return matchSegment; } }); const matchSegment = (existingSegment, segment)=>{ // segment is either Array or string if (typeof existingSegment === 'string') { if (typeof segment === 'string') { // Common case: segment is just a string return existingSegment === segment; } return false; } if (typeof segment === 'string') { return false; } return existingSegment[0] === segment[0] && existingSegment[1] === segment[1]; }; 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; } }), "[project]/node_modules/next/dist/shared/lib/segment-cache/vary-params-decoding.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Vary Params Decoding * * This module is shared between server and client. */ Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "readVaryParams", { enumerable: true, get: function() { return readVaryParams; } }); function readVaryParams(thenable) { // Attach a no-op listener to force Flight to synchronously resolve the // thenable. When a thenable arrives from the Flight stream, it may be in an // intermediate 'resolved_model' state (data received but not unwrapped). // Calling .then() triggers Flight to transition it to 'fulfilled', making // the value available synchronously. React uses this same optimization // internally to avoid unnecessary microtasks. thenable.then(noop); // If the thenable is still not 'fulfilled' after calling .then(), the server // failed to resolve it before the stream ended. Treat as unknown. if (thenable.status !== 'fulfilled') { return null; } return thenable.value; } const noop = ()=>{}; }), "[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { ACTION_HEADER: null, FLIGHT_HEADERS: null, NEXT_ACTION_NOT_FOUND_HEADER: null, NEXT_ACTION_REVALIDATED_HEADER: null, NEXT_DID_POSTPONE_HEADER: null, NEXT_HMR_REFRESH_HASH_COOKIE: null, NEXT_HMR_REFRESH_HEADER: null, NEXT_HTML_REQUEST_ID_HEADER: null, NEXT_INSTANT_PREFETCH_HEADER: null, NEXT_INSTANT_TEST_COOKIE: null, NEXT_IS_PRERENDER_HEADER: null, NEXT_REQUEST_ID_HEADER: null, NEXT_REWRITTEN_PATH_HEADER: null, NEXT_REWRITTEN_QUERY_HEADER: null, NEXT_ROUTER_PREFETCH_HEADER: null, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER: null, NEXT_ROUTER_STALE_TIME_HEADER: null, NEXT_ROUTER_STATE_TREE_HEADER: null, NEXT_RSC_UNION_QUERY: null, NEXT_URL: null, RSC_CONTENT_TYPE_HEADER: null, RSC_HEADER: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { ACTION_HEADER: function() { return ACTION_HEADER; }, FLIGHT_HEADERS: function() { return FLIGHT_HEADERS; }, NEXT_ACTION_NOT_FOUND_HEADER: function() { return NEXT_ACTION_NOT_FOUND_HEADER; }, NEXT_ACTION_REVALIDATED_HEADER: function() { return NEXT_ACTION_REVALIDATED_HEADER; }, NEXT_DID_POSTPONE_HEADER: function() { return NEXT_DID_POSTPONE_HEADER; }, NEXT_HMR_REFRESH_HASH_COOKIE: function() { return NEXT_HMR_REFRESH_HASH_COOKIE; }, NEXT_HMR_REFRESH_HEADER: function() { return NEXT_HMR_REFRESH_HEADER; }, NEXT_HTML_REQUEST_ID_HEADER: function() { return NEXT_HTML_REQUEST_ID_HEADER; }, NEXT_INSTANT_PREFETCH_HEADER: function() { return NEXT_INSTANT_PREFETCH_HEADER; }, NEXT_INSTANT_TEST_COOKIE: function() { return NEXT_INSTANT_TEST_COOKIE; }, NEXT_IS_PRERENDER_HEADER: function() { return NEXT_IS_PRERENDER_HEADER; }, NEXT_REQUEST_ID_HEADER: function() { return NEXT_REQUEST_ID_HEADER; }, NEXT_REWRITTEN_PATH_HEADER: function() { return NEXT_REWRITTEN_PATH_HEADER; }, NEXT_REWRITTEN_QUERY_HEADER: function() { return NEXT_REWRITTEN_QUERY_HEADER; }, NEXT_ROUTER_PREFETCH_HEADER: function() { return NEXT_ROUTER_PREFETCH_HEADER; }, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER: function() { return NEXT_ROUTER_SEGMENT_PREFETCH_HEADER; }, NEXT_ROUTER_STALE_TIME_HEADER: function() { return NEXT_ROUTER_STALE_TIME_HEADER; }, NEXT_ROUTER_STATE_TREE_HEADER: function() { return NEXT_ROUTER_STATE_TREE_HEADER; }, NEXT_RSC_UNION_QUERY: function() { return NEXT_RSC_UNION_QUERY; }, NEXT_URL: function() { return NEXT_URL; }, RSC_CONTENT_TYPE_HEADER: function() { return RSC_CONTENT_TYPE_HEADER; }, RSC_HEADER: function() { return RSC_HEADER; } }); const RSC_HEADER = 'rsc'; const ACTION_HEADER = 'next-action'; const NEXT_ROUTER_STATE_TREE_HEADER = 'next-router-state-tree'; const NEXT_ROUTER_PREFETCH_HEADER = 'next-router-prefetch'; const NEXT_ROUTER_SEGMENT_PREFETCH_HEADER = 'next-router-segment-prefetch'; const NEXT_HMR_REFRESH_HEADER = 'next-hmr-refresh'; const NEXT_HMR_REFRESH_HASH_COOKIE = '__next_hmr_refresh_hash__'; const NEXT_URL = 'next-url'; const RSC_CONTENT_TYPE_HEADER = 'text/x-component'; const NEXT_INSTANT_PREFETCH_HEADER = 'next-instant-navigation-testing-prefetch'; const NEXT_INSTANT_TEST_COOKIE = 'next-instant-navigation-testing'; const FLIGHT_HEADERS = [ RSC_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_HMR_REFRESH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER ]; const NEXT_RSC_UNION_QUERY = '_rsc'; const NEXT_ROUTER_STALE_TIME_HEADER = 'x-nextjs-stale-time'; const NEXT_DID_POSTPONE_HEADER = 'x-nextjs-postponed'; const NEXT_REWRITTEN_PATH_HEADER = 'x-nextjs-rewritten-path'; const NEXT_REWRITTEN_QUERY_HEADER = 'x-nextjs-rewritten-query'; const NEXT_IS_PRERENDER_HEADER = 'x-nextjs-prerender'; const NEXT_ACTION_NOT_FOUND_HEADER = 'x-nextjs-action-not-found'; const NEXT_REQUEST_ID_HEADER = 'x-nextjs-request-id'; const NEXT_HTML_REQUEST_ID_HEADER = 'x-nextjs-html-request-id'; const NEXT_ACTION_REVALIDATED_HEADER = 'x-action-revalidated'; 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; } }), "[project]/node_modules/next/dist/shared/lib/is-thenable.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Check to see if a value is Thenable. * * @param promise the maybe-thenable value * @returns true if the value is thenable */ Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "isThenable", { enumerable: true, get: function() { return isThenable; } }); function isThenable(promise) { return promise !== null && typeof promise === 'object' && 'then' in promise && typeof promise.then === 'function'; } }), "[project]/node_modules/next/dist/next-devtools/userspace/use-app-dev-rendering-indicator.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "useAppDevRenderingIndicator", { enumerable: true, get: function() { return useAppDevRenderingIndicator; } }); const _react = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js [app-ssr] (ecmascript)"); const _nextdevtools = __turbopack_context__.r("[project]/node_modules/next/dist/next-devtools/dev-overlay.shim.js [app-ssr] (ecmascript)"); const useAppDevRenderingIndicator = ()=>{ const [isPending, startTransition] = (0, _react.useTransition)(); (0, _react.useEffect)(()=>{ if (isPending) { _nextdevtools.dispatcher.renderingIndicatorShow(); } else { _nextdevtools.dispatcher.renderingIndicatorHide(); } }, [ isPending ]); return startTransition; }; 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; } }), "[project]/node_modules/next/dist/client/components/use-action-queue.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { dispatchAppRouterAction: null, dispatchGestureState: null, refreshOnInstantNavigationUnlock: null, useActionQueue: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { dispatchAppRouterAction: function() { return dispatchAppRouterAction; }, dispatchGestureState: function() { return dispatchGestureState; }, refreshOnInstantNavigationUnlock: function() { return refreshOnInstantNavigationUnlock; }, useActionQueue: function() { return useActionQueue; } }); const _interop_require_wildcard = __turbopack_context__.r("[project]/node_modules/@swc/helpers/cjs/_interop_require_wildcard.cjs [app-ssr] (ecmascript)"); const _react = /*#__PURE__*/ _interop_require_wildcard._(__turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js [app-ssr] (ecmascript)")); const _isthenable = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/is-thenable.js [app-ssr] (ecmascript)"); const _routerreducertypes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/router-reducer-types.js [app-ssr] (ecmascript)"); // The app router state lives outside of React, so we can import the dispatch // method directly wherever we need it, rather than passing it around via props // or context. let dispatch = null; function refreshOnInstantNavigationUnlock() { if ("TURBOPACK compile-time truthy", 1) { if (dispatch !== null) { dispatch({ type: _routerreducertypes.ACTION_REFRESH, bypassCacheInvalidation: true }); } else { window.location.reload(); } } } function dispatchAppRouterAction(action) { if (dispatch === null) { throw Object.defineProperty(new Error('Internal Next.js error: Router action dispatched before initialization.'), "__NEXT_ERROR_CODE", { value: "E668", enumerable: false, configurable: true }); } dispatch(action); } // Optimistic state setter for experimental_gesturePush. Only should be used // during a gesture transition. let setGestureRouterState = null; function dispatchGestureState(state) { if (setGestureRouterState === null) { throw Object.defineProperty(new Error('Internal Next.js error: Router action dispatched before initialization.'), "__NEXT_ERROR_CODE", { value: "E668", enumerable: false, configurable: true }); } setGestureRouterState(state); } const __DEV__ = ("TURBOPACK compile-time value", "development") !== 'production'; const promisesWithDebugInfo = ("TURBOPACK compile-time truthy", 1) ? new WeakMap() : "TURBOPACK unreachable"; function useActionQueue(actionQueue) { const [canonicalState, setState] = _react.default.useState(actionQueue.state); // Wrap the canonical state in useOptimistic to support // experimental_gesturePush. During a gesture transition, this returns a fork // of the router state that represents the eventual target if/when the gesture // completes. Otherwise it returns the canonical state. const [state, setGesture] = (0, _react.useOptimistic)(canonicalState); if (("TURBOPACK compile-time value", "undefined") !== 'undefined') { setGestureRouterState = setGesture; } // Because of a known issue that requires to decode Flight streams inside the // render phase, we have to be a bit clever and assign the dispatch method to // a module-level variable upon initialization. The useState hook in this // module only exists to synchronize state that lives outside of React. // Ideally, what we'd do instead is pass the state as a prop to root.render; // this is conceptually how we're modeling the app router state, despite the // weird implementation details. let nextDispatch; if ("TURBOPACK compile-time truthy", 1) { const { useAppDevRenderingIndicator } = __turbopack_context__.r("[project]/node_modules/next/dist/next-devtools/userspace/use-app-dev-rendering-indicator.js [app-ssr] (ecmascript)"); // eslint-disable-next-line react-hooks/rules-of-hooks const appDevRenderingIndicator = useAppDevRenderingIndicator(); nextDispatch = (action)=>{ appDevRenderingIndicator(()=>{ actionQueue.dispatch(action, setState); }); }; } else //TURBOPACK unreachable ; if (("TURBOPACK compile-time value", "undefined") !== 'undefined') { dispatch = nextDispatch; } // When navigating to a non-prefetched route, then App Router state will be // blocked until the server responds. We need to transfer the `_debugInfo` // from the underlying Flight response onto the top-level promise that is // passed to React (via `use`) so that the latency is accurately represented // in the React DevTools. const stateWithDebugInfo = (0, _react.useMemo)(()=>{ if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; if ((0, _isthenable.isThenable)(state)) { // useMemo can't be used to cache a Promise since the memoized value is thrown // away when we suspend. So we use a WeakMap to cache the Promise with debug info. let promiseWithDebugInfo = promisesWithDebugInfo.get(state); if (promiseWithDebugInfo === undefined) { const debugInfo = []; promiseWithDebugInfo = Promise.resolve(state).then((asyncState)=>{ if (asyncState.debugInfo !== null) { debugInfo.push(...asyncState.debugInfo); } return asyncState; }); promiseWithDebugInfo._debugInfo = debugInfo; promisesWithDebugInfo.set(state, promiseWithDebugInfo); } return promiseWithDebugInfo; } return state; }, [ state ]); return (0, _isthenable.isThenable)(stateWithDebugInfo) ? (0, _react.use)(stateWithDebugInfo) : stateWithDebugInfo; } 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; } }), "[project]/node_modules/next/dist/client/app-call-server.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "callServer", { enumerable: true, get: function() { return callServer; } }); const _react = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js [app-ssr] (ecmascript)"); const _routerreducertypes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/router-reducer-types.js [app-ssr] (ecmascript)"); const _useactionqueue = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/use-action-queue.js [app-ssr] (ecmascript)"); async function callServer(actionId, actionArgs) { return new Promise((resolve, reject)=>{ (0, _react.startTransition)(()=>{ (0, _useactionqueue.dispatchAppRouterAction)({ type: _routerreducertypes.ACTION_SERVER_ACTION, actionId, actionArgs, resolve, reject }); }); }); } 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; } }), "[project]/node_modules/next/dist/client/app-find-source-map-url.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "findSourceMapURL", { enumerable: true, get: function() { return findSourceMapURL; } }); const basePath = ("TURBOPACK compile-time value", "") || ''; const pathname = `${basePath}/__nextjs_source-map`; const findSourceMapURL = ("TURBOPACK compile-time truthy", 1) ? function findSourceMapURL(filename) { if (filename === '') { return null; } if (filename.startsWith(document.location.origin) && filename.includes('/_next/static')) { // This is a request for a client chunk. This can only happen when // using Turbopack. In this case, since we control how those source // maps are generated, we can safely assume that the sourceMappingURL // is relative to the filename, with an added `.map` extension. The // browser can just request this file, and it gets served through the // normal dev server, without the need to route this through // the `/__nextjs_source-map` dev middleware. return `${filename}.map`; } const url = new URL(pathname, document.location.origin); url.searchParams.set('filename', filename); return url.href; } : "TURBOPACK unreachable"; 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; } }), "[project]/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { HEAD_REQUEST_KEY: null, ROOT_SEGMENT_REQUEST_KEY: null, appendSegmentRequestKeyPart: null, convertSegmentPathToStaticExportFilename: null, createSegmentRequestKeyPart: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { HEAD_REQUEST_KEY: function() { return HEAD_REQUEST_KEY; }, ROOT_SEGMENT_REQUEST_KEY: function() { return ROOT_SEGMENT_REQUEST_KEY; }, appendSegmentRequestKeyPart: function() { return appendSegmentRequestKeyPart; }, convertSegmentPathToStaticExportFilename: function() { return convertSegmentPathToStaticExportFilename; }, createSegmentRequestKeyPart: function() { return createSegmentRequestKeyPart; } }); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const ROOT_SEGMENT_REQUEST_KEY = ''; const HEAD_REQUEST_KEY = '/_head'; function createSegmentRequestKeyPart(segment) { if (typeof segment === 'string') { if (segment.startsWith(_segment.PAGE_SEGMENT_KEY)) { // The Flight Router State type sometimes includes the search params in // the page segment. However, the Segment Cache tracks this as a separate // key. So, we strip the search params here, and then add them back when // the cache entry is turned back into a FlightRouterState. This is an // unfortunate consequence of the FlightRouteState being used both as a // transport type and as a cache key; we'll address this once more of the // Segment Cache implementation has settled. // TODO: We should hoist the search params out of the FlightRouterState // type entirely, This is our plan for dynamic route params, too. return _segment.PAGE_SEGMENT_KEY; } const safeName = // But params typically don't include the leading slash. We should use // a different encoding to avoid this special case. segment === '/_not-found' ? '_not-found' : encodeToFilesystemAndURLSafeString(segment); // Since this is not a dynamic segment, it's fully encoded. It does not // need to be "hydrated" with a param value. return safeName; } const name = segment[0]; const paramType = segment[2]; const safeName = encodeToFilesystemAndURLSafeString(name); const encodedName = '$' + paramType + '$' + safeName; return encodedName; } function appendSegmentRequestKeyPart(parentRequestKey, parallelRouteKey, childRequestKeyPart) { // Aside from being filesystem safe, segment keys are also designed so that // each segment and parallel route creates its own subdirectory. Roughly in // the same shape as the source app directory. This is mostly just for easier // debugging (you can open up the build folder and navigate the output); if // we wanted to do we could just use a flat structure. // Omit the parallel route key for children, since this is the most // common case. Saves some bytes (and it's what the app directory does). const slotKey = parallelRouteKey === 'children' ? childRequestKeyPart : `@${encodeToFilesystemAndURLSafeString(parallelRouteKey)}/${childRequestKeyPart}`; return parentRequestKey + '/' + slotKey; } // Define a regex pattern to match the most common characters found in a route // param. It excludes anything that might not be cross-platform filesystem // compatible, like |. It does not need to be precise because the fallback is to // just base64url-encode the whole parameter, which is fine; we just don't do it // by default for compactness, and for easier debugging. const simpleParamValueRegex = /^[a-zA-Z0-9\-_@]+$/; function encodeToFilesystemAndURLSafeString(value) { if (simpleParamValueRegex.test(value)) { return value; } // If there are any unsafe characters, base64url-encode the entire value. // We also add a ! prefix so it doesn't collide with the simple case. const base64url = btoa(value).replace(/\+/g, '-') // Replace '+' with '-' .replace(/\//g, '_') // Replace '/' with '_' .replace(/=+$/, '') // Remove trailing '=' ; return '!' + base64url; } function convertSegmentPathToStaticExportFilename(segmentPath) { return `__next${segmentPath.replace(/\//g, '.')}.txt`; } }), "[project]/node_modules/next/dist/client/route-params.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { doesStaticSegmentAppearInURL: null, getCacheKeyForDynamicParam: null, getParamValueFromCacheKey: null, getRenderedPathname: null, getRenderedSearch: null, parseDynamicParamFromURLPart: null, urlSearchParamsToParsedUrlQuery: null, urlToUrlWithoutFlightMarker: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { doesStaticSegmentAppearInURL: function() { return doesStaticSegmentAppearInURL; }, getCacheKeyForDynamicParam: function() { return getCacheKeyForDynamicParam; }, getParamValueFromCacheKey: function() { return getParamValueFromCacheKey; }, getRenderedPathname: function() { return getRenderedPathname; }, getRenderedSearch: function() { return getRenderedSearch; }, parseDynamicParamFromURLPart: function() { return parseDynamicParamFromURLPart; }, urlSearchParamsToParsedUrlQuery: function() { return urlSearchParamsToParsedUrlQuery; }, urlToUrlWithoutFlightMarker: function() { return urlToUrlWithoutFlightMarker; } }); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const _segmentvalueencoding = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.js [app-ssr] (ecmascript)"); const _approuterheaders = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)"); function getRenderedSearch(response) { // If the server performed a rewrite, the search params used to render the // page will be different from the params in the request URL. In this case, // the response will include a header that gives the rewritten search query. const rewrittenQuery = response.headers.get(_approuterheaders.NEXT_REWRITTEN_QUERY_HEADER); if (rewrittenQuery !== null) { return rewrittenQuery === '' ? '' : '?' + rewrittenQuery; } // If the header is not present, there was no rewrite, so we use the search // query of the response URL. return urlToUrlWithoutFlightMarker(new URL(response.url)).search; } function getRenderedPathname(response) { // If the server performed a rewrite, the pathname used to render the // page will be different from the pathname in the request URL. In this case, // the response will include a header that gives the rewritten pathname. const rewrittenPath = response.headers.get(_approuterheaders.NEXT_REWRITTEN_PATH_HEADER); return rewrittenPath ?? urlToUrlWithoutFlightMarker(new URL(response.url)).pathname; } // Pathname parts come from `URL.pathname.split('/')`, so they are already // in the encoded form the URL parser produces. The server-side equivalent // (`get-dynamic-param.ts`) starts from a decoded param value and applies // `encodeURIComponent` once. The two encodings are not the same — for // example, the URL parser leaves `,` and `:` untouched while // `encodeURIComponent` percent-encodes them. To produce the same canonical // form on the client (and avoid double-encoding `%xx` sequences such as // `%2F` → `%252F`), we decode the URL part first and re-encode it. function canonicalizeURLPart(part) { try { return encodeURIComponent(decodeURIComponent(part)); } catch { // `decodeURIComponent` throws on malformed sequences. Fall back to the // already-encoded form rather than failing the navigation. return part; } } function parseDynamicParamFromURLPart(paramType, pathnameParts, partIndex) { // This needs to match the behavior in get-dynamic-param.ts. switch(paramType){ // Catchalls case 'c': { // Catchalls receive all the remaining URL parts. If there are no // remaining pathname parts, return an empty array. return partIndex < pathnameParts.length ? pathnameParts.slice(partIndex).map((s)=>canonicalizeURLPart(s)) : []; } // Catchall intercepted case 'ci(..)(..)': case 'ci(.)': case 'ci(..)': case 'ci(...)': { const prefix = paramType.length - 2; return partIndex < pathnameParts.length ? pathnameParts.slice(partIndex).map((s, i)=>{ if (i === 0) { return canonicalizeURLPart(s.slice(prefix)); } return canonicalizeURLPart(s); }) : []; } // Optional catchalls case 'oc': { // Optional catchalls receive all the remaining URL parts, unless this is // the end of the pathname, in which case they return null. return partIndex < pathnameParts.length ? pathnameParts.slice(partIndex).map((s)=>canonicalizeURLPart(s)) : null; } // Dynamic case 'd': { if (partIndex >= pathnameParts.length) { // The route tree expected there to be more parts in the URL than there // actually are. This could happen if the x-nextjs-rewritten-path header // is incorrectly set, or potentially due to bug in Next.js. TODO: // Should this be a hard error? During a prefetch, we can just abort. // During a client navigation, we could trigger a hard refresh. But if // it happens during initial render, we don't really have any // recovery options. return ''; } return canonicalizeURLPart(pathnameParts[partIndex]); } // Dynamic intercepted case 'di(..)(..)': case 'di(.)': case 'di(..)': case 'di(...)': { const prefix = paramType.length - 2; if (partIndex >= pathnameParts.length) { // The route tree expected there to be more parts in the URL than there // actually are. This could happen if the x-nextjs-rewritten-path header // is incorrectly set, or potentially due to bug in Next.js. TODO: // Should this be a hard error? During a prefetch, we can just abort. // During a client navigation, we could trigger a hard refresh. But if // it happens during initial render, we don't really have any // recovery options. return ''; } return canonicalizeURLPart(pathnameParts[partIndex].slice(prefix)); } default: paramType; return ''; } } function doesStaticSegmentAppearInURL(segment) { // This is not a parameterized segment; however, we need to determine // whether or not this segment appears in the URL. For example, this route // groups do not appear in the URL, so they should be skipped. Any other // special cases must be handled here. // TODO: Consider encoding this directly into the router tree instead of // inferring it on the client based on the segment type. Something like // a `doesAppearInURL` flag in FlightRouterState. if (segment === _segmentvalueencoding.ROOT_SEGMENT_REQUEST_KEY || // For some reason, the loader tree sometimes includes extra __PAGE__ // "layouts" when part of a parallel route. But it's not a leaf node. // Otherwise, we wouldn't need this special case because pages are // always leaf nodes. // TODO: Investigate why the loader produces these fake page segments. segment.startsWith(_segment.PAGE_SEGMENT_KEY) || // Route groups. segment[0] === '(' && segment.endsWith(')') || segment === _segment.DEFAULT_SEGMENT_KEY || segment === '/_not-found') { return false; } else { // All other segment types appear in the URL return true; } } function getCacheKeyForDynamicParam(paramValue, renderedSearch) { // This needs to match the logic in get-dynamic-param.ts, until we're able to // unify the various implementations so that these are always computed on // the client. if (typeof paramValue === 'string') { // TODO: Refactor or remove this helper function to accept a string rather // than the whole segment type. Also we can probably just append the // search string instead of turning it into JSON. const pageSegmentWithSearchParams = (0, _segment.addSearchParamsIfPageSegment)(paramValue, Object.fromEntries(new URLSearchParams(renderedSearch))); return pageSegmentWithSearchParams; } else if (paramValue === null) { return ''; } else { return paramValue.join('/'); } } function urlToUrlWithoutFlightMarker(url) { const urlWithoutFlightParameters = new URL(url); urlWithoutFlightParameters.searchParams.delete(_approuterheaders.NEXT_RSC_UNION_QUERY); if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; return urlWithoutFlightParameters; } function getParamValueFromCacheKey(paramCacheKey, paramType) { // Turn the cache key string sent by the server (as part of FlightRouterState) // into a value that can be passed to `useParams` and client components. const isCatchAll = paramType === 'c' || paramType === 'oc'; if (isCatchAll) { // Catch-all param keys are a concatenation of the path segments. // See equivalent logic in `getSelectedParams`. // TODO: We should just pass the array directly, rather than concatenate // it to a string and then split it back to an array. It needs to be an // array in some places, like when passing a key React, but we can convert // it at runtime in those places. return paramCacheKey.split('/'); } return paramCacheKey; } function urlSearchParamsToParsedUrlQuery(searchParams) { // Converts a URLSearchParams object to the same type used by the server when // creating search params props, i.e. the type returned by Node's // "querystring" module. const result = {}; for (const [key, value] of searchParams.entries()){ if (result[key] === undefined) { result[key] = value; } else if (Array.isArray(result[key])) { result[key].push(value); } else { result[key] = [ result[key], value ]; } } return result; } 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; } }), "[project]/node_modules/next/dist/client/components/router-reducer/create-href-from-url.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "createHrefFromUrl", { enumerable: true, get: function() { return createHrefFromUrl; } }); function createHrefFromUrl(url, includeHash = true) { return url.pathname + url.search + (includeHash ? url.hash : ''); } 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; } }), "[project]/node_modules/next/dist/client/flight-data-helpers.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { createInitialRSCPayloadFromFallbackPrerender: null, getFlightDataPartsFromPath: null, getNextFlightSegmentPath: null, normalizeFlightData: null, prepareFlightRouterStateForRequest: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { createInitialRSCPayloadFromFallbackPrerender: function() { return createInitialRSCPayloadFromFallbackPrerender; }, getFlightDataPartsFromPath: function() { return getFlightDataPartsFromPath; }, getNextFlightSegmentPath: function() { return getNextFlightSegmentPath; }, normalizeFlightData: function() { return normalizeFlightData; }, prepareFlightRouterStateForRequest: function() { return prepareFlightRouterStateForRequest; } }); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const _routeparams = __turbopack_context__.r("[project]/node_modules/next/dist/client/route-params.js [app-ssr] (ecmascript)"); const _createhreffromurl = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/create-href-from-url.js [app-ssr] (ecmascript)"); function getFlightDataPartsFromPath(flightDataPath) { // Pick the last 4 items from the `FlightDataPath` to get the [tree, seedData, viewport, isHeadPartial]. const flightDataPathLength = 4; // tree, seedData, and head are *always* the last three items in the `FlightDataPath`. const [tree, seedData, head, isHeadPartial] = flightDataPath.slice(-flightDataPathLength); // The `FlightSegmentPath` is everything except the last three items. For a root render, it won't be present. const segmentPath = flightDataPath.slice(0, -flightDataPathLength); return { // TODO: Unify these two segment path helpers. We are inconsistently pushing an empty segment ("") // to the start of the segment path in some places which makes it hard to use solely the segment path. // Look for "// TODO-APP: remove ''" in the codebase. pathToSegment: segmentPath.slice(0, -1), segmentPath, // if the `FlightDataPath` corresponds with the root, there'll be no segment path, // in which case we default to ''. segment: segmentPath[segmentPath.length - 1] ?? '', tree, seedData, head, isHeadPartial, isRootRender: flightDataPath.length === flightDataPathLength }; } function createInitialRSCPayloadFromFallbackPrerender(response, fallbackInitialRSCPayload) { // This is a static fallback page. In order to hydrate the page, we need to // parse the client params from the URL, but to account for the possibility // that the page was rewritten, we need to check the response headers // for x-nextjs-rewritten-path or x-nextjs-rewritten-query headers. Since // we can't access the headers of the initial document response, the client // performs a fetch request to the current location. Since it's possible that // the fetch request will be dynamically rewritten to a different path than // the initial document, this fetch request delivers _all_ the hydration data // for the page; it was not inlined into the document, like it normally // would be. // // TODO: Consider treating the case where fetch is rewritten to a different // path from the document as a special deopt case. We should optimistically // assume this won't happen, inline the data into the document, and perform // a minimal request (like a HEAD or range request) to verify that the // response matches. Tricky to get right because we need to account for // all the different deployment environments we support, like output: // "export" mode, where we currently don't assume that custom response // headers are present. // Patch the Flight data sent by the server with the correct params parsed // from the URL + response object. const renderedPathname = (0, _routeparams.getRenderedPathname)(response); const renderedSearch = (0, _routeparams.getRenderedSearch)(response); const canonicalUrl = (0, _createhreffromurl.createHrefFromUrl)(new URL(location.href)); const originalFlightDataPath = fallbackInitialRSCPayload.f[0]; const originalFlightRouterState = originalFlightDataPath[0]; const payload = { c: canonicalUrl.split('/'), q: renderedSearch, i: fallbackInitialRSCPayload.i, f: [ [ fillInFallbackFlightRouterState(originalFlightRouterState, renderedPathname, renderedSearch), originalFlightDataPath[1], originalFlightDataPath[2], originalFlightDataPath[2] ] ], m: fallbackInitialRSCPayload.m, G: fallbackInitialRSCPayload.G, S: fallbackInitialRSCPayload.S, h: fallbackInitialRSCPayload.h }; if (fallbackInitialRSCPayload.b) { payload.b = fallbackInitialRSCPayload.b; } return payload; } function fillInFallbackFlightRouterState(flightRouterState, renderedPathname, renderedSearch) { const pathnameParts = renderedPathname.split('/').filter((p)=>p !== ''); const index = 0; return fillInFallbackFlightRouterStateImpl(flightRouterState, renderedSearch, pathnameParts, index); } function fillInFallbackFlightRouterStateImpl(flightRouterState, renderedSearch, pathnameParts, pathnamePartsIndex) { const originalSegment = flightRouterState[0]; let newSegment; let doesAppearInURL; if (typeof originalSegment === 'string') { newSegment = originalSegment; doesAppearInURL = (0, _routeparams.doesStaticSegmentAppearInURL)(originalSegment); } else { const paramName = originalSegment[0]; const paramType = originalSegment[2]; const staticSiblings = originalSegment[3]; const paramValue = (0, _routeparams.parseDynamicParamFromURLPart)(paramType, pathnameParts, pathnamePartsIndex); const cacheKey = (0, _routeparams.getCacheKeyForDynamicParam)(paramValue, renderedSearch); newSegment = [ paramName, cacheKey, paramType, staticSiblings ]; doesAppearInURL = true; } // Only increment the index if the segment appears in the URL. If it's a // "virtual" segment, like a route group, it remains the same. const childPathnamePartsIndex = doesAppearInURL ? pathnamePartsIndex + 1 : pathnamePartsIndex; const children = flightRouterState[1]; const newChildren = {}; for(let key in children){ const childFlightRouterState = children[key]; newChildren[key] = fillInFallbackFlightRouterStateImpl(childFlightRouterState, renderedSearch, pathnameParts, childPathnamePartsIndex); } const newState = [ newSegment, newChildren, null, flightRouterState[3], flightRouterState[4] ]; return newState; } function getNextFlightSegmentPath(flightSegmentPath) { // Since `FlightSegmentPath` is a repeated tuple of `Segment` and `ParallelRouteKey`, we slice off two items // to get the next segment path. return flightSegmentPath.slice(2); } function normalizeFlightData(flightData) { // FlightData can be a string when the server didn't respond with a proper flight response, // or when a redirect happens, to signal to the client that it needs to perform an MPA navigation. if (typeof flightData === 'string') { return flightData; } return flightData.map((flightDataPath)=>getFlightDataPartsFromPath(flightDataPath)); } function prepareFlightRouterStateForRequest(flightRouterState, isHmrRefresh) { // HMR requests need the complete, unmodified state for proper functionality if (isHmrRefresh) { return encodeURIComponent(JSON.stringify(flightRouterState)); } return encodeURIComponent(JSON.stringify(stripClientOnlyDataFromFlightRouterState(flightRouterState))); } /** * Recursively strips client-only data from FlightRouterState while preserving * server-needed information for proper rendering decisions. */ function stripClientOnlyDataFromFlightRouterState(flightRouterState) { const [segment, parallelRoutes, _refreshState, refreshMarker, prefetchHints] = flightRouterState; // Strip client-only data from the segment const cleanedSegment = stripClientOnlyDataFromSegment(segment); // Recursively process parallel routes const cleanedParallelRoutes = {}; for (const [key, childState] of Object.entries(parallelRoutes)){ cleanedParallelRoutes[key] = stripClientOnlyDataFromFlightRouterState(childState); } const result = [ cleanedSegment, cleanedParallelRoutes ]; if (refreshMarker) { result[2] = null // null slightly more compact than undefined ; result[3] = refreshMarker; } // Append optional fields if present if (prefetchHints !== undefined) { result[4] = prefetchHints; } // Everything else is used only by the client and is not needed for requests. return result; } /** * Strips client-only data from segments: * - Search parameters from __PAGE__ segments * - staticSiblings from dynamic segment tuples (only needed for client-side * prefetch reuse decisions) */ function stripClientOnlyDataFromSegment(segment) { if (typeof segment === 'string') { // Strip search params from __PAGE__ segments if (segment.startsWith(_segment.PAGE_SEGMENT_KEY + '?')) { return _segment.PAGE_SEGMENT_KEY; } return segment; } // Dynamic segment tuple: [paramName, paramCacheKey, paramType, staticSiblings] // Strip staticSiblings (4th element) since server doesn't need it const [paramName, paramCacheKey, paramType] = segment; return [ paramName, paramCacheKey, paramType, null ]; } 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; } }), "[project]/node_modules/next/dist/shared/lib/hash.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; // http://www.cse.yorku.ca/~oz/hash.html // More specifically, 32-bit hash via djbxor // (ref: https://gist.github.com/eplawless/52813b1d8ad9af510d85?permalink_comment_id=3367765#gistcomment-3367765) // This is due to number type differences between rust for turbopack to js number types, // where rust does not have easy way to repreesnt js's 53-bit float number type for the matching // overflow behavior. This is more `correct` in terms of having canonical hash across different runtime / implementation // as can gaurantee determinstic output from 32bit hash. Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { djb2Hash: null, hexHash: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { djb2Hash: function() { return djb2Hash; }, hexHash: function() { return hexHash; } }); function djb2Hash(str) { let hash = 5381; for(let i = 0; i < str.length; i++){ const char = str.charCodeAt(i); hash = (hash << 5) + hash + char & 0xffffffff; } return hash >>> 0; } function hexHash(str) { return djb2Hash(str).toString(36).slice(0, 5); } }), "[project]/node_modules/next/dist/shared/lib/router/utils/cache-busting-search-param.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { computeCacheBustingSearchParam: null, computeLegacyCacheBustingSearchParam: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { computeCacheBustingSearchParam: function() { return computeCacheBustingSearchParam; }, computeLegacyCacheBustingSearchParam: function() { return computeLegacyCacheBustingSearchParam; } }); const _hash = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/hash.js [app-ssr] (ecmascript)"); const CACHE_BUSTING_SEARCH_PARAM_DIGEST_BYTES = 12; const textEncoder = new TextEncoder(); function encodeCacheBustingSearchParam(bytes) { let binary = ''; for(let i = 0; i < bytes.length; i++){ binary += String.fromCharCode(bytes[i]); } return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } function normalizeCacheBustingInput(value) { if (value === undefined) { return '0'; } return Array.isArray(value) ? value.join(',') : value; } function createCacheBustingSearchParamInput(prefetchHeader, segmentPrefetchHeader, stateTreeHeader, nextUrlHeader) { if ((prefetchHeader === undefined || prefetchHeader === '0') && segmentPrefetchHeader === undefined && stateTreeHeader === undefined && nextUrlHeader === undefined) { return null; } return [ prefetchHeader ?? '0', normalizeCacheBustingInput(segmentPrefetchHeader), normalizeCacheBustingInput(stateTreeHeader), normalizeCacheBustingInput(nextUrlHeader) ].join(','); } async function computeCacheBustingSearchParamFromInput(input) { // Truncate SHA-256 to 96 bits to keep `_rsc` compact const digest = await globalThis.crypto.subtle.digest('SHA-256', textEncoder.encode(input)); return encodeCacheBustingSearchParam(new Uint8Array(digest).subarray(0, CACHE_BUSTING_SEARCH_PARAM_DIGEST_BYTES)); } async function computeCacheBustingSearchParam(prefetchHeader, segmentPrefetchHeader, stateTreeHeader, nextUrlHeader) { const input = createCacheBustingSearchParamInput(prefetchHeader, segmentPrefetchHeader, stateTreeHeader, nextUrlHeader); if (input === null) { return ''; } return computeCacheBustingSearchParamFromInput(input); } function computeLegacyCacheBustingSearchParam(prefetchHeader, segmentPrefetchHeader, stateTreeHeader, nextUrlHeader) { const input = createCacheBustingSearchParamInput(prefetchHeader, segmentPrefetchHeader, stateTreeHeader, nextUrlHeader); if (input === null) { return ''; } return (0, _hash.hexHash)(input); } }), "[project]/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { setCacheBustingSearchParam: null, setCacheBustingSearchParamWithHash: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { setCacheBustingSearchParam: function() { return setCacheBustingSearchParam; }, setCacheBustingSearchParamWithHash: function() { return setCacheBustingSearchParamWithHash; } }); const _cachebustingsearchparam = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/cache-busting-search-param.js [app-ssr] (ecmascript)"); const _approuterheaders = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)"); async function computeClientCacheBustingSearchParam(headers) { if (typeof globalThis.crypto?.subtle?.digest === 'function') { return (0, _cachebustingsearchparam.computeCacheBustingSearchParam)(headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER], headers[_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER], headers[_approuterheaders.NEXT_ROUTER_STATE_TREE_HEADER], headers[_approuterheaders.NEXT_URL]); } return (0, _cachebustingsearchparam.computeLegacyCacheBustingSearchParam)(headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER], headers[_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER], headers[_approuterheaders.NEXT_ROUTER_STATE_TREE_HEADER], headers[_approuterheaders.NEXT_URL]); } const setCacheBustingSearchParam = async (url, headers)=>{ const uniqueCacheKey = await computeClientCacheBustingSearchParam(headers); setCacheBustingSearchParamWithHash(url, uniqueCacheKey); }; const setCacheBustingSearchParamWithHash = (url, hash)=>{ /** * Note that we intentionally do not use `url.searchParams.set` here: * * const url = new URL('https://example.com/search?q=custom%20spacing'); * url.searchParams.set('_rsc', 'abc123'); * console.log(url.toString()); // Outputs: https://example.com/search?q=custom+spacing&_rsc=abc123 * ^ <--- this is causing confusion * This is in fact intended based on https://url.spec.whatwg.org/#interface-urlsearchparams, but * we want to preserve the %20 as %20 if that's what the user passed in, hence the custom * logic below. */ const existingSearch = url.search; const rawQuery = existingSearch.startsWith('?') ? existingSearch.slice(1) : existingSearch; // Always remove any existing cache busting param and add a fresh one to ensure // we have the correct value based on current request headers const pairs = rawQuery.split('&').filter((pair)=>pair && !pair.startsWith(`${_approuterheaders.NEXT_RSC_UNION_QUERY}=`)); if (hash.length > 0) { pairs.push(`${_approuterheaders.NEXT_RSC_UNION_QUERY}=${hash}`); } else { pairs.push(`${_approuterheaders.NEXT_RSC_UNION_QUERY}`); } url.search = pairs.length ? `?${pairs.join('&')}` : ''; }; 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; } }), "[project]/node_modules/next/dist/shared/lib/deployment-id.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getAssetToken: null, getAssetTokenQuery: null, getDeploymentId: null, getDeploymentIdQuery: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getAssetToken: function() { return getAssetToken; }, getAssetTokenQuery: function() { return getAssetTokenQuery; }, getDeploymentId: function() { return getDeploymentId; }, getDeploymentIdQuery: function() { return getDeploymentIdQuery; } }); let deploymentId; if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; else { // Client side: replaced with globalThis.NEXT_DEPLOYMENT_ID // Server side: left as is or replaced with a string or replaced with false deploymentId = ("TURBOPACK compile-time value", false) || undefined; } function getDeploymentId() { return deploymentId; } function getDeploymentIdQuery(ampersand = false) { let id = getDeploymentId(); if (id) { return `${ampersand ? '&' : '?'}dpl=${id}`; } return ''; } function getAssetToken() { return ("TURBOPACK compile-time value", "") || ("TURBOPACK compile-time value", false); } function getAssetTokenQuery(ampersand = false) { let id = getAssetToken(); if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; return ''; } }), "[project]/node_modules/next/dist/client/navigation-build-id.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; // This gets assigned as a side-effect during app initialization. Because it // represents the build used to create the JS bundle, it should never change // after being set, so we store it in a global variable. // // When performing RSC requests, if the incoming data has a different build ID, // we perform an MPA navigation/refresh to load the updated build and ensure // that the client and server in sync. // // Starts as an empty string. In practice, because setNavigationBuildId is called during initialization // before hydration starts, this will always get reassigned to the actual ID before it's ever needed // by a navigation. If for some reasons it didn't, due to a bug or race condition, then on // navigation the build comparision would fail and trigger an MPA navigation. // // Note that this can also be initialized with the deployment id instead (if available). So it's not // the same as "the build id", but we are running out of alternative names for "build id or // deployment id". Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getNavigationBuildId: null, setNavigationBuildId: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getNavigationBuildId: function() { return getNavigationBuildId; }, setNavigationBuildId: function() { return setNavigationBuildId; } }); let globalBuildId = ''; function setNavigationBuildId(buildId) { globalBuildId = buildId; } function getNavigationBuildId() { return globalBuildId; } 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; } }), "[project]/node_modules/next/dist/lib/constants.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { ACTION_SUFFIX: null, APP_DIR_ALIAS: null, CACHE_ONE_YEAR_SECONDS: null, DOT_NEXT_ALIAS: null, ESLINT_DEFAULT_DIRS: null, GSP_NO_RETURNED_VALUE: null, GSSP_COMPONENT_MEMBER_ERROR: null, GSSP_NO_RETURNED_VALUE: null, HTML_CONTENT_TYPE_HEADER: null, INFINITE_CACHE: null, INSTRUMENTATION_HOOK_FILENAME: null, JSON_CONTENT_TYPE_HEADER: null, MATCHED_PATH_HEADER: null, MIDDLEWARE_FILENAME: null, MIDDLEWARE_LOCATION_REGEXP: null, NEXT_BODY_SUFFIX: null, NEXT_CACHE_IMPLICIT_TAG_ID: null, NEXT_CACHE_REVALIDATED_TAGS_HEADER: null, NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER: null, NEXT_CACHE_ROOT_PARAM_TAG_ID: null, NEXT_CACHE_SOFT_TAG_MAX_LENGTH: null, NEXT_CACHE_TAGS_HEADER: null, NEXT_CACHE_TAG_MAX_ITEMS: null, NEXT_CACHE_TAG_MAX_LENGTH: null, NEXT_DATA_SUFFIX: null, NEXT_INTERCEPTION_MARKER_PREFIX: null, NEXT_META_SUFFIX: null, NEXT_NAV_DEPLOYMENT_ID_HEADER: null, NEXT_QUERY_PARAM_PREFIX: null, NEXT_RESUME_HEADER: null, NEXT_RESUME_STATE_LENGTH_HEADER: null, NON_STANDARD_NODE_ENV: null, PAGES_DIR_ALIAS: null, PRERENDER_REVALIDATE_HEADER: null, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER: null, PROXY_FILENAME: null, PROXY_LOCATION_REGEXP: null, PUBLIC_DIR_MIDDLEWARE_CONFLICT: null, ROOT_DIR_ALIAS: null, RSC_ACTION_CLIENT_WRAPPER_ALIAS: null, RSC_ACTION_ENCRYPTION_ALIAS: null, RSC_ACTION_PROXY_ALIAS: null, RSC_ACTION_VALIDATE_ALIAS: null, RSC_CACHE_WRAPPER_ALIAS: null, RSC_DYNAMIC_IMPORT_WRAPPER_ALIAS: null, RSC_MOD_REF_PROXY_ALIAS: null, RSC_SEGMENTS_DIR_SUFFIX: null, RSC_SEGMENT_SUFFIX: null, RSC_SUFFIX: null, SERVER_PROPS_EXPORT_ERROR: null, SERVER_PROPS_GET_INIT_PROPS_CONFLICT: null, SERVER_PROPS_SSG_CONFLICT: null, SERVER_RUNTIME: null, SSG_FALLBACK_EXPORT_ERROR: null, SSG_GET_INITIAL_PROPS_CONFLICT: null, STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR: null, TEXT_PLAIN_CONTENT_TYPE_HEADER: null, UNSTABLE_REVALIDATE_RENAME_ERROR: null, WEBPACK_LAYERS: null, WEBPACK_RESOURCE_QUERIES: null, WEB_SOCKET_MAX_RECONNECTIONS: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { ACTION_SUFFIX: function() { return ACTION_SUFFIX; }, APP_DIR_ALIAS: function() { return APP_DIR_ALIAS; }, CACHE_ONE_YEAR_SECONDS: function() { return CACHE_ONE_YEAR_SECONDS; }, DOT_NEXT_ALIAS: function() { return DOT_NEXT_ALIAS; }, ESLINT_DEFAULT_DIRS: function() { return ESLINT_DEFAULT_DIRS; }, GSP_NO_RETURNED_VALUE: function() { return GSP_NO_RETURNED_VALUE; }, GSSP_COMPONENT_MEMBER_ERROR: function() { return GSSP_COMPONENT_MEMBER_ERROR; }, GSSP_NO_RETURNED_VALUE: function() { return GSSP_NO_RETURNED_VALUE; }, HTML_CONTENT_TYPE_HEADER: function() { return HTML_CONTENT_TYPE_HEADER; }, INFINITE_CACHE: function() { return INFINITE_CACHE; }, INSTRUMENTATION_HOOK_FILENAME: function() { return INSTRUMENTATION_HOOK_FILENAME; }, JSON_CONTENT_TYPE_HEADER: function() { return JSON_CONTENT_TYPE_HEADER; }, MATCHED_PATH_HEADER: function() { return MATCHED_PATH_HEADER; }, MIDDLEWARE_FILENAME: function() { return MIDDLEWARE_FILENAME; }, MIDDLEWARE_LOCATION_REGEXP: function() { return MIDDLEWARE_LOCATION_REGEXP; }, NEXT_BODY_SUFFIX: function() { return NEXT_BODY_SUFFIX; }, NEXT_CACHE_IMPLICIT_TAG_ID: function() { return NEXT_CACHE_IMPLICIT_TAG_ID; }, NEXT_CACHE_REVALIDATED_TAGS_HEADER: function() { return NEXT_CACHE_REVALIDATED_TAGS_HEADER; }, NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER: function() { return NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER; }, NEXT_CACHE_ROOT_PARAM_TAG_ID: function() { return NEXT_CACHE_ROOT_PARAM_TAG_ID; }, NEXT_CACHE_SOFT_TAG_MAX_LENGTH: function() { return NEXT_CACHE_SOFT_TAG_MAX_LENGTH; }, NEXT_CACHE_TAGS_HEADER: function() { return NEXT_CACHE_TAGS_HEADER; }, NEXT_CACHE_TAG_MAX_ITEMS: function() { return NEXT_CACHE_TAG_MAX_ITEMS; }, NEXT_CACHE_TAG_MAX_LENGTH: function() { return NEXT_CACHE_TAG_MAX_LENGTH; }, NEXT_DATA_SUFFIX: function() { return NEXT_DATA_SUFFIX; }, NEXT_INTERCEPTION_MARKER_PREFIX: function() { return NEXT_INTERCEPTION_MARKER_PREFIX; }, NEXT_META_SUFFIX: function() { return NEXT_META_SUFFIX; }, NEXT_NAV_DEPLOYMENT_ID_HEADER: function() { return NEXT_NAV_DEPLOYMENT_ID_HEADER; }, NEXT_QUERY_PARAM_PREFIX: function() { return NEXT_QUERY_PARAM_PREFIX; }, NEXT_RESUME_HEADER: function() { return NEXT_RESUME_HEADER; }, NEXT_RESUME_STATE_LENGTH_HEADER: function() { return NEXT_RESUME_STATE_LENGTH_HEADER; }, NON_STANDARD_NODE_ENV: function() { return NON_STANDARD_NODE_ENV; }, PAGES_DIR_ALIAS: function() { return PAGES_DIR_ALIAS; }, PRERENDER_REVALIDATE_HEADER: function() { return PRERENDER_REVALIDATE_HEADER; }, PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER: function() { return PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER; }, PROXY_FILENAME: function() { return PROXY_FILENAME; }, PROXY_LOCATION_REGEXP: function() { return PROXY_LOCATION_REGEXP; }, PUBLIC_DIR_MIDDLEWARE_CONFLICT: function() { return PUBLIC_DIR_MIDDLEWARE_CONFLICT; }, ROOT_DIR_ALIAS: function() { return ROOT_DIR_ALIAS; }, RSC_ACTION_CLIENT_WRAPPER_ALIAS: function() { return RSC_ACTION_CLIENT_WRAPPER_ALIAS; }, RSC_ACTION_ENCRYPTION_ALIAS: function() { return RSC_ACTION_ENCRYPTION_ALIAS; }, RSC_ACTION_PROXY_ALIAS: function() { return RSC_ACTION_PROXY_ALIAS; }, RSC_ACTION_VALIDATE_ALIAS: function() { return RSC_ACTION_VALIDATE_ALIAS; }, RSC_CACHE_WRAPPER_ALIAS: function() { return RSC_CACHE_WRAPPER_ALIAS; }, RSC_DYNAMIC_IMPORT_WRAPPER_ALIAS: function() { return RSC_DYNAMIC_IMPORT_WRAPPER_ALIAS; }, RSC_MOD_REF_PROXY_ALIAS: function() { return RSC_MOD_REF_PROXY_ALIAS; }, RSC_SEGMENTS_DIR_SUFFIX: function() { return RSC_SEGMENTS_DIR_SUFFIX; }, RSC_SEGMENT_SUFFIX: function() { return RSC_SEGMENT_SUFFIX; }, RSC_SUFFIX: function() { return RSC_SUFFIX; }, SERVER_PROPS_EXPORT_ERROR: function() { return SERVER_PROPS_EXPORT_ERROR; }, SERVER_PROPS_GET_INIT_PROPS_CONFLICT: function() { return SERVER_PROPS_GET_INIT_PROPS_CONFLICT; }, SERVER_PROPS_SSG_CONFLICT: function() { return SERVER_PROPS_SSG_CONFLICT; }, SERVER_RUNTIME: function() { return SERVER_RUNTIME; }, SSG_FALLBACK_EXPORT_ERROR: function() { return SSG_FALLBACK_EXPORT_ERROR; }, SSG_GET_INITIAL_PROPS_CONFLICT: function() { return SSG_GET_INITIAL_PROPS_CONFLICT; }, STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR: function() { return STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR; }, TEXT_PLAIN_CONTENT_TYPE_HEADER: function() { return TEXT_PLAIN_CONTENT_TYPE_HEADER; }, UNSTABLE_REVALIDATE_RENAME_ERROR: function() { return UNSTABLE_REVALIDATE_RENAME_ERROR; }, WEBPACK_LAYERS: function() { return WEBPACK_LAYERS; }, WEBPACK_RESOURCE_QUERIES: function() { return WEBPACK_RESOURCE_QUERIES; }, WEB_SOCKET_MAX_RECONNECTIONS: function() { return WEB_SOCKET_MAX_RECONNECTIONS; } }); const TEXT_PLAIN_CONTENT_TYPE_HEADER = 'text/plain'; const HTML_CONTENT_TYPE_HEADER = 'text/html; charset=utf-8'; const JSON_CONTENT_TYPE_HEADER = 'application/json; charset=utf-8'; const NEXT_QUERY_PARAM_PREFIX = 'nxtP'; const NEXT_INTERCEPTION_MARKER_PREFIX = 'nxtI'; const MATCHED_PATH_HEADER = 'x-matched-path'; const PRERENDER_REVALIDATE_HEADER = 'x-prerender-revalidate'; const PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER = 'x-prerender-revalidate-if-generated'; const RSC_SEGMENTS_DIR_SUFFIX = '.segments'; const RSC_SEGMENT_SUFFIX = '.segment.rsc'; const RSC_SUFFIX = '.rsc'; const ACTION_SUFFIX = '.action'; const NEXT_DATA_SUFFIX = '.json'; const NEXT_META_SUFFIX = '.meta'; const NEXT_BODY_SUFFIX = '.body'; const NEXT_NAV_DEPLOYMENT_ID_HEADER = 'x-nextjs-deployment-id'; const NEXT_CACHE_TAGS_HEADER = 'x-next-cache-tags'; const NEXT_CACHE_REVALIDATED_TAGS_HEADER = 'x-next-revalidated-tags'; const NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER = 'x-next-revalidate-tag-token'; const NEXT_RESUME_HEADER = 'next-resume'; const NEXT_RESUME_STATE_LENGTH_HEADER = 'x-next-resume-state-length'; const NEXT_CACHE_TAG_MAX_ITEMS = 128; const NEXT_CACHE_TAG_MAX_LENGTH = 256; const NEXT_CACHE_SOFT_TAG_MAX_LENGTH = 1024; const NEXT_CACHE_IMPLICIT_TAG_ID = '_N_T_'; const NEXT_CACHE_ROOT_PARAM_TAG_ID = '_N_RP_'; const CACHE_ONE_YEAR_SECONDS = 31536000; const INFINITE_CACHE = 0xfffffffe; const MIDDLEWARE_FILENAME = 'middleware'; const MIDDLEWARE_LOCATION_REGEXP = `(?:src/)?${MIDDLEWARE_FILENAME}`; const PROXY_FILENAME = 'proxy'; const PROXY_LOCATION_REGEXP = `(?:src/)?${PROXY_FILENAME}`; const INSTRUMENTATION_HOOK_FILENAME = 'instrumentation'; const PAGES_DIR_ALIAS = 'private-next-pages'; const DOT_NEXT_ALIAS = 'private-dot-next'; const ROOT_DIR_ALIAS = 'private-next-root-dir'; const APP_DIR_ALIAS = 'private-next-app-dir'; const RSC_MOD_REF_PROXY_ALIAS = 'private-next-rsc-mod-ref-proxy'; const RSC_ACTION_VALIDATE_ALIAS = 'private-next-rsc-action-validate'; const RSC_ACTION_PROXY_ALIAS = 'private-next-rsc-server-reference'; const RSC_CACHE_WRAPPER_ALIAS = 'private-next-rsc-cache-wrapper'; const RSC_DYNAMIC_IMPORT_WRAPPER_ALIAS = 'private-next-rsc-track-dynamic-import'; const RSC_ACTION_ENCRYPTION_ALIAS = 'private-next-rsc-action-encryption'; const RSC_ACTION_CLIENT_WRAPPER_ALIAS = 'private-next-rsc-action-client-wrapper'; const PUBLIC_DIR_MIDDLEWARE_CONFLICT = `You can not have a '_next' folder inside of your public folder. This conflicts with the internal '/_next' route. https://nextjs.org/docs/messages/public-next-folder-conflict`; const SSG_GET_INITIAL_PROPS_CONFLICT = `You can not use getInitialProps with getStaticProps. To use SSG, please remove your getInitialProps`; const SERVER_PROPS_GET_INIT_PROPS_CONFLICT = `You can not use getInitialProps with getServerSideProps. Please remove getInitialProps.`; const SERVER_PROPS_SSG_CONFLICT = `You can not use getStaticProps or getStaticPaths with getServerSideProps. To use SSG, please remove getServerSideProps`; const STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR = `can not have getInitialProps/getServerSideProps, https://nextjs.org/docs/messages/404-get-initial-props`; const SERVER_PROPS_EXPORT_ERROR = `pages with \`getServerSideProps\` can not be exported. See more info here: https://nextjs.org/docs/messages/gssp-export`; const GSP_NO_RETURNED_VALUE = 'Your `getStaticProps` function did not return an object. Did you forget to add a `return`?'; const GSSP_NO_RETURNED_VALUE = 'Your `getServerSideProps` function did not return an object. Did you forget to add a `return`?'; const UNSTABLE_REVALIDATE_RENAME_ERROR = 'The `unstable_revalidate` property is available for general use.\n' + 'Please use `revalidate` instead.'; const GSSP_COMPONENT_MEMBER_ERROR = `can not be attached to a page's component and must be exported from the page. See more info here: https://nextjs.org/docs/messages/gssp-component-member`; const NON_STANDARD_NODE_ENV = `You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env`; const SSG_FALLBACK_EXPORT_ERROR = `Pages with \`fallback\` enabled in \`getStaticPaths\` can not be exported. See more info here: https://nextjs.org/docs/messages/ssg-fallback-true-export`; const ESLINT_DEFAULT_DIRS = [ 'app', 'pages', 'components', 'lib', 'src' ]; const SERVER_RUNTIME = { edge: 'edge', experimentalEdge: 'experimental-edge', nodejs: 'nodejs' }; const WEB_SOCKET_MAX_RECONNECTIONS = 12; /** * The names of the webpack layers. These layers are the primitives for the * webpack chunks. */ const WEBPACK_LAYERS_NAMES = { /** * The layer for the shared code between the client and server bundles. */ shared: 'shared', /** * The layer for server-only runtime and picking up `react-server` export conditions. * Including app router RSC pages and app router custom routes and metadata routes. */ reactServerComponents: 'rsc', /** * Server Side Rendering layer for app (ssr). */ serverSideRendering: 'ssr', /** * The browser client bundle layer for actions. */ actionBrowser: 'action-browser', /** * The Node.js bundle layer for the API routes. */ apiNode: 'api-node', /** * The Edge Lite bundle layer for the API routes. */ apiEdge: 'api-edge', /** * The layer for the middleware code. */ middleware: 'middleware', /** * The layer for the instrumentation hooks. */ instrument: 'instrument', /** * The layer for assets on the edge. */ edgeAsset: 'edge-asset', /** * The browser client bundle layer for App directory. */ appPagesBrowser: 'app-pages-browser', /** * The browser client bundle layer for Pages directory. */ pagesDirBrowser: 'pages-dir-browser', /** * The Edge Lite bundle layer for Pages directory. */ pagesDirEdge: 'pages-dir-edge', /** * The Node.js bundle layer for Pages directory. */ pagesDirNode: 'pages-dir-node' }; const WEBPACK_LAYERS = { ...WEBPACK_LAYERS_NAMES, GROUP: { builtinReact: [ WEBPACK_LAYERS_NAMES.reactServerComponents, WEBPACK_LAYERS_NAMES.actionBrowser ], serverOnly: [ WEBPACK_LAYERS_NAMES.reactServerComponents, WEBPACK_LAYERS_NAMES.actionBrowser, WEBPACK_LAYERS_NAMES.instrument, WEBPACK_LAYERS_NAMES.middleware ], neutralTarget: [ // pages api WEBPACK_LAYERS_NAMES.apiNode, WEBPACK_LAYERS_NAMES.apiEdge ], clientOnly: [ WEBPACK_LAYERS_NAMES.serverSideRendering, WEBPACK_LAYERS_NAMES.appPagesBrowser ], bundled: [ WEBPACK_LAYERS_NAMES.reactServerComponents, WEBPACK_LAYERS_NAMES.actionBrowser, WEBPACK_LAYERS_NAMES.serverSideRendering, WEBPACK_LAYERS_NAMES.appPagesBrowser, WEBPACK_LAYERS_NAMES.shared, WEBPACK_LAYERS_NAMES.instrument, WEBPACK_LAYERS_NAMES.middleware ], appPages: [ // app router pages and layouts WEBPACK_LAYERS_NAMES.reactServerComponents, WEBPACK_LAYERS_NAMES.serverSideRendering, WEBPACK_LAYERS_NAMES.appPagesBrowser, WEBPACK_LAYERS_NAMES.actionBrowser ] } }; const WEBPACK_RESOURCE_QUERIES = { edgeSSREntry: '__next_edge_ssr_entry__', metadata: '__next_metadata__', metadataRoute: '__next_metadata_route__', metadataImageMeta: '__next_metadata_image_meta__' }; }), "[project]/node_modules/next/dist/client/components/router-reducer/is-navigating-to-new-root-layout.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "isNavigatingToNewRootLayout", { enumerable: true, get: function() { return isNavigatingToNewRootLayout; } }); const _approutertypes = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/app-router-types.js [app-ssr] (ecmascript)"); function isNavigatingToNewRootLayout(currentTree, nextTree) { // Compare segments const currentTreeSegment = currentTree[0]; const nextTreeSegment = nextTree.segment; // If any segment is different before we find the root layout, the root layout has changed. // E.g. /same/(group1)/layout.js -> /same/(group2)/layout.js // First segment is 'same' for both, keep looking. (group1) changed to (group2) before the root layout was found, it must have changed. if (Array.isArray(currentTreeSegment) && Array.isArray(nextTreeSegment)) { // Compare dynamic param name and type but ignore the value, different values would not affect the current root layout // /[name] - /slug1 and /slug2, both values (slug1 & slug2) still has the same layout /[name]/layout.js if (currentTreeSegment[0] !== nextTreeSegment[0] || currentTreeSegment[2] !== nextTreeSegment[2]) { return true; } } else if (currentTreeSegment !== nextTreeSegment) { return true; } // Current tree root layout found const currentIsRootLayout = ((currentTree[4] ?? 0) & _approutertypes.PrefetchHint.IsRootLayout) !== 0; const nextIsRootLayout = (nextTree.prefetchHints & _approutertypes.PrefetchHint.IsRootLayout) !== 0; if (currentIsRootLayout) { // If the next tree doesn't have the root layout flag, it must have changed. return !nextIsRootLayout; } // Current tree didn't have its root layout here, must have changed. if (nextIsRootLayout) { return true; } const slots = nextTree.slots; const currentTreeChildren = currentTree[1]; if (slots !== null) { for(const slot in slots){ const nextTreeChild = slots[slot]; const currentTreeChild = currentTreeChildren[slot]; if (currentTreeChild === undefined || isNavigatingToNewRootLayout(currentTreeChild, nextTreeChild)) { return true; } } } return false; } 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; } }), "[project]/node_modules/next/dist/client/components/router-reducer/reducers/committed-state.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getLastCommittedTree: null, setLastCommittedTree: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getLastCommittedTree: function() { return getLastCommittedTree; }, setLastCommittedTree: function() { return setLastCommittedTree; } }); // The tree from the last state that was committed to the browser history // (i.e., the last state for which HistoryUpdater's useInsertionEffect ran). // This lets the server-patch reducer distinguish between retrying a // navigation that already pushed a history entry vs one whose transition // suspended and never committed. // // Currently only used by the server-patch retry logic, but this module is a // stepping stone toward a broader refactor of the navigation queue. The // existing AppRouter action queue will eventually be replaced by a more // reactive model that explicitly tracks pending vs committed navigation // state. This file will likely evolve into (or be subsumed by) that new // implementation. let lastCommittedTree = null; function getLastCommittedTree() { return lastCommittedTree; } function setLastCommittedTree(tree) { lastCommittedTree = tree; } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/lru.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { cleanup: null, deleteFromLru: null, lruPut: null, updateLruSize: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { cleanup: function() { return cleanup; }, deleteFromLru: function() { return deleteFromLru; }, lruPut: function() { return lruPut; }, updateLruSize: function() { return updateLruSize; } }); const _cachemap = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-map.js [app-ssr] (ecmascript)"); const _scheduler = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/scheduler.js [app-ssr] (ecmascript)"); // We use an LRU for memory management. We must update this whenever we add or // remove a new cache entry, or when an entry changes size. let head = null; let lruSize = 0; // TODO: I chose the max size somewhat arbitrarily. Consider setting this based // on navigator.deviceMemory, or some other heuristic. We should make this // customizable via the Next.js config, too. const maxLruSize = 50 * 1024 * 1024 // 50 MB ; function lruPut(node) { if (head === node) { // Already at the head return; } const prev = node.prev; const next = node.next; if (next === null || prev === null) { // This is an insertion lruSize += node.size; // Whenever we add an entry, we need to check if we've exceeded the // max size. We don't evict entries immediately; they're evicted later in // an asynchronous task. ensureCleanupIsScheduled(); } else { // This is a move. Remove from its current position. prev.next = next; next.prev = prev; } // Move to the front of the list if (head === null) { // This is the first entry node.prev = node; node.next = node; } else { // Add to the front of the list const tail = head.prev; node.prev = tail; // In practice, this is never null, but that isn't encoded in the type if (tail !== null) { tail.next = node; } node.next = head; head.prev = node; } head = node; } function updateLruSize(node, newNodeSize) { // This is a separate function from `put` so that we can resize the entry // regardless of whether it's currently being tracked by the LRU. const prevNodeSize = node.size; node.size = newNodeSize; if (node.next === null) { // This entry is not currently being tracked by the LRU. return; } // Update the total LRU size lruSize = lruSize - prevNodeSize + newNodeSize; ensureCleanupIsScheduled(); } function deleteFromLru(deleted) { const next = deleted.next; const prev = deleted.prev; if (next !== null && prev !== null) { lruSize -= deleted.size; deleted.next = null; deleted.prev = null; // Remove from the list if (head === deleted) { // Update the head if (next === head) { // This was the last entry head = null; } else { head = next; prev.next = next; next.prev = prev; } } else { prev.next = next; next.prev = prev; } } else { // Already deleted } } function ensureCleanupIsScheduled() { if (lruSize <= maxLruSize) { return; } // To schedule cleanup, ping the prefetch scheduler. At the end of its work // loop, once there are no queued tasks and no in-progress requests, it will // call cleanup(). (0, _scheduler.pingPrefetchScheduler)(); } function cleanup() { if (lruSize <= maxLruSize) { return; } // Evict entries until we're at 90% capacity. We can assume this won't // infinite loop because even if `maxLruSize` were 0, eventually // `deleteFromLru` sets `head` to `null` when we run out entries. const ninetyPercentMax = maxLruSize * 0.9; while(lruSize > ninetyPercentMax && head !== null){ const tail = head.prev; // In practice, this is never null, but that isn't encoded in the type if (tail !== null) { // Delete the entry from the map. In turn, this will remove it from // the LRU. (0, _cachemap.deleteMapEntry)(tail); } } } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/cache-map.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { Fallback: null, createCacheMap: null, deleteFromCacheMap: null, deleteMapEntry: null, getFromCacheMap: null, isValueExpired: null, setInCacheMap: null, setSizeInCacheMap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { Fallback: function() { return Fallback; }, createCacheMap: function() { return createCacheMap; }, deleteFromCacheMap: function() { return deleteFromCacheMap; }, deleteMapEntry: function() { return deleteMapEntry; }, getFromCacheMap: function() { return getFromCacheMap; }, isValueExpired: function() { return isValueExpired; }, setInCacheMap: function() { return setInCacheMap; }, setSizeInCacheMap: function() { return setSizeInCacheMap; } }); const _lru = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/lru.js [app-ssr] (ecmascript)"); const Fallback = {}; // This is a special internal key that is used for "revalidation" entries. It's // an implementation detail that shouldn't leak outside of this module. const Revalidation = {}; function createCacheMap() { const cacheMap = { parent: null, key: null, value: null, map: null, // LRU-related fields prev: null, next: null, size: 0 }; return cacheMap; } function getOrInitialize(cacheMap, keys, isRevalidation) { // Go through each level of keys until we find the entry that matches, or // create a new entry if one doesn't exist. // // This function will only return entries that match the keypath _exactly_. // Unlike getWithFallback, it will not access fallback entries unless it's // explicitly part of the keypath. let entry = cacheMap; let remainingKeys = keys; let key = null; while(true){ const previousKey = key; if (remainingKeys !== null) { key = remainingKeys.value; remainingKeys = remainingKeys.parent; } else if (isRevalidation && previousKey !== Revalidation) { // During a revalidation, we append an internal "Revalidation" key to // the end of the keypath. The "normal" entry is its parent. // However, if the parent entry is currently empty, we don't need to store // this as a revalidation entry. Just insert the revalidation into the // normal slot. if (entry.value === null) { return entry; } // Otheriwse, create a child entry. key = Revalidation; } else { break; } let map = entry.map; if (map !== null) { const existingEntry = map.get(key); if (existingEntry !== undefined) { // Found a match. Keep going. entry = existingEntry; continue; } } else { map = new Map(); entry.map = map; } // No entry exists yet at this level. Create a new one. const newEntry = { parent: entry, key, value: null, map: null, // LRU-related fields prev: null, next: null, size: 0 }; map.set(key, newEntry); entry = newEntry; } return entry; } function getFromCacheMap(now, currentCacheVersion, rootEntry, keys, isRevalidation) { const entry = getEntryWithFallbackImpl(now, currentCacheVersion, rootEntry, keys, isRevalidation, 0); if (entry === null || entry.value === null) { return null; } // This is an LRU access. Move the entry to the front of the list. (0, _lru.lruPut)(entry); return entry.value; } function isValueExpired(now, currentCacheVersion, value) { return value.staleAt <= now || value.version < currentCacheVersion; } function lazilyEvictIfNeeded(now, currentCacheVersion, entry) { // We have a matching entry, but before we can return it, we need to check if // it's still fresh. Otherwise it should be treated the same as a cache miss. if (entry.value === null) { // This entry has no value, so there's nothing to evict. return entry; } const value = entry.value; if (isValueExpired(now, currentCacheVersion, value)) { // The value expired. Lazily evict it from the cache, and return null. This // is conceptually the same as a cache miss. deleteMapEntry(entry); return null; } // The matched entry has not expired. Return it. return entry; } function getEntryWithFallbackImpl(now, currentCacheVersion, entry, keys, isRevalidation, previousKey) { // This is similar to getExactEntry, but if an exact match is not found for // a key, it will return the fallback entry instead. This is recursive at // every level, e.g. an entry with keypath [a, Fallback, c, Fallback] is // valid match for [a, b, c, d]. // // It will return the most specific match available. let key; let remainingKeys; if (keys !== null) { key = keys.value; remainingKeys = keys.parent; } else if (isRevalidation && previousKey !== Revalidation) { // During a revalidation, we append an internal "Revalidation" key to // the end of the keypath. key = Revalidation; remainingKeys = null; } else { // There are no more keys. This is the terminal entry. // TODO: When performing a lookup during a navigation, as opposed to a // prefetch, we may want to skip entries that are Pending if there's also // a Fulfilled fallback entry. Tricky to say, though, since if it's // already pending, it's likely to stream in soon. Maybe we could do this // just on slow connections and offline mode. return lazilyEvictIfNeeded(now, currentCacheVersion, entry); } const map = entry.map; if (map !== null) { const existingEntry = map.get(key); if (existingEntry !== undefined) { // Found an exact match for this key. Keep searching. const result = getEntryWithFallbackImpl(now, currentCacheVersion, existingEntry, remainingKeys, isRevalidation, key); if (result !== null) { return result; } } // No match found for this key. Check if there's a fallback. const fallbackEntry = map.get(Fallback); if (fallbackEntry !== undefined) { // Found a fallback for this key. Keep searching. return getEntryWithFallbackImpl(now, currentCacheVersion, fallbackEntry, remainingKeys, isRevalidation, key); } } return null; } function setInCacheMap(cacheMap, keys, value, isRevalidation) { // Add a value to the map at the given keypath. If the value is already // part of the map, it's removed from its previous keypath. (NOTE: This is // unlike a regular JS map, but the behavior is intentional.) const entry = getOrInitialize(cacheMap, keys, isRevalidation); setMapEntryValue(entry, value); // This is an LRU access. Move the entry to the front of the list. (0, _lru.lruPut)(entry); (0, _lru.updateLruSize)(entry, value.size); } function setMapEntryValue(entry, value) { if (entry.value !== null) { // There's already a value at the given keypath. Disconnect the old value // from the map. We're not calling `deleteMapEntry` here because the // entry itself is still in the map. We just want to overwrite its value. dropRef(entry.value); entry.value = null; } // This value may already be in the map at a different keypath. // Grab a reference before we overwrite it. const oldEntry = value.ref; entry.value = value; value.ref = entry; (0, _lru.updateLruSize)(entry, value.size); if (oldEntry !== null && oldEntry !== entry && oldEntry.value === value) { // This value is already in the map at a different keypath in the map. // Values only exist at a single keypath at a time. Remove it from the // previous keypath. // // Note that only the internal map entry is garbage collected; we don't // call `dropRef` here because it's still in the map, just // at a new keypath (the one we just set, above). deleteMapEntry(oldEntry); } } function deleteFromCacheMap(value) { const entry = value.ref; if (entry === null) { // This value is not a member of any map. return; } dropRef(value); deleteMapEntry(entry); } function dropRef(value) { // Drop the value from the map by setting its `ref` backpointer to // null. This is a separate operation from `deleteMapEntry` because when // re-keying a value we need to be able to delete the old, internal map // entry without garbage collecting the value itself. value.ref = null; } function deleteMapEntry(entry) { // Delete the entry from the cache. entry.value = null; (0, _lru.deleteFromLru)(entry); // Check if we can garbage collect the entry. const map = entry.map; if (map === null) { // Since this entry has no value, and also no child entries, we can // garbage collect it. Remove it from its parent, and keep garbage // collecting the parents until we reach a non-empty entry. let parent = entry.parent; let key = entry.key; while(parent !== null){ const parentMap = parent.map; if (parentMap !== null) { parentMap.delete(key); if (parentMap.size === 0) { // We just removed the last entry in the parent map. parent.map = null; if (parent.value === null) { // The parent node has no child entries, nor does it have a value // on itself. It can be garbage collected. Keep going. key = parent.key; parent = parent.parent; continue; } } } break; } } else { // Check if there's a revalidating entry. If so, promote it to a // "normal" entry, since the normal one was just deleted. const revalidatingEntry = map.get(Revalidation); if (revalidatingEntry !== undefined && revalidatingEntry.value !== null) { setMapEntryValue(entry, revalidatingEntry.value); } } } function setSizeInCacheMap(value, size) { const entry = value.ref; if (entry === null) { // This value is not a member of any map. return; } // Except during initialization (when the size is set to 0), this is the only // place the `size` field should be updated, to ensure it's in sync with the // the LRU. value.size = size; (0, _lru.updateLruSize)(entry, size); } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/vary-path.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { appendLayoutVaryPath: null, clonePageVaryPathWithNewSearchParams: null, finalizeLayoutVaryPath: null, finalizeMetadataVaryPath: null, finalizePageVaryPath: null, getFulfilledRouteVaryPath: null, getFulfilledSegmentVaryPath: null, getPartialLayoutVaryPath: null, getPartialPageVaryPath: null, getRenderedSearchFromVaryPath: null, getRouteVaryPath: null, getSegmentVaryPathForRequest: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { appendLayoutVaryPath: function() { return appendLayoutVaryPath; }, clonePageVaryPathWithNewSearchParams: function() { return clonePageVaryPathWithNewSearchParams; }, finalizeLayoutVaryPath: function() { return finalizeLayoutVaryPath; }, finalizeMetadataVaryPath: function() { return finalizeMetadataVaryPath; }, finalizePageVaryPath: function() { return finalizePageVaryPath; }, getFulfilledRouteVaryPath: function() { return getFulfilledRouteVaryPath; }, getFulfilledSegmentVaryPath: function() { return getFulfilledSegmentVaryPath; }, getPartialLayoutVaryPath: function() { return getPartialLayoutVaryPath; }, getPartialPageVaryPath: function() { return getPartialPageVaryPath; }, getRenderedSearchFromVaryPath: function() { return getRenderedSearchFromVaryPath; }, getRouteVaryPath: function() { return getRouteVaryPath; }, getSegmentVaryPathForRequest: function() { return getSegmentVaryPathForRequest; } }); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _cachemap = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-map.js [app-ssr] (ecmascript)"); const _segmentvalueencoding = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.js [app-ssr] (ecmascript)"); function getRouteVaryPath(pathname, search, nextUrl) { // requestKey -> searchParams -> nextUrl const varyPath = { id: null, value: pathname, parent: { id: '?', value: search, parent: { id: null, value: nextUrl, parent: null } } }; return varyPath; } function getFulfilledRouteVaryPath(pathname, search, nextUrl, couldBeIntercepted) { // This is called when a route's data is fulfilled. The cache entry will be // re-keyed based on which inputs the response varies by. // requestKey -> searchParams -> nextUrl const varyPath = { id: null, value: pathname, parent: { id: '?', value: search, parent: { id: null, value: couldBeIntercepted ? nextUrl : _cachemap.Fallback, parent: null } } }; return varyPath; } function appendLayoutVaryPath(parentPath, cacheKey, paramName) { const varyPathPart = { id: paramName, value: cacheKey, parent: parentPath }; return varyPathPart; } function finalizeLayoutVaryPath(requestKey, varyPath) { const layoutVaryPath = { id: null, value: requestKey, parent: varyPath }; return layoutVaryPath; } function getPartialLayoutVaryPath(finalizedVaryPath) { // This is the inverse of finalizeLayoutVaryPath. return finalizedVaryPath.parent; } function finalizePageVaryPath(requestKey, renderedSearch, varyPath) { // Unlike layouts, a page segment's vary path also includes the search string. // requestKey -> searchParams -> pathParams const pageVaryPath = { id: null, value: requestKey, parent: { id: '?', value: renderedSearch, parent: varyPath } }; return pageVaryPath; } function getPartialPageVaryPath(finalizedVaryPath) { // This is the inverse of finalizePageVaryPath. return finalizedVaryPath.parent.parent; } function finalizeMetadataVaryPath(pageRequestKey, renderedSearch, varyPath) { // The metadata "segment" is not a real segment because it doesn't exist in // the normal structure of the route tree, but in terms of caching, it // behaves like a page segment because it varies by all the same params as // a page. // // To keep the protocol for querying the server simple, the request key for // the metadata does not include any path information. It's unnecessary from // the server's perspective, because unlike page segments, there's only one // metadata response per URL, i.e. there's no need to distinguish multiple // parallel pages. // // However, this means the metadata request key is insufficient for // caching the the metadata in the client cache, because on the client we // use the request key to distinguish the metadata entry from all other // page's metadata entries. // // So instead we create a simulated request key based on the page segment. // Conceptually this is equivalent to the request key the server would have // assigned the metadata segment if it treated it as part of the actual // route structure. // If there are multiple parallel pages, we use whichever is the first one. // This is fine because the only difference between request keys for // different parallel pages are things like route groups and parallel // route slots. As long as it's always the same one, it doesn't matter. const pageVaryPath = { id: null, // Append the actual metadata request key to the page request key. Note // that we're not using a separate vary path part; it's unnecessary because // these are not conceptually separate inputs. value: pageRequestKey + _segmentvalueencoding.HEAD_REQUEST_KEY, parent: { id: '?', value: renderedSearch, parent: varyPath } }; return pageVaryPath; } function getSegmentVaryPathForRequest(fetchStrategy, tree) { // This is used for storing pending requests in the cache. We want to choose // the most generic vary path based on the strategy used to fetch it, i.e. // static/PPR versus runtime prefetching, so that it can be reused as much // as possible. // // We may be able to re-key the response to something even more generic once // we receive it — for example, if the server tells us that the response // doesn't vary on a particular param — but even before we send the request, // we know some params are reusable based on the fetch strategy alone. For // example, a static prefetch will never vary on search params. // // The original vary path with all the params filled in is stored on the // route tree object. We will clone this one to create a new vary path // where certain params are replaced with Fallback. // // This result of this function is not stored anywhere. It's only used to // access the cache a single time. // // TODO: Rather than create a new list object just to access the cache, the // plan is to add the concept of a "vary mask". This will represent all the // params that can be treated as Fallback. (Or perhaps the inverse.) const originalVaryPath = tree.varyPath; // Only page segments (and the special "metadata" segment, which is treated // like a page segment for the purposes of caching) may contain search // params. There's no reason to include them in the vary path otherwise. if (tree.isPage) { // Only a runtime prefetch will include search params in the vary path. // Static prefetches never include search params, so they can be reused // across all possible search param values. const doesVaryOnSearchParams = fetchStrategy === _types.FetchStrategy.Full || fetchStrategy === _types.FetchStrategy.PPRRuntime; if (!doesVaryOnSearchParams) { // The response from the the server will not vary on search params. Clone // the end of the original vary path to replace the search params // with Fallback. // // requestKey -> searchParams -> pathParams // ^ This part gets replaced with Fallback const searchParamsVaryPath = originalVaryPath.parent; const pathParamsVaryPath = searchParamsVaryPath.parent; const patchedVaryPath = { id: null, value: originalVaryPath.value, parent: { id: '?', value: _cachemap.Fallback, parent: pathParamsVaryPath } }; return patchedVaryPath; } } // The request does vary on search params. We don't need to modify anything. return originalVaryPath; } function clonePageVaryPathWithNewSearchParams(originalVaryPath, newSearch) { // requestKey -> searchParams -> pathParams // ^ This part gets replaced with newSearch const searchParamsVaryPath = originalVaryPath.parent; const clonedVaryPath = { id: null, value: originalVaryPath.value, parent: { id: '?', value: newSearch, parent: searchParamsVaryPath.parent } }; return clonedVaryPath; } function getRenderedSearchFromVaryPath(varyPath) { const searchParams = varyPath.parent.value; return typeof searchParams === 'string' ? searchParams : null; } function getFulfilledSegmentVaryPath(original, varyParams) { // Re-keys a segment's vary path based on which params the segment actually // depends on. Params that are NOT in the varyParams set are replaced with // Fallback, allowing the cache entry to be reused across different values of // those params. // This is called when a segment is fulfilled with data from the server. The // varyParams set comes from the server and indicates which params were // accessed during rendering. const clone = { id: original.id, // If the id is null, this node is not a param (e.g., it's a request key). // If the id is in the varyParams set, keep the original value. // Otherwise, replace with Fallback to make it reusable. value: original.id === null || varyParams.has(original.id) ? original.value : _cachemap.Fallback, parent: original.parent === null ? null : getFulfilledSegmentVaryPath(original.parent, varyParams) }; return clone; } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/optimistic-routes.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Optimistic Routing (Known Routes) * * This module enables the client to predict route structure for URLs that * haven't been prefetched yet, based on previously learned route patterns. * When successful, this allows skipping the route tree prefetch request * entirely. * * The core idea is that many URLs map to the same route structure. For example, * /blog/post-1 and /blog/post-2 both resolve to /blog/[slug]. Once we've * prefetched one, we can predict the structure of the other. * * However, we can't always make this prediction. Static siblings (like * /blog/featured alongside /blog/[slug]) have different route structures. * When we learn a dynamic route, we also learn its static siblings so we * know when NOT to apply the prediction. * * Main entry points: * * 1. discoverKnownRoute: Called after receiving a route tree from the server. * Traverses the route tree, compares URL parts to segments, and populates * the known route tree if they match. Routes are always inserted into the * cache. * * 2. matchKnownRoute: Called when looking up a route with no cache entry. * Matches the candidate URL against learned patterns. Returns a synthetic * cache entry if successful, or null to fall back to server resolution. * * Rewrite detection happens during traversal: if a URL path part doesn't match * the corresponding route segment, we stop populating the known route tree * (since the mapping is incorrect) but still insert the route into the cache. * * The known route tree is append-only with no eviction. Route patterns are * derived from the filesystem, so they don't become stale within a session. * Cache invalidation on deploy clears everything anyway. * * Current limitations (deopt to server resolution): * - Rewrites: Detected during traversal (tree not populated, but route cached) * - Intercepted routes: The route tree varies by referrer (Next-Url header), * so we can't predict the correct structure from the URL alone. Patterns are * still stored during discovery (so the trie stays populated for non- * intercepted siblings), but matching bails out when the pattern is marked * as interceptable. */ Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { discoverKnownRoute: null, matchKnownRoute: null, resetKnownRoutes: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { discoverKnownRoute: function() { return discoverKnownRoute; }, matchKnownRoute: function() { return matchKnownRoute; }, resetKnownRoutes: function() { return resetKnownRoutes; } }); const _cache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)"); const _routeparams = __turbopack_context__.r("[project]/node_modules/next/dist/client/route-params.js [app-ssr] (ecmascript)"); const _varypath = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/vary-path.js [app-ssr] (ecmascript)"); function createEmptyPart() { return { staticChildren: null, dynamicChild: null, dynamicChildParamName: null, dynamicChildParamType: null, pattern: null }; } // The root of the known route tree. let knownRouteTreeRoot = createEmptyPart(); function discoverKnownRoute(now, pathname, nextUrl, pendingEntry, routeTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching, hasDynamicRewrite) { const tree = routeTree; const pathnameParts = pathname.split('/').filter((p)=>p !== ''); const firstPart = pathnameParts.length > 0 ? pathnameParts[0] : null; const remainingParts = pathnameParts.length > 0 ? pathnameParts.slice(1) : []; if (pendingEntry !== null) { // Fulfill the pending entry first const fulfilledEntry = (0, _cache.fulfillRouteCacheEntry)(now, pendingEntry, tree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching); if (hasDynamicRewrite) { fulfilledEntry.hasDynamicRewrite = true; } // Populate the known route tree (handles rewrite detection internally). // The entry is already in the cache; this just stores it as a pattern // if the URL matches the route structure. discoverKnownRoutePart(knownRouteTreeRoot, tree, firstPart, remainingParts, fulfilledEntry, now, pathname, nextUrl, tree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching, hasDynamicRewrite); return fulfilledEntry; } // No pending entry - discoverKnownRoutePart will create one and insert it // into the cache, or return an existing pattern if one exists. return discoverKnownRoutePart(knownRouteTreeRoot, tree, firstPart, remainingParts, null, now, pathname, nextUrl, tree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching, hasDynamicRewrite); } /** * Gets or creates the dynamic child node for a KnownRoutePart. * A node can have at most one dynamic child (you can't have both [slug] and * [id] at the same route level), so we either return existing or create new. */ function discoverDynamicChild(part, paramName, paramType) { if (part.dynamicChild !== null) { return part.dynamicChild; } const newChild = createEmptyPart(); // Type assertion needed because we're converting from "without" to "with" // dynamic child variant. const mutablePart = part; mutablePart.dynamicChild = newChild; mutablePart.dynamicChildParamName = paramName; mutablePart.dynamicChildParamType = paramType; return newChild; } /** * Recursive workhorse for discoverKnownRoute. * * Walks the route tree and URL parts in parallel, building out the known * route tree as it goes. At each step: * 1. Determines if the current segment appears in the URL (dynamic/static) * 2. Validates URL matches route structure (detects rewrites) * 3. Creates/updates the corresponding KnownRoutePart node * 4. Records static siblings for future matching * 5. Recurses into child slots (parallel routes) * * If a URL/route mismatch is detected (rewrite), we stop building the known * route tree but still cache the route entry for direct lookup. */ function discoverKnownRoutePart(parentKnownRoutePart, routeTree, urlPart, remainingParts, existingEntry, now, pathname, nextUrl, fullTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching, hasDynamicRewrite) { const segment = routeTree.segment; let segmentAppearsInURL; let paramName = null; let paramType = null; let staticSiblings = null; if (typeof segment === 'string') { segmentAppearsInURL = (0, _routeparams.doesStaticSegmentAppearInURL)(segment); } else { // Dynamic segment tuple: [paramName, paramCacheKey, paramType, staticSiblings] paramName = segment[0]; paramType = segment[2]; staticSiblings = segment[3]; segmentAppearsInURL = true; } let knownRoutePart = parentKnownRoutePart; let nextUrlPart = urlPart; let nextRemainingParts = remainingParts; if (segmentAppearsInURL) { // Check for mismatch: if this is a static segment, the URL part must match if (paramName === null && urlPart !== segment) { // URL doesn't match route structure (likely a rewrite). // Don't populate the known route tree, just write the route into the // cache and return immediately. if (existingEntry !== null) { return existingEntry; } return (0, _cache.writeRouteIntoCache)(now, pathname, nextUrl, fullTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching); } // URL matches route structure. Build the known route tree. if (paramName !== null && paramType !== null) { // Dynamic segment knownRoutePart = discoverDynamicChild(parentKnownRoutePart, paramName, paramType); // Record static siblings as placeholder parts. // IMPORTANT: We use the null vs Map distinction to track whether // siblings are known at this level: // - staticChildren: null = siblings unknown (can't safely match dynamic) // - staticChildren: Map = siblings known (even if empty) // This matters in dev mode where webpack may not know all siblings yet. if (staticSiblings !== null) { // Siblings are known - ensure we have a Map (even if empty) if (parentKnownRoutePart.staticChildren === null) { parentKnownRoutePart.staticChildren = new Map(); } for (const sibling of staticSiblings){ if (!parentKnownRoutePart.staticChildren.has(sibling)) { parentKnownRoutePart.staticChildren.set(sibling, createEmptyPart()); } } } } else { // Static segment if (parentKnownRoutePart.staticChildren === null) { parentKnownRoutePart.staticChildren = new Map(); } let existingChild = parentKnownRoutePart.staticChildren.get(urlPart); if (existingChild === undefined) { existingChild = createEmptyPart(); parentKnownRoutePart.staticChildren.set(urlPart, existingChild); } knownRoutePart = existingChild; } // Advance to next URL part nextUrlPart = remainingParts.length > 0 ? remainingParts[0] : null; nextRemainingParts = remainingParts.length > 0 ? remainingParts.slice(1) : []; } // else: Transparent segment (route group, __PAGE__, etc.) // Stay at the same known route part, don't advance URL parts // Recurse into child routes. A route tree can have multiple parallel routes // (e.g., @modal alongside children). Each parallel route is a separate // branch, but they all share the same URL - we just need to traverse all // branches to build out the known route tree. const slots = routeTree.slots; let resultFromChildren = null; if (slots !== null) { for(const parallelRouteKey in slots){ const childRouteTree = slots[parallelRouteKey]; // Skip branches with refreshState set - these were reused from a // different route (e.g., a "default" parallel slot) and don't represent // the actual route structure for this URL. if (childRouteTree.refreshState !== null) { continue; } const result = discoverKnownRoutePart(knownRoutePart, childRouteTree, nextUrlPart, nextRemainingParts, existingEntry, now, pathname, nextUrl, fullTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching, hasDynamicRewrite); // All parallel route branches share the same URL, so they should all // reach compatible leaf nodes. We capture any result. resultFromChildren = result; } if (resultFromChildren !== null) { return resultFromChildren; } // Defensive fallback: no children returned a result. This shouldn't happen // for valid route trees, but handle it gracefully. if (existingEntry !== null) { return existingEntry; } return (0, _cache.writeRouteIntoCache)(now, pathname, nextUrl, fullTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching); } // Reached a page node. Create/get the route cache entry and store as a // pattern. First, check if there's already a pattern for this route. if (knownRoutePart.pattern !== null) { // If this route has a dynamic rewrite, mark the existing pattern. if (hasDynamicRewrite) { knownRoutePart.pattern.hasDynamicRewrite = true; } return knownRoutePart.pattern; } // Get or create the entry let entry; if (existingEntry !== null) { // Already have a fulfilled entry, use it directly. It's already in the // route cache map. entry = existingEntry; } else { // Create the entry and insert it into the route cache map. entry = (0, _cache.writeRouteIntoCache)(now, pathname, nextUrl, fullTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching); } if (hasDynamicRewrite) { entry.hasDynamicRewrite = true; } // Store as pattern knownRoutePart.pattern = entry; return entry; } function matchKnownRoute(pathname, search) { const pathnameParts = pathname.split('/').filter((p)=>p !== ''); const resolvedParams = new Map(); const match = matchKnownRoutePart(knownRouteTreeRoot, pathnameParts, 0, resolvedParams); if (match === null) { return null; } const matchedPart = match.part; const pattern = match.pattern; // If the pattern could be intercepted, we can't safely use it for prediction. // Interception routes resolve to different route trees depending on the // referrer (the Next-Url header), which means the same URL can map to // different page components depending on where the navigation originated. // Since the known route tree only stores a single pattern per URL shape, we // can't distinguish between the intercepted and non-intercepted cases, so we // bail out to server resolution. // // TODO: We could store interception behavior in the known route tree itself // (e.g., which segments use interception markers and what they resolve to). // With enough information embedded in the trie, we could match interception // routes entirely on the client without a server round-trip. if (pattern.couldBeIntercepted) { return null; } // "Reify" the pattern: clone the template tree with concrete param values. // This substitutes resolved params (e.g., slug: "hello") into dynamic // segments and recomputes vary paths for correct segment cache keying. const acc = { metadataVaryPath: null }; const reifiedTree = reifyRouteTree(pattern.tree, resolvedParams, search, null, acc); // The metadata tree is a flat page node without the intermediate layout // structure. Clone it with the updated metadata vary path collected during // the main tree traversal. const metadataVaryPath = acc.metadataVaryPath; if (metadataVaryPath === null) { // This shouldn't be reachable for a valid route tree. return null; } const reifiedMetadata = (0, _cache.createMetadataRouteTree)(metadataVaryPath); // Create a synthetic (predicted) entry and store it as the new pattern. // // Why replace the pattern? We intentionally update the pattern with this // synthetic entry so that if our prediction was wrong (server returns a // different pathname due to dynamic rewrite), the entry gets marked with // hasDynamicRewrite. Future predictions for this route will see the flag // and bail out to server resolution instead of making the same mistake. const syntheticEntry = { canonicalUrl: pathname + search, status: _cache.EntryStatus.Fulfilled, blockedTasks: null, tree: reifiedTree, metadata: reifiedMetadata, couldBeIntercepted: pattern.couldBeIntercepted, supportsPerSegmentPrefetching: pattern.supportsPerSegmentPrefetching, hasDynamicRewrite: false, renderedSearch: search, ref: null, size: pattern.size, staleAt: pattern.staleAt, version: pattern.version }; matchedPart.pattern = syntheticEntry; return syntheticEntry; } /** * Recursively matches a URL against the known route tree. * * Matching priority (most specific first): * 1. Static children - exact path segment match * 2. Dynamic child - [param], [...param], [[...param]] * 3. Direct pattern - when no more URL parts remain * * Collects resolved param values in resolvedParams as it traverses. * Returns null if no match found (caller should fall back to server). */ function matchKnownRoutePart(part, pathnameParts, partIndex, resolvedParams) { const urlPart = partIndex < pathnameParts.length ? pathnameParts[partIndex] : null; // If staticChildren is null, we don't know what static routes exist at this // level. This happens in webpack dev mode where routes are compiled // on-demand. We can't safely match a dynamicChild because the URL part might // be a static sibling we haven't discovered yet. Example: We know // /blog/[slug] exists, but haven't compiled /blog/featured. A request for // /blog/featured would incorrectly match /blog/[slug]. if (part.staticChildren === null) { // The only safe match is a direct pattern when no URL parts remain. if (urlPart === null) { const pattern = part.pattern; if (pattern !== null && !pattern.hasDynamicRewrite) { return { part, pattern }; } } return null; } // Static children take priority over dynamic. This ensures /blog/featured // matches its own route rather than /blog/[slug]. if (urlPart !== null) { const staticChild = part.staticChildren.get(urlPart); if (staticChild !== undefined) { // Check if this is an "unknown" placeholder part. These are created when // we learn about static siblings (from the route tree's staticSiblings // field) but haven't prefetched them yet. We know the path exists but // don't know its structure, so we can't predict it. if (staticChild.pattern === null && staticChild.dynamicChild === null && staticChild.staticChildren === null) { // Bail out - server must resolve this route. return null; } const match = matchKnownRoutePart(staticChild, pathnameParts, partIndex + 1, resolvedParams); if (match !== null) { return match; } // Static child is a real node (not a placeholder) but its subtree // didn't match the remaining URL parts. This means the route exists // in the static subtree but hasn't been fully discovered yet. Do not // fall through to try the dynamic child — the static match is // authoritative. Bail out to server resolution. return null; } } // Try dynamic child if (part.dynamicChild !== null) { const dynamicPart = part.dynamicChild; const paramName = part.dynamicChildParamName; const paramType = part.dynamicChildParamType; const dynamicPattern = dynamicPart.pattern; switch(paramType){ case 'c': // Required catch-all [...param]: consumes 1+ URL parts if (dynamicPattern !== null && !dynamicPattern.hasDynamicRewrite && urlPart !== null) { resolvedParams.set(paramName, pathnameParts.slice(partIndex)); return { part: dynamicPart, pattern: dynamicPattern }; } break; case 'oc': // Optional catch-all [[...param]]: consumes 0+ URL parts if (dynamicPattern !== null && !dynamicPattern.hasDynamicRewrite) { if (urlPart !== null) { resolvedParams.set(paramName, pathnameParts.slice(partIndex)); return { part: dynamicPart, pattern: dynamicPattern }; } // urlPart is null - can match with zero parts, but a direct pattern // (e.g., page.tsx alongside [[...param]]) takes precedence. if (part.pattern === null || part.pattern.hasDynamicRewrite) { resolvedParams.set(paramName, []); return { part: dynamicPart, pattern: dynamicPattern }; } } break; case 'd': // Regular dynamic [param]: consumes exactly 1 URL part. // Unlike catch-all which terminates here, regular dynamic must // continue recursing to find the leaf pattern. if (urlPart !== null) { resolvedParams.set(paramName, urlPart); return matchKnownRoutePart(dynamicPart, pathnameParts, partIndex + 1, resolvedParams); } break; // Intercepted routes use relative path markers like (.), (..), (...) // Their behavior depends on navigation context (soft vs hard nav), // so we can't predict them client-side. Defer to server. case 'ci(..)(..)': case 'ci(.)': case 'ci(..)': case 'ci(...)': case 'di(..)(..)': case 'di(.)': case 'di(..)': case 'di(...)': return null; default: paramType; } } // No children matched. If we've consumed all URL parts, check for a direct // pattern at this node (the route terminates here). if (urlPart === null) { const pattern = part.pattern; if (pattern !== null && !pattern.hasDynamicRewrite) { return { part, pattern }; } } return null; } /** * "Reify" means to make concrete - we take an abstract pattern (the template * route tree) and produce a concrete instance with actual param values. * * This function clones a RouteTree, substituting dynamic segment values from * resolvedParams and computing new vary paths. The vary path encodes param * values so segment cache entries can be correctly keyed. * * Example: Pattern for /blog/[slug] with resolvedParams { slug: "hello" } * produces a tree where segment [slug] has cacheKey "hello". */ function reifyRouteTree(pattern, resolvedParams, search, parentPartialVaryPath, acc) { const originalSegment = pattern.segment; let newSegment = originalSegment; let partialVaryPath; if (typeof originalSegment !== 'string') { // Dynamic segment: compute new cache key and append to partial vary path const paramName = originalSegment[0]; const paramType = originalSegment[2]; const staticSiblings = originalSegment[3]; const newValue = resolvedParams.get(paramName); if (newValue !== undefined) { const newCacheKey = Array.isArray(newValue) ? newValue.join('/') : newValue; newSegment = [ paramName, newCacheKey, paramType, staticSiblings ]; partialVaryPath = (0, _varypath.appendLayoutVaryPath)(parentPartialVaryPath, newCacheKey, paramName); } else { // Param not found in resolvedParams - keep original and inherit partial // TODO: This should never happen. Bail out with null. partialVaryPath = parentPartialVaryPath; } } else { // Static segment: inherit partial vary path from parent partialVaryPath = parentPartialVaryPath; } // Recurse into children with the (possibly updated) partial vary path let newSlots = null; if (pattern.slots !== null) { newSlots = {}; for(const key in pattern.slots){ newSlots[key] = reifyRouteTree(pattern.slots[key], resolvedParams, search, partialVaryPath, acc); } } if (pattern.isPage) { // Page segment: finalize with search params const newVaryPath = (0, _varypath.finalizePageVaryPath)(pattern.requestKey, search, partialVaryPath); // Collect metadata vary path (first page wins, same as original algorithm) if (acc.metadataVaryPath === null) { acc.metadataVaryPath = (0, _varypath.finalizeMetadataVaryPath)(pattern.requestKey, search, partialVaryPath); } return { requestKey: pattern.requestKey, segment: newSegment, refreshState: pattern.refreshState, slots: newSlots, prefetchHints: pattern.prefetchHints, isPage: true, varyPath: newVaryPath }; } else { // Layout segment: finalize without search params const newVaryPath = (0, _varypath.finalizeLayoutVaryPath)(pattern.requestKey, partialVaryPath); return { requestKey: pattern.requestKey, segment: newSegment, refreshState: pattern.refreshState, slots: newSlots, prefetchHints: pattern.prefetchHints, isPage: false, varyPath: newVaryPath }; } } function resetKnownRoutes() { knownRouteTreeRoot = createEmptyPart(); } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/navigation-testing-lock.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * Navigation lock for the Instant Navigation Testing API. * * Manages the in-memory lock (a promise) that gates dynamic data writes * during instant navigation captures, and owns all cookie state * transitions (pending → captured-MPA, pending → captured-SPA). * * External actors (Playwright, devtools) set [0] to start a lock scope * and delete the cookie to end one. Next.js writes captured values. * The CookieStore handler distinguishes them by value: pending = external, * captured = self-write (ignored). */ Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { isNavigationLocked: null, startListeningForInstantNavigationCookie: null, transitionToCapturedSPA: null, updateCapturedSPAToTree: null, waitForNavigationLockIfActive: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { isNavigationLocked: function() { return isNavigationLocked; }, startListeningForInstantNavigationCookie: function() { return startListeningForInstantNavigationCookie; }, transitionToCapturedSPA: function() { return transitionToCapturedSPA; }, updateCapturedSPAToTree: function() { return updateCapturedSPAToTree; }, waitForNavigationLockIfActive: function() { return waitForNavigationLockIfActive; } }); const _approuterheaders = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)"); const _useactionqueue = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/use-action-queue.js [app-ssr] (ecmascript)"); function parseCookieValue(raw) { try { const parsed = JSON.parse(raw); if (Array.isArray(parsed) && parsed.length >= 3) { const rawState = parsed[2]; return rawState === null ? 'mpa' : 'spa'; } } catch {} return 'pending'; } function writeCookieValue(value) { if (typeof cookieStore === 'undefined') { return; } // Read the existing cookie to preserve its attributes (domain, path), // then write back with the new value. This updates the same cookie // entry that the external actor created, regardless of how it was // scoped. cookieStore.get(_approuterheaders.NEXT_INSTANT_TEST_COOKIE).then((existing)=>{ if (existing) { const options = { name: _approuterheaders.NEXT_INSTANT_TEST_COOKIE, value: JSON.stringify(value), path: existing.path ?? '/' }; if (existing.domain) { options.domain = existing.domain; } cookieStore.set(options); } }); } let lockState = null; function acquireLock() { if (lockState !== null) { return; } let resolve; const promise = new Promise((r)=>{ resolve = r; }); lockState = { promise, resolve: resolve }; } function releaseLock() { if (lockState !== null) { lockState.resolve(); lockState = null; } } function startListeningForInstantNavigationCookie() { if ("TURBOPACK compile-time truthy", 1) { // If the server served a static shell, this is an MPA page load // while the lock is held. Transition to captured-MPA and acquire. if (self.__next_instant_test) { if (typeof cookieStore !== 'undefined') { // If the cookie was already cleared during the MPA page // transition, reload to get the full dynamic page. cookieStore.get(_approuterheaders.NEXT_INSTANT_TEST_COOKIE).then((cookie)=>{ if (!cookie) { window.location.reload(); } }); } writeCookieValue([ 1, `c${Math.random()}`, null ]); acquireLock(); } if (typeof cookieStore === 'undefined') { return; } cookieStore.addEventListener('change', (event)=>{ for (const cookie of event.changed){ if (cookie.name === _approuterheaders.NEXT_INSTANT_TEST_COOKIE) { const state = parseCookieValue(cookie.value ?? ''); if (state !== 'pending') { // Captured value — our own transition. Ignore. return; } // Pending value — external actor starting a new lock scope. if (lockState !== null) { releaseLock(); } acquireLock(); return; } } for (const cookie of event.deleted){ if (cookie.name === _approuterheaders.NEXT_INSTANT_TEST_COOKIE) { releaseLock(); (0, _useactionqueue.refreshOnInstantNavigationUnlock)(); return; } } }); } } function transitionToCapturedSPA(fromTree, toTree) { if ("TURBOPACK compile-time truthy", 1) { writeCookieValue([ 1, `c${Math.random()}`, { from: fromTree, to: toTree } ]); } } function updateCapturedSPAToTree(fromTree, toTree) { if ("TURBOPACK compile-time truthy", 1) { writeCookieValue([ 1, `c${Math.random()}`, { from: fromTree, to: toTree } ]); } } function isNavigationLocked() { if ("TURBOPACK compile-time truthy", 1) { return lockState !== null; } //TURBOPACK unreachable ; } async function waitForNavigationLockIfActive() { if ("TURBOPACK compile-time truthy", 1) { if (lockState !== null) { await lockState.promise; } } } 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; } }), "[project]/node_modules/next/dist/client/components/router-reducer/ppr-navigations.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { FreshnessPolicy: null, createInitialCacheNodeForHydration: null, isDeferredRsc: null, spawnDynamicRequests: null, startPPRNavigation: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { FreshnessPolicy: function() { return FreshnessPolicy; }, createInitialCacheNodeForHydration: function() { return createInitialCacheNodeForHydration; }, isDeferredRsc: function() { return isDeferredRsc; }, spawnDynamicRequests: function() { return spawnDynamicRequests; }, startPPRNavigation: function() { return startPPRNavigation; } }); const _approutertypes = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/app-router-types.js [app-ssr] (ecmascript)"); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const _matchsegments = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/match-segments.js [app-ssr] (ecmascript)"); const _createhreffromurl = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/create-href-from-url.js [app-ssr] (ecmascript)"); const _fetchserverresponse = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js [app-ssr] (ecmascript)"); const _useactionqueue = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/use-action-queue.js [app-ssr] (ecmascript)"); const _routerreducertypes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/router-reducer-types.js [app-ssr] (ecmascript)"); const _isnavigatingtonewrootlayout = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/is-navigating-to-new-root-layout.js [app-ssr] (ecmascript)"); const _committedstate = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/reducers/committed-state.js [app-ssr] (ecmascript)"); const _navigation = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation.js [app-ssr] (ecmascript)"); const _cache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)"); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _optimisticroutes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/optimistic-routes.js [app-ssr] (ecmascript)"); const _constants = __turbopack_context__.r("[project]/node_modules/next/dist/lib/constants.js [app-ssr] (ecmascript)"); const _varypath = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/vary-path.js [app-ssr] (ecmascript)"); const _bfcache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/bfcache.js [app-ssr] (ecmascript)"); var FreshnessPolicy = /*#__PURE__*/ function(FreshnessPolicy) { FreshnessPolicy[FreshnessPolicy["Default"] = 0] = "Default"; FreshnessPolicy[FreshnessPolicy["Hydration"] = 1] = "Hydration"; FreshnessPolicy[FreshnessPolicy["HistoryTraversal"] = 2] = "HistoryTraversal"; FreshnessPolicy[FreshnessPolicy["RefreshAll"] = 3] = "RefreshAll"; FreshnessPolicy[FreshnessPolicy["HMRRefresh"] = 4] = "HMRRefresh"; FreshnessPolicy[FreshnessPolicy["Gesture"] = 5] = "Gesture"; return FreshnessPolicy; }({}); const noop = ()=>{}; function createInitialCacheNodeForHydration(navigatedAt, initialTree, seedData, seedHead, seedDynamicStaleAt) { // Create the initial cache node tree, using the data embedded into the // HTML document. const accumulation = { separateRefreshUrls: null, scrollRef: null }; const task = createCacheNodeOnNavigation(navigatedAt, initialTree, null, 1, seedData, seedHead, seedDynamicStaleAt, false, accumulation); return task; } function startPPRNavigation(navigatedAt, oldUrl, oldRenderedSearch, oldCacheNode, oldRouterState, newRouteTree, newMetadataVaryPath, freshness, seedData, seedHead, seedDynamicStaleAt, isSamePageNavigation, accumulation) { const didFindRootLayout = false; const parentNeedsDynamicRequest = false; const parentRefreshState = null; const oldRootRefreshState = { canonicalUrl: (0, _createhreffromurl.createHrefFromUrl)(oldUrl), renderedSearch: oldRenderedSearch }; return updateCacheNodeOnNavigation(navigatedAt, oldUrl, oldCacheNode !== null ? oldCacheNode : undefined, oldRouterState, newRouteTree, newMetadataVaryPath, freshness, didFindRootLayout, seedData, seedHead, seedDynamicStaleAt, isSamePageNavigation, parentNeedsDynamicRequest, oldRootRefreshState, parentRefreshState, accumulation); } function updateCacheNodeOnNavigation(navigatedAt, oldUrl, oldCacheNode, oldRouterState, newRouteTree, newMetadataVaryPath, freshness, didFindRootLayout, seedData, seedHead, seedDynamicStaleAt, isSamePageNavigation, parentNeedsDynamicRequest, oldRootRefreshState, parentRefreshState, accumulation) { // Check if this segment matches the one in the previous route. const oldSegment = oldRouterState[0]; const newSegment = createSegmentFromRouteTree(newRouteTree); if (!(0, _matchsegments.matchSegment)(newSegment, oldSegment)) { // This segment does not match the previous route. We're now entering the // new part of the target route. Switch to the "create" path. if (// highest-level layout in a route tree is referred to as the "root" // layout.) This could mean that we're navigating between two different // root layouts. When this happens, we perform a full-page (MPA-style) // navigation. // // However, the algorithm for deciding where to start rendering a route // (i.e. the one performed in order to reach this function) is stricter // than the one used to detect a change in the root layout. So just // because we're re-rendering a segment outside of the root layout does // not mean we should trigger a full-page navigation. // // Specifically, we handle dynamic parameters differently: two segments // are considered the same even if their parameter values are different. // // Refer to isNavigatingToNewRootLayout for details. // // Note that we only have to perform this extra traversal if we didn't // already discover a root layout in the part of the tree that is // unchanged. We also only need to compare the subtree that is not // shared. In the common case, this branch is skipped completely. !didFindRootLayout && (0, _isnavigatingtonewrootlayout.isNavigatingToNewRootLayout)(oldRouterState, newRouteTree) || // The global Not Found route (app/global-not-found.tsx) is a special // case, because it acts like a root layout, but in the router tree, it // is rendered in the same position as app/layout.tsx. // // Any navigation to the global Not Found route should trigger a // full-page navigation. // // TODO: We should probably model this by changing the key of the root // segment when this happens. Then the root layout check would work // as expected, without a special case. newSegment === _segment.NOT_FOUND_SEGMENT_KEY) { return null; } return createCacheNodeOnNavigation(navigatedAt, newRouteTree, newMetadataVaryPath, freshness, seedData, seedHead, seedDynamicStaleAt, parentNeedsDynamicRequest, accumulation); } const newSlots = newRouteTree.slots; const oldRouterStateChildren = oldRouterState[1]; const seedDataChildren = seedData !== null ? seedData[1] : null; // We're currently traversing the part of the tree that was also part of // the previous route. If we discover a root layout, then we don't need to // trigger an MPA navigation. const childDidFindRootLayout = didFindRootLayout || (newRouteTree.prefetchHints & _approutertypes.PrefetchHint.IsRootLayout) !== 0; let shouldRefreshDynamicData = false; switch(freshness){ case 0: case 2: case 1: case 5: shouldRefreshDynamicData = false; break; case 3: case 4: shouldRefreshDynamicData = true; break; default: freshness; break; } // TODO: We're not consistent about how we do this check. Some places // check if the segment starts with PAGE_SEGMENT_KEY, but most seem to // check if there any any children, which is why I'm doing it here. We // should probably encode an empty children set as `null` though. Either // way, we should update all the checks to be consistent. const isLeafSegment = newSlots === null; // Get the data for this segment. Since it was part of the previous route, // usually we just clone the data from the old CacheNode. However, during a // refresh or a revalidation, there won't be any existing CacheNode. So we // may need to consult the prefetch cache, like we would for a new segment. let newCacheNode; let needsDynamicRequest; if (oldCacheNode !== undefined && !shouldRefreshDynamicData && // During a same-page navigation, we always refetch the page segments !(isLeafSegment && isSamePageNavigation)) { // Reuse the existing CacheNode const dropPrefetchRsc = false; newCacheNode = reuseSharedCacheNode(dropPrefetchRsc, oldCacheNode); needsDynamicRequest = false; } else { // If this is part of a refresh, ignore the existing CacheNode and create a // new one. const seedRsc = seedData !== null ? seedData[0] : null; const result = createCacheNodeForSegment(navigatedAt, newRouteTree, seedRsc, newMetadataVaryPath, seedHead, freshness, seedDynamicStaleAt); newCacheNode = result.cacheNode; needsDynamicRequest = result.needsDynamicRequest; // Carry forward the old node's scrollRef. This preserves scroll // intent when a prior navigation's cache node is replaced by a // refresh before the scroll handler has had a chance to fire — // e.g. when router.push() and router.refresh() are called in the // same startTransition batch. if (oldCacheNode !== undefined) { newCacheNode.scrollRef = oldCacheNode.scrollRef; } } // During a refresh navigation, there's a special case that happens when // entering a "default" slot. The default slot may not be part of the // current route; it may have been reused from an older route. If so, // we need to fetch its data from the old route's URL rather than current // route's URL. Keep track of this as we traverse the tree. const maybeRefreshState = newRouteTree.refreshState; const refreshState = maybeRefreshState !== undefined && maybeRefreshState !== null ? maybeRefreshState : parentRefreshState; // If this segment itself needs to fetch new data from the server, then by // definition it is being refreshed. Track its refresh URL so we know which // URL to request the data from. if (needsDynamicRequest && refreshState !== null) { accumulateRefreshUrl(accumulation, refreshState); } // As we diff the trees, we may sometimes modify (copy-on-write, not mutate) // the Route Tree that was returned by the server — for example, in the case // of default parallel routes, we preserve the currently active segment. To // avoid mutating the original tree, we clone the router state children along // the return path. let patchedRouterStateChildren = {}; let taskChildren = null; // Most navigations require a request to fetch additional data from the // server, either because the data was not already prefetched, or because the // target route contains dynamic data that cannot be prefetched. // // However, if the target route is fully static, and it's already completely // loaded into the segment cache, then we can skip the server request. // // This starts off as `false`, and is set to `true` if any of the child // routes requires a dynamic request. let childNeedsDynamicRequest = false; // As we traverse the children, we'll construct a FlightRouterState that can // be sent to the server to request the dynamic data. If it turns out that // nothing in the subtree is dynamic (i.e. childNeedsDynamicRequest is false // at the end), then this will be discarded. // TODO: We can probably optimize the format of this data structure to only // include paths that are dynamic. Instead of reusing the // FlightRouterState type. let dynamicRequestTreeChildren = {}; let newCacheNodeSlots = null; if (newSlots !== null) { const oldCacheNodeSlots = oldCacheNode !== undefined ? oldCacheNode.slots : null; newCacheNode.slots = newCacheNodeSlots = {}; taskChildren = new Map(); for(let parallelRouteKey in newSlots){ let newRouteTreeChild = newSlots[parallelRouteKey]; const oldRouterStateChild = oldRouterStateChildren[parallelRouteKey]; if (oldRouterStateChild === undefined) { // This should never happen, but if it does, it suggests a malformed // server response. Trigger a full-page navigation. return null; } let seedDataChild = seedDataChildren !== null ? seedDataChildren[parallelRouteKey] : null; const oldSegmentChild = oldRouterStateChild[0]; let newSegmentChild = createSegmentFromRouteTree(newRouteTreeChild); let seedHeadChild = seedHead; if (// was stashed in the history entry as-is. freshness !== 2 && newSegmentChild === _segment.DEFAULT_SEGMENT_KEY && oldSegmentChild !== _segment.DEFAULT_SEGMENT_KEY) { // This is a "default" segment. These are never sent by the server during // a soft navigation; instead, the client reuses whatever segment was // already active in that slot on the previous route. newRouteTreeChild = reuseActiveSegmentInDefaultSlot(newRouteTree, parallelRouteKey, oldRootRefreshState, oldRouterStateChild); newSegmentChild = createSegmentFromRouteTree(newRouteTreeChild); // Since we're switching to a different route tree, these are no // longer valid, because they correspond to the outer tree. seedDataChild = null; seedHeadChild = null; } const oldCacheNodeChild = oldCacheNodeSlots !== null ? oldCacheNodeSlots[parallelRouteKey] : undefined; const taskChild = updateCacheNodeOnNavigation(navigatedAt, oldUrl, oldCacheNodeChild, oldRouterStateChild, newRouteTreeChild, newMetadataVaryPath, freshness, childDidFindRootLayout, seedDataChild ?? null, seedHeadChild, seedDynamicStaleAt, isSamePageNavigation, parentNeedsDynamicRequest || needsDynamicRequest, oldRootRefreshState, refreshState, accumulation); if (taskChild === null) { // One of the child tasks discovered a change to the root layout. // Immediately unwind from this recursive traversal. This will trigger a // full-page navigation. return null; } // Recursively propagate up the child tasks. taskChildren.set(parallelRouteKey, taskChild); newCacheNodeSlots[parallelRouteKey] = taskChild.node; // The child tree's route state may be different from the prefetched // route sent by the server. We need to clone it as we traverse back up // the tree. const taskChildRoute = taskChild.route; patchedRouterStateChildren[parallelRouteKey] = taskChildRoute; const dynamicRequestTreeChild = taskChild.dynamicRequestTree; if (dynamicRequestTreeChild !== null) { // Something in the child tree is dynamic. childNeedsDynamicRequest = true; dynamicRequestTreeChildren[parallelRouteKey] = dynamicRequestTreeChild; } else { dynamicRequestTreeChildren[parallelRouteKey] = taskChildRoute; } } } const newFlightRouterState = [ createSegmentFromRouteTree(newRouteTree), patchedRouterStateChildren, refreshState !== null ? [ refreshState.canonicalUrl, refreshState.renderedSearch ] : null, null, newRouteTree.prefetchHints ]; return { status: needsDynamicRequest ? 0 : 1, route: newFlightRouterState, node: newCacheNode, dynamicRequestTree: createDynamicRequestTree(newFlightRouterState, dynamicRequestTreeChildren, needsDynamicRequest, childNeedsDynamicRequest, parentNeedsDynamicRequest), refreshState, children: taskChildren }; } /** * Assigns a ScrollRef to a new leaf CacheNode so the scroll handler * knows to scroll to it after navigation. All leaves in the same * navigation share the same ScrollRef — the first segment to scroll * consumes it, preventing others from also scrolling. * * This is only called inside `createCacheNodeOnNavigation`, which only * runs when segments diverge from the previous route. So for a refresh * where the route structure stays the same, segments match, the update * path is taken, and this function is never called — no scroll ref is * assigned. A scroll ref is only assigned when the route actually * changed (e.g. a redirect, or a dynamic condition on the server that * produces a different route). * * Skipped during hydration (initial render should not scroll) and * history traversal (scroll restoration is handled separately). */ function accumulateScrollRef(freshness, cacheNode, accumulation) { switch(freshness){ case 0: case 5: case 3: case 4: if (accumulation.scrollRef === null) { accumulation.scrollRef = { current: true }; } cacheNode.scrollRef = accumulation.scrollRef; break; case 1: break; case 2: break; default: freshness; break; } } function createCacheNodeOnNavigation(navigatedAt, newRouteTree, newMetadataVaryPath, freshness, seedData, seedHead, seedDynamicStaleAt, parentNeedsDynamicRequest, accumulation) { // Same traversal as updateCacheNodeNavigation, but simpler. We switch to this // path once we reach the part of the tree that was not in the previous route. // We don't need to diff against the old tree, we just need to create a new // one. We also don't need to worry about any refresh-related logic. // // For the most part, this is a subset of updateCacheNodeOnNavigation, so any // change that happens in this function likely needs to be applied to that // one, too. However there are some places where the behavior intentionally // diverges, which is why we keep them separate. const newSegment = createSegmentFromRouteTree(newRouteTree); const newSlots = newRouteTree.slots; const seedDataChildren = seedData !== null ? seedData[1] : null; const seedRsc = seedData !== null ? seedData[0] : null; const result = createCacheNodeForSegment(navigatedAt, newRouteTree, seedRsc, newMetadataVaryPath, seedHead, freshness, seedDynamicStaleAt); const newCacheNode = result.cacheNode; const needsDynamicRequest = result.needsDynamicRequest; const isLeafSegment = newSlots === null; if (isLeafSegment) { accumulateScrollRef(freshness, newCacheNode, accumulation); } let patchedRouterStateChildren = {}; let taskChildren = null; let childNeedsDynamicRequest = false; let dynamicRequestTreeChildren = {}; let newCacheNodeSlots = null; if (newSlots !== null) { newCacheNode.slots = newCacheNodeSlots = {}; taskChildren = new Map(); for(let parallelRouteKey in newSlots){ const newRouteTreeChild = newSlots[parallelRouteKey]; const seedDataChild = seedDataChildren !== null ? seedDataChildren[parallelRouteKey] : null; const taskChild = createCacheNodeOnNavigation(navigatedAt, newRouteTreeChild, newMetadataVaryPath, freshness, seedDataChild ?? null, seedHead, seedDynamicStaleAt, parentNeedsDynamicRequest || needsDynamicRequest, accumulation); taskChildren.set(parallelRouteKey, taskChild); newCacheNodeSlots[parallelRouteKey] = taskChild.node; const taskChildRoute = taskChild.route; patchedRouterStateChildren[parallelRouteKey] = taskChildRoute; const dynamicRequestTreeChild = taskChild.dynamicRequestTree; if (dynamicRequestTreeChild !== null) { childNeedsDynamicRequest = true; dynamicRequestTreeChildren[parallelRouteKey] = dynamicRequestTreeChild; } else { dynamicRequestTreeChildren[parallelRouteKey] = taskChildRoute; } } } const newFlightRouterState = [ newSegment, patchedRouterStateChildren, null, null, newRouteTree.prefetchHints ]; return { status: needsDynamicRequest ? 0 : 1, route: newFlightRouterState, node: newCacheNode, dynamicRequestTree: createDynamicRequestTree(newFlightRouterState, dynamicRequestTreeChildren, needsDynamicRequest, childNeedsDynamicRequest, parentNeedsDynamicRequest), // This route is not part of the current tree, so there's no reason to // track the refresh URL. refreshState: null, children: taskChildren }; } function createSegmentFromRouteTree(newRouteTree) { if (newRouteTree.isPage) { // In a dynamic server response, the server embeds the search params into // the segment key, but in a static one it's omitted. The client handles // this inconsistency by adding the search params back right at the end. // // TODO: The only thing this is used for is to create a cache key for // ChildSegmentMap. But we already track the `renderedSearch` everywhere as // part of the varyPath. The plan is get rid of ChildSegmentMap and // store the page data in a CacheMap using the varyPath, like we do // for prefetches. Then we can remove it from the segment key. // // As an incremental step, we can grab the search params from the varyPath. const renderedSearch = (0, _varypath.getRenderedSearchFromVaryPath)(newRouteTree.varyPath); if (renderedSearch === null) { return _segment.PAGE_SEGMENT_KEY; } // This is based on equivalent logic in addSearchParamsIfPageSegment, used // on the server. const stringifiedQuery = JSON.stringify(Object.fromEntries(new URLSearchParams(renderedSearch))); return stringifiedQuery !== '{}' ? _segment.PAGE_SEGMENT_KEY + '?' + stringifiedQuery : _segment.PAGE_SEGMENT_KEY; } return newRouteTree.segment; } function patchRouterStateWithNewChildren(baseRouterState, newChildren) { const clone = [ baseRouterState[0], newChildren ]; // Based on equivalent logic in apply-router-state-patch-to-tree, but should // confirm whether we need to copy all of these fields. Not sure the server // ever sends, e.g. the refetch marker. if (2 in baseRouterState) { clone[2] = baseRouterState[2]; } if (3 in baseRouterState) { clone[3] = baseRouterState[3]; } if (4 in baseRouterState) { clone[4] = baseRouterState[4]; } return clone; } function createDynamicRequestTree(newRouterState, dynamicRequestTreeChildren, needsDynamicRequest, childNeedsDynamicRequest, parentNeedsDynamicRequest) { // Create a FlightRouterState that instructs the server how to render the // requested segment. // // Or, if neither this segment nor any of the children require a new data, // then we return `null` to skip the request. let dynamicRequestTree = null; if (needsDynamicRequest) { dynamicRequestTree = patchRouterStateWithNewChildren(newRouterState, dynamicRequestTreeChildren); // The "refetch" marker is set on the top-most segment that requires new // data. We can omit it if a parent was already marked. if (!parentNeedsDynamicRequest) { dynamicRequestTree[3] = 'refetch'; } } else if (childNeedsDynamicRequest) { // This segment does not request new data, but at least one of its // children does. dynamicRequestTree = patchRouterStateWithNewChildren(newRouterState, dynamicRequestTreeChildren); } else { dynamicRequestTree = null; } return dynamicRequestTree; } function accumulateRefreshUrl(accumulation, refreshState) { // This is a refresh navigation, and we're inside a "default" slot that's // not part of the current route; it was reused from an older route. In // order to get fresh data for this reused route, we need to issue a // separate request using the old route's URL. // // Track these extra URLs in the accumulated result. Later, we'll construct // an appropriate request for each unique URL in the final set. The reason // we don't do it immediately here is so we can deduplicate multiple // instances of the same URL into a single request. See // listenForDynamicRequest for more details. const refreshUrl = refreshState.canonicalUrl; const separateRefreshUrls = accumulation.separateRefreshUrls; if (separateRefreshUrls === null) { accumulation.separateRefreshUrls = new Set([ refreshUrl ]); } else { separateRefreshUrls.add(refreshUrl); } } function reuseActiveSegmentInDefaultSlot(parentRouteTree, parallelRouteKey, oldRootRefreshState, oldRouterState) { // This is a "default" segment. These are never sent by the server during a // soft navigation; instead, the client reuses whatever segment was already // active in that slot on the previous route. This means if we later need to // refresh the segment, it will have to be refetched from the previous route's // URL. We store it in the Flight Router State. let reusedUrl; let reusedRenderedSearch; const oldRefreshState = oldRouterState[2]; if (oldRefreshState !== undefined && oldRefreshState !== null) { // This segment was already reused from an even older route. Keep its // existing URL and refresh state. reusedUrl = oldRefreshState[0]; reusedRenderedSearch = oldRefreshState[1]; } else { // Since this route didn't already have a refresh state, it must have been // reachable from the root of the old route. So we use the refresh state // that represents the old route. reusedUrl = oldRootRefreshState.canonicalUrl; reusedRenderedSearch = oldRootRefreshState.renderedSearch; } const acc = { metadataVaryPath: null }; const reusedRouteTree = (0, _cache.convertReusedFlightRouterStateToRouteTree)(parentRouteTree, parallelRouteKey, oldRouterState, reusedRenderedSearch, acc); reusedRouteTree.refreshState = { canonicalUrl: reusedUrl, renderedSearch: reusedRenderedSearch }; return reusedRouteTree; } function reuseSharedCacheNode(dropPrefetchRsc, existingCacheNode) { // Clone the CacheNode that was already present in the previous tree. // Carry forward the scrollRef so scroll intent from a prior navigation // survives tree rebuilds (e.g. push + refresh in the same batch). return createCacheNode(existingCacheNode.rsc, dropPrefetchRsc ? null : existingCacheNode.prefetchRsc, existingCacheNode.head, dropPrefetchRsc ? null : existingCacheNode.prefetchHead, existingCacheNode.scrollRef); } function createCacheNodeForSegment(now, tree, seedRsc, metadataVaryPath, seedHead, freshness, dynamicStaleAt) { // Construct a new CacheNode using data from the BFCache, the client's // Segment Cache, or seeded from a server response. // // If there's a cache miss, or if we only have a partial hit, we'll render // the partial state immediately, and spawn a request to the server to fill // in the missing data. // // If the segment is fully cached on the client already, we can omit this // segment from the server request. // // If we already have a dynamic data response associated with this navigation, // as in the case of a Server Action-initiated redirect or refresh, we may // also be able to use that data without spawning a new request. (This is // referred to as the "seed" data.) const isPage = tree.isPage; // During certain kinds of navigations, we may be able to render from // the BFCache. switch(freshness){ case 0: { // Check BFCache during regular navigations. The entry's staleAt // determines whether it's still fresh. This is used when // staleTimes.dynamic is configured globally or when a page exports // unstable_dynamicStaleTime for per-page control. const bfcacheEntry = (0, _bfcache.readFromBFCacheDuringRegularNavigation)(now, tree.varyPath); if (bfcacheEntry !== null) { return { cacheNode: createCacheNode(bfcacheEntry.rsc, bfcacheEntry.prefetchRsc, bfcacheEntry.head, bfcacheEntry.prefetchHead), needsDynamicRequest: false }; } break; } case 1: { // This is not related to the BFCache but it is a special case. // // We should never spawn network requests during hydration. We must treat // the initial payload as authoritative, because the initial page load is // used as a last-ditch mechanism for recovering the app. // // This is also an important safety check because if this leaks into the // server rendering path (which theoretically it never should because the // server payload should be consistent), the server would hang because these // promises would never resolve. // // TODO: There is an existing case where the global "not found" boundary // triggers this path. But it does render correctly despite that. That's an // unusual render path so it's not surprising, but we should look into // modeling it in a more consistent way. See also the /_notFound special // case in updateCacheNodeOnNavigation. const rsc = seedRsc; const prefetchRsc = null; const head = isPage ? seedHead : null; const prefetchHead = null; (0, _bfcache.writeToBFCache)(now, tree.varyPath, rsc, prefetchRsc, head, prefetchHead, dynamicStaleAt); if (isPage && metadataVaryPath !== null) { (0, _bfcache.writeHeadToBFCache)(now, metadataVaryPath, head, prefetchHead, dynamicStaleAt); } return { cacheNode: createCacheNode(rsc, prefetchRsc, head, prefetchHead), needsDynamicRequest: false }; } case 2: const bfcacheEntry = (0, _bfcache.readFromBFCache)(tree.varyPath); if (bfcacheEntry !== null) { // Only show prefetched data if the dynamic data is still pending. This // avoids a flash back to the prefetch state in a case where it's highly // likely to have already streamed in. // // Tehnically, what we're actually checking is whether the dynamic // network response was received. But since it's a streaming response, // this does not mean that all the dynamic data has fully streamed in. // It just means that _some_ of the dynamic data was received. But as a // heuristic, we assume that the rest dynamic data will stream in // quickly, so it's still better to skip the prefetch state. const oldRsc = bfcacheEntry.rsc; const oldRscDidResolve = !isDeferredRsc(oldRsc) || oldRsc.status !== 'pending'; const dropPrefetchRsc = oldRscDidResolve; return { cacheNode: createCacheNode(bfcacheEntry.rsc, dropPrefetchRsc ? null : bfcacheEntry.prefetchRsc, bfcacheEntry.head, dropPrefetchRsc ? null : bfcacheEntry.prefetchHead), needsDynamicRequest: false }; } break; case 3: case 4: case 5: break; default: freshness; break; } let cachedRsc = null; let isCachedRscPartial = true; const segmentEntry = (0, _cache.readSegmentCacheEntry)(now, tree.varyPath); if (segmentEntry !== null) { switch(segmentEntry.status){ case _cache.EntryStatus.Fulfilled: { // Happy path: a cache hit cachedRsc = segmentEntry.rsc; isCachedRscPartial = segmentEntry.isPartial; break; } case _cache.EntryStatus.Pending: { // We haven't received data for this segment yet, but there's already // an in-progress request. Since it's extremely likely to arrive // before the dynamic data response, we might as well use it. const promiseForFulfilledEntry = (0, _cache.waitForSegmentCacheEntry)(segmentEntry); cachedRsc = promiseForFulfilledEntry.then((entry)=>entry !== null ? entry.rsc : null); // Because the request is still pending, we typically don't know yet // whether the response will be partial. We shouldn't skip this segment // during the dynamic navigation request. Otherwise, we might need to // do yet another request to fill in the remaining data, creating // a waterfall. // // The one exception is if this segment is being fetched with via // prefetch={true} (i.e. the "force stale" or "full" strategy). If so, // we can assume the response will be full. This field is set to `false` // for such segments. isCachedRscPartial = segmentEntry.isPartial; break; } case _cache.EntryStatus.Empty: case _cache.EntryStatus.Rejected: { break; } default: { segmentEntry; break; } } } // Now combine the cached data with the seed data to determine what we can // render immediately, versus what needs to stream in later. // A partial state to show immediately while we wait for the final data to // arrive. If `rsc` is already a complete value (not partial), or if we // don't have any useful partial state, this will be `null`. let prefetchRsc; // The final, resolved segment data. If the data is missing, this will be a // promise that resolves to the eventual data. A resolved value of `null` // means the data failed to load; the LayoutRouter will suspend indefinitely // until the router updates again (refer to finishNavigationTask). let rsc; let doesSegmentNeedDynamicRequest; if (seedRsc !== null) { // We already have a dynamic server response for this segment. if (isCachedRscPartial) { // The seed data may still be streaming in, so it's worth showing the // partial cached state in the meantime. prefetchRsc = cachedRsc; rsc = seedRsc; } else { // We already have a completely cached segment. Ignore the seed data, // which may still be streaming in. This shouldn't happen in the normal // case because the client will inform the server which segments are // already fully cached, and the server will skip rendering them. prefetchRsc = null; rsc = cachedRsc; } doesSegmentNeedDynamicRequest = false; } else { if (isCachedRscPartial) { // The cached data contains dynamic holes, or it's missing entirely. We'll // show the partial state immediately (if available), and stream in the // final data. // // Create a pending promise that we can later write to when the // data arrives from the server. prefetchRsc = cachedRsc; rsc = createDeferredRsc(); } else { // The data is fully cached. prefetchRsc = null; rsc = cachedRsc; } doesSegmentNeedDynamicRequest = isCachedRscPartial; } // If this is a page segment, we need to do the same for the head. This // follows analogous logic to the segment data above. // TODO: We don't need to store the head on the page segment's CacheNode; we // can lift it to the main state object. Then we can also delete // findHeadCache. let prefetchHead = null; let head = null; let doesHeadNeedDynamicRequest = isPage; if (isPage) { let cachedHead = null; let isCachedHeadPartial = true; if (metadataVaryPath !== null) { const metadataEntry = (0, _cache.readSegmentCacheEntry)(now, metadataVaryPath); if (metadataEntry !== null) { switch(metadataEntry.status){ case _cache.EntryStatus.Fulfilled: { cachedHead = metadataEntry.rsc; isCachedHeadPartial = metadataEntry.isPartial; break; } case _cache.EntryStatus.Pending: { cachedHead = (0, _cache.waitForSegmentCacheEntry)(metadataEntry).then((entry)=>entry !== null ? entry.rsc : null); isCachedHeadPartial = metadataEntry.isPartial; break; } case _cache.EntryStatus.Empty: case _cache.EntryStatus.Rejected: { break; } default: { metadataEntry; break; } } } } if (("TURBOPACK compile-time value", false) && isCachedHeadPartial) { // TODO: When optimistic routing is enabled, don't block on waiting for // the viewport to resolve. This is a temporary workaround until Vary // Params are tracked when rendering the metadata. We'll fix it before // this feature is stable. However, it's not a critical issue because 1) // it will stream in eventually anyway 2) metadata is wrapped in an // internal Suspense boundary, so is always non-blocking; this only // affects the viewport node, which is meant to blocking, however... 3) // before Segment Cache landed this wasn't always the case, anyway, so // it's unlikely that many people are relying on this behavior. Still, // will be fixed before stable. It's the very next step in the sequence of // work on this project. // // This line of code works because the App Router treats `null` as // "no renderable head available", rather than an empty head. React treats // an empty string as empty. cachedHead = ''; } if (seedHead !== null) { if (isCachedHeadPartial) { prefetchHead = cachedHead; head = seedHead; } else { prefetchHead = null; head = cachedHead; } doesHeadNeedDynamicRequest = false; } else { if (isCachedHeadPartial) { prefetchHead = cachedHead; head = createDeferredRsc(); } else { prefetchHead = null; head = cachedHead; } doesHeadNeedDynamicRequest = isCachedHeadPartial; } } // Now that we're creating a new segment, write its data to the BFCache. A // subsequent back/forward navigation will reuse this same data, until or // unless it's cleared by a refresh/revalidation. // // Skip BFCache writes for optimistic navigations since they are transient // and will be replaced by the canonical navigation. if (freshness !== 5) { (0, _bfcache.writeToBFCache)(now, tree.varyPath, rsc, prefetchRsc, head, prefetchHead, dynamicStaleAt); if (isPage && metadataVaryPath !== null) { (0, _bfcache.writeHeadToBFCache)(now, metadataVaryPath, head, prefetchHead, dynamicStaleAt); } } return { cacheNode: createCacheNode(rsc, prefetchRsc, head, prefetchHead), // TODO: We should store this field on the CacheNode itself. I think we can // probably unify NavigationTask, CacheNode, and DeferredRsc into a // single type. Or at least CacheNode and DeferredRsc. needsDynamicRequest: doesSegmentNeedDynamicRequest || doesHeadNeedDynamicRequest }; } function createCacheNode(rsc, prefetchRsc, head, prefetchHead, scrollRef = null) { return { rsc, prefetchRsc, head, prefetchHead, slots: null, scrollRef }; } // Represents whether the previuos navigation resulted in a route tree mismatch. // A mismatch results in a refresh of the page. If there are two successive // mismatches, we will fall back to an MPA navigation, to prevent a retry loop. let previousNavigationDidMismatch = false; function spawnDynamicRequests(task, primaryUrl, nextUrl, freshnessPolicy, accumulation, // prediction. Passed through so it can be marked as having a dynamic rewrite // if the server returns a different pathname than expected (indicating // dynamic rewrite behavior that varies by param value). routeCacheEntry, // server-patch retry logic so it can inherit the intent if the original // transition hasn't committed yet. navigateType) { const dynamicRequestTree = task.dynamicRequestTree; if (dynamicRequestTree === null) { // This navigation was fully cached. There are no dynamic requests to spawn. previousNavigationDidMismatch = false; return; } // This is intentionally not an async function to discourage the caller from // awaiting the result. Any subsequent async operations spawned by this // function should result in a separate navigation task, rather than // block the original one. // // In this function we spawn (but do not await) all the network requests that // block the navigation, and collect the promises. The next function, // `finishNavigationTask`, can await the promises in any order without // accidentally introducing a network waterfall. const primaryRequestPromise = fetchMissingDynamicData(task, dynamicRequestTree, primaryUrl, nextUrl, freshnessPolicy, routeCacheEntry); const separateRefreshUrls = accumulation.separateRefreshUrls; let refreshRequestPromises = null; if (separateRefreshUrls !== null) { // There are multiple URLs that we need to request the data from. This // happens when a "default" parallel route slot is present in the tree, and // its data cannot be fetched from the current route. We need to split the // combined dynamic request tree into separate requests per URL. // TODO: Create a scoped dynamic request tree that omits anything that // is not relevant to the given URL. Without doing this, the server may // sometimes render more data than necessary; this is not a regression // compared to the pre-Segment Cache implementation, though, just an // optimization we can make in the future. // Construct a request tree for each additional refresh URL. This will // prune away everything except the parts of the tree that match the // given refresh URL. refreshRequestPromises = []; const canonicalUrl = (0, _createhreffromurl.createHrefFromUrl)(primaryUrl); for (const refreshUrl of separateRefreshUrls){ if (refreshUrl === canonicalUrl) { continue; } // TODO: Create a scoped dynamic request tree that omits anything that // is not relevant to the given URL. Without doing this, the server may // sometimes render more data than necessary; this is not a regression // compared to the pre-Segment Cache implementation, though, just an // optimization we can make in the future. // const scopedDynamicRequestTree = splitTaskByURL(task, refreshUrl) const scopedDynamicRequestTree = dynamicRequestTree; if (scopedDynamicRequestTree !== null) { refreshRequestPromises.push(fetchMissingDynamicData(task, scopedDynamicRequestTree, new URL(refreshUrl, location.origin), // time the refresh URL was set, not the current Next-Url. Need to // start tracking this alongside the refresh URL. In the meantime, // if a refresh fails due to a mismatch, it will trigger a // hard refresh. nextUrl, freshnessPolicy, routeCacheEntry)); } } } // Further async operations are moved into this separate function to // discourage sequential network requests. const voidPromise = finishNavigationTask(task, nextUrl, primaryRequestPromise, refreshRequestPromises, routeCacheEntry, navigateType); // `finishNavigationTask` is responsible for error handling, so we can attach // noop callbacks to this promise. voidPromise.then(noop, noop); } async function finishNavigationTask(task, nextUrl, primaryRequestPromise, refreshRequestPromises, routeCacheEntry, navigateType) { // Wait for all the requests to finish, or for the first one to fail. let exitStatus = await waitForRequestsToFinish(primaryRequestPromise, refreshRequestPromises); // Once the all the requests have finished, check the tree for any remaining // pending tasks. If anything is still pending, it means the server response // does not match the client, and we must refresh to get back to a consistent // state. We can skip this step if we already detected a mismatch during the // first phase; it doesn't matter in that case because we're going to refresh // the whole tree regardless. if (exitStatus === 0) { exitStatus = abortRemainingPendingTasks(task, null, null); } switch(exitStatus){ case 0: { // The task has completely finished. There's no missing data. Exit. previousNavigationDidMismatch = false; return; } case 1: { // Some data failed to finish loading. Trigger a soft retry. // TODO: As an extra precaution against soft retry loops, consider // tracking whether a navigation was itself triggered by a retry. If two // happen in a row, fall back to a hard retry. const isHardRetry = false; const primaryRequestResult = await primaryRequestPromise; dispatchRetryDueToTreeMismatch(isHardRetry, primaryRequestResult.url, nextUrl, primaryRequestResult.seed, task.route, routeCacheEntry, navigateType); return; } case 2: { // Some data failed to finish loading in a non-recoverable way, such as a // network error. Trigger an MPA navigation. // // Hard navigating/refreshing is how we prevent an infinite retry loop // caused by a network error — when the network fails, we fall back to the // browser behavior for offline navigations. In the future, Next.js may // introduce its own custom handling of offline navigations, but that // doesn't exist yet. const isHardRetry = true; const primaryRequestResult = await primaryRequestPromise; dispatchRetryDueToTreeMismatch(isHardRetry, primaryRequestResult.url, nextUrl, primaryRequestResult.seed, task.route, routeCacheEntry, navigateType); return; } default: { return exitStatus; } } } function waitForRequestsToFinish(primaryRequestPromise, refreshRequestPromises) { // Custom async combinator logic. This could be replaced by Promise.any but // we don't assume that's available. // // Each promise resolves once the server responsds and the data is written // into the CacheNode tree. Resolve the combined promise once all the // requests finish. // // Or, resolve as soon as one of the requests fails, without waiting for the // others to finish. return new Promise((resolve)=>{ const onFulfill = (result)=>{ if (result.exitStatus === 0) { remainingCount--; if (remainingCount === 0) { // All the requests finished successfully. resolve(0); } } else { // One of the requests failed. Exit with a failing status. // NOTE: It's possible for one of the requests to fail with SoftRetry // and a later one to fail with HardRetry. In this case, we choose to // retry immediately, rather than delay the retry until all the requests // finish. If it fails again, we will hard retry on the next // attempt, anyway. resolve(result.exitStatus); } }; // onReject shouldn't ever be called because fetchMissingDynamicData's // entire body is wrapped in a try/catch. This is just defensive. const onReject = ()=>resolve(2); // Attach the listeners to the promises. let remainingCount = 1; primaryRequestPromise.then(onFulfill, onReject); if (refreshRequestPromises !== null) { remainingCount += refreshRequestPromises.length; refreshRequestPromises.forEach((refreshRequestPromise)=>refreshRequestPromise.then(onFulfill, onReject)); } }); } function dispatchRetryDueToTreeMismatch(isHardRetry, retryUrl, retryNextUrl, seed, baseTree, // prediction. If the navigation results in a mismatch, we mark it as having // a dynamic rewrite so future predictions bail out. routeCacheEntry, originalNavigateType) { // If the navigation used a route prediction, mark it as having a dynamic // rewrite since it resulted in a mismatch. if (routeCacheEntry !== null) { (0, _cache.markRouteEntryAsDynamicRewrite)(routeCacheEntry); } else if (seed !== null) { // Even without a direct reference to the route cache entry, we can still // mark the route as having a dynamic rewrite by traversing the known route // tree. This handles cases where the navigation didn't originate from a // route prediction, but still needs to mark the pattern. const metadataVaryPath = seed.metadataVaryPath; if (metadataVaryPath !== null) { const now = Date.now(); (0, _optimisticroutes.discoverKnownRoute)(now, retryUrl.pathname, retryNextUrl, null, seed.routeTree, metadataVaryPath, false, (0, _createhreffromurl.createHrefFromUrl)(retryUrl), false, true // hasDynamicRewrite ); } } // Invalidate all route cache entries. Other entries may have been derived // from the template before we knew it had a dynamic rewrite. This also // triggers re-prefetching of visible links. (0, _cache.invalidateRouteCacheEntries)(retryNextUrl, baseTree); // If this is the second time in a row that a navigation resulted in a // mismatch, fall back to a hard (MPA) refresh. isHardRetry = isHardRetry || previousNavigationDidMismatch; previousNavigationDidMismatch = true; // If the original navigation hasn't committed to the browser history yet // (the transition suspended before React committed), inherit its push/replace // intent. Otherwise, the pushState already ran, so use 'replace' to avoid // creating a duplicate history entry. // // This works because React entangles the retry's state update with the // original pending transition — they commit together as a single batch, // so the navigate type from the retry is what HistoryUpdater ultimately sees. // // TODO: Ideally this check would happen right before we schedule the React // update (i.e., closer to where the action is dispatched into the queue), // not here where the action is constructed. But the current action queue // doesn't provide a natural place for that. Revisit when we refactor the // action queue into a more reactive navigation model. const lastCommitted = (0, _committedstate.getLastCommittedTree)(); const retryNavigateType = lastCommitted !== null && baseTree !== lastCommitted ? originalNavigateType : 'replace'; const retryAction = { type: _routerreducertypes.ACTION_SERVER_PATCH, previousTree: baseTree, url: retryUrl, nextUrl: retryNextUrl, seed, mpa: isHardRetry, navigateType: retryNavigateType }; (0, _useactionqueue.dispatchAppRouterAction)(retryAction); } async function fetchMissingDynamicData(task, dynamicRequestTree, url, nextUrl, freshnessPolicy, routeCacheEntry) { try { const result = await (0, _fetchserverresponse.fetchServerResponse)(url, { flightRouterState: dynamicRequestTree, nextUrl, isHmrRefresh: freshnessPolicy === 4 }); if (typeof result === 'string') { // fetchServerResponse will return an href to indicate that the SPA // navigation failed. For example, if the server triggered a hard // redirect, or the fetch request errored. Initiate an MPA navigation // to the given href. return { exitStatus: 2, url: new URL(result, location.origin), seed: null }; } const now = Date.now(); const seed = (0, _navigation.convertServerPatchToFullTree)(now, task.route, result.flightData, result.renderedSearch, result.dynamicStaleTime); // If the navigation lock is active, wait for it to be released before // writing the dynamic data. This allows tests to assert on the prefetched // UI state. if ("TURBOPACK compile-time truthy", 1) { await waitForNavigationLock(); } if (routeCacheEntry !== null && result.staticStageData !== null) { const { response: staticStageResponse, isResponsePartial } = result.staticStageData; (0, _cache.getStaleAt)(now, staticStageResponse.s).then((staleAt)=>{ const buildId = result.responseHeaders.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? staticStageResponse.b; (0, _cache.writeStaticStageResponseIntoCache)(now, staticStageResponse.f, buildId, staticStageResponse.h, staleAt, dynamicRequestTree, result.renderedSearch, isResponsePartial); }).catch(()=>{ // The static stage processing failed. Not fatal — the navigation // completed normally, we just won't write into the cache. }); } if (routeCacheEntry !== null && result.runtimePrefetchStream !== null) { (0, _cache.processRuntimePrefetchStream)(now, result.runtimePrefetchStream, dynamicRequestTree, result.renderedSearch).then((processed)=>{ if (processed !== null) { (0, _cache.writeDynamicRenderResponseIntoCache)(now, _types.FetchStrategy.PPRRuntime, processed.flightDatas, processed.buildId, processed.isResponsePartial, processed.headVaryParams, processed.staleAt, processed.navigationSeed, null); } }).catch(()=>{ // The runtime prefetch cache write failed. Not fatal — the // navigation completed normally, we just won't cache runtime data. }); } // result.dynamicStaleTime is in seconds (from the server's `d` field). // Convert to an absolute timestamp using the centralized helper. const dynamicStaleAt = (0, _bfcache.computeDynamicStaleAt)(now, result.dynamicStaleTime); const didReceiveUnknownParallelRoute = writeDynamicDataIntoNavigationTask(task, seed.routeTree, seed.data, seed.head, dynamicStaleAt, result.debugInfo); return { exitStatus: didReceiveUnknownParallelRoute ? 1 : 0, url: new URL(result.canonicalUrl, location.origin), seed }; } catch { // This shouldn't happen because fetchServerResponse's entire body is // wrapped in a try/catch. If it does, though, it implies the server failed // to respond with any tree at all. So we must fall back to a hard retry. return { exitStatus: 2, url: url, seed: null }; } } function writeDynamicDataIntoNavigationTask(task, serverRouteTree, dynamicData, dynamicHead, dynamicStaleAt, debugInfo) { if (task.status === 0 && dynamicData !== null) { task.status = 1; finishPendingCacheNode(task.node, dynamicData, dynamicHead, debugInfo); // Update the BFCache entry's staleAt for this segment with the value // from the dynamic response. This applies the per-page // unstable_dynamicStaleTime if set, or the default DYNAMIC_STALETIME_MS. // We only update segments that received dynamic data — static segments // are unaffected. (0, _bfcache.updateBFCacheEntryStaleAt)(serverRouteTree.varyPath, dynamicStaleAt); } const taskChildren = task.children; const serverChildren = serverRouteTree.slots; const dynamicDataChildren = dynamicData !== null ? dynamicData[1] : null; // Detect whether the server sends a parallel route slot that the client // doesn't know about. let didReceiveUnknownParallelRoute = false; if (taskChildren !== null) { if (serverChildren !== null) { for(const parallelRouteKey in serverChildren){ const serverRouteTreeChild = serverChildren[parallelRouteKey]; const dynamicDataChild = dynamicDataChildren !== null ? dynamicDataChildren[parallelRouteKey] : null; const taskChild = taskChildren.get(parallelRouteKey); if (taskChild === undefined) { // The server sent a child segment that the client doesn't know about. // // When we receive an unknown parallel route, we must consider it a // mismatch. This is unlike the case where the segment itself // mismatches, because multiple routes can be active simultaneously. // But a given layout should never have a mismatching set of // child slots. // // Theoretically, this should only happen in development during an HMR // refresh, because the set of parallel routes for a layout does not // change over the lifetime of a build/deployment. In production, we // should have already mismatched on either the build id or the segment // path. But as an extra precaution, we validate in prod, too. didReceiveUnknownParallelRoute = true; } else { const taskSegment = taskChild.route[0]; const serverSegment = createSegmentFromRouteTree(serverRouteTreeChild); if ((0, _matchsegments.matchSegment)(serverSegment, taskSegment) && dynamicDataChild !== null && dynamicDataChild !== undefined) { // Found a match for this task. Keep traversing down the task tree. const childDidReceiveUnknownParallelRoute = writeDynamicDataIntoNavigationTask(taskChild, serverRouteTreeChild, dynamicDataChild, dynamicHead, dynamicStaleAt, debugInfo); if (childDidReceiveUnknownParallelRoute) { didReceiveUnknownParallelRoute = true; } } } } } else { if (serverChildren !== null) { // The server sent a child segment that the client doesn't know about. didReceiveUnknownParallelRoute = true; } } } return didReceiveUnknownParallelRoute; } function finishPendingCacheNode(cacheNode, dynamicData, dynamicHead, debugInfo) { // Writes a dynamic response into an existing Cache Node tree. This does _not_ // create a new tree, it updates the existing tree in-place. So it must follow // the Suspense rules of cache safety — it can resolve pending promises, but // it cannot overwrite existing data. It can add segments to the tree (because // a missing segment will cause the layout router to suspend). // but it cannot delete them. // // We must resolve every promise in the tree, or else it will suspend // indefinitely. If we did not receive data for a segment, we will resolve its // data promise to `null` to trigger a lazy fetch during render. // Use the dynamic data from the server to fulfill the deferred RSC promise // on the Cache Node. const rsc = cacheNode.rsc; const dynamicSegmentData = dynamicData[0]; if (dynamicSegmentData === null) { // This is an empty CacheNode; this particular server request did not // render this segment. There may be a separate pending request that will, // though, so we won't abort the task until all pending requests finish. return; } if (rsc === null) { // This is a lazy cache node. We can overwrite it. This is only safe // because we know that the LayoutRouter suspends if `rsc` is `null`. cacheNode.rsc = dynamicSegmentData; } else if (isDeferredRsc(rsc)) { // This is a deferred RSC promise. We can fulfill it with the data we just // received from the server. If it was already resolved by a different // navigation, then this does nothing because we can't overwrite data. rsc.resolve(dynamicSegmentData, debugInfo); } else { // This is not a deferred RSC promise, nor is it empty, so it must have // been populated by a different navigation. We must not overwrite it. } // Check if this is a leaf segment. If so, it will have a `head` property with // a pending promise that needs to be resolved with the dynamic head from // the server. const head = cacheNode.head; if (isDeferredRsc(head)) { head.resolve(dynamicHead, debugInfo); } } function abortRemainingPendingTasks(task, error, debugInfo) { let exitStatus; if (task.status === 0) { // The data for this segment is still missing. task.status = 2; abortPendingCacheNode(task.node, error, debugInfo); // If the server failed to fulfill the data for this segment, it implies // that the route tree received from the server mismatched the tree that // was previously prefetched. // // In an app with fully static routes and no proxy-driven redirects or // rewrites, this should never happen, because the route for a URL would // always be the same across multiple requests. So, this implies that some // runtime routing condition changed, likely in a proxy, without being // pushed to the client. // // When this happens, we treat this the same as a refresh(). The entire // tree will be re-rendered from the root. if (task.refreshState === null) { // Trigger a "soft" refresh. Essentially the same as calling `refresh()` // in a Server Action. exitStatus = 1; } else { // The mismatch was discovered inside an inactive parallel route. This // implies the inactive parallel route is no longer reachable at the URL // that originally rendered it. Fall back to an MPA refresh. // TODO: An alternative could be to trigger a soft refresh but to _not_ // re-use the inactive parallel routes this time. Similar to what would // happen if were to do a hard refrehs, but without the HTML page. exitStatus = 2; } } else { // This segment finished. (An error here is treated as Done because they are // surfaced to the application during render.) exitStatus = 0; } const taskChildren = task.children; if (taskChildren !== null) { for (const [, taskChild] of taskChildren){ const childExitStatus = abortRemainingPendingTasks(taskChild, error, debugInfo); // Propagate the exit status up the tree. The statuses are ordered by // their precedence. if (childExitStatus > exitStatus) { exitStatus = childExitStatus; } } } return exitStatus; } function abortPendingCacheNode(cacheNode, error, debugInfo) { const rsc = cacheNode.rsc; if (isDeferredRsc(rsc)) { if (error === null) { // This will trigger a lazy fetch during render. rsc.resolve(null, debugInfo); } else { // This will trigger an error during rendering. rsc.reject(error, debugInfo); } } // Check if this is a leaf segment. If so, it will have a `head` property with // a pending promise that needs to be resolved. If an error was provided, we // will not resolve it with an error, since this is rendered at the root of // the app. We want the segment to error, not the entire app. const head = cacheNode.head; if (isDeferredRsc(head)) { head.resolve(null, debugInfo); } } const DEFERRED = Symbol(); function isDeferredRsc(value) { return value && typeof value === 'object' && value.tag === DEFERRED; } function createDeferredRsc() { // Create an unresolved promise that represents data derived from a Flight // response. The promise will be resolved later as soon as we start receiving // data from the server, i.e. as soon as the Flight client decodes and returns // the top-level response object. // The `_debugInfo` field contains profiling information. Promises that are // created by Flight already have this info added by React; for any derived // promise created by the router, we need to transfer the Flight debug info // onto the derived promise. // // The debug info represents the latency between the start of the navigation // and the start of rendering. (It does not represent the time it takes for // whole stream to finish.) const debugInfo = []; let resolve; let reject; const pendingRsc = new Promise((res, rej)=>{ resolve = res; reject = rej; }); pendingRsc.status = 'pending'; pendingRsc.resolve = (value, responseDebugInfo)=>{ if (pendingRsc.status === 'pending') { const fulfilledRsc = pendingRsc; fulfilledRsc.status = 'fulfilled'; fulfilledRsc.value = value; if (responseDebugInfo !== null) { // Transfer the debug info to the derived promise. debugInfo.push.apply(debugInfo, responseDebugInfo); } resolve(value); } }; pendingRsc.reject = (error, responseDebugInfo)=>{ if (pendingRsc.status === 'pending') { const rejectedRsc = pendingRsc; rejectedRsc.status = 'rejected'; rejectedRsc.reason = error; if (responseDebugInfo !== null) { // Transfer the debug info to the derived promise. debugInfo.push.apply(debugInfo, responseDebugInfo); } reject(error); } }; pendingRsc.tag = DEFERRED; pendingRsc._debugInfo = debugInfo; return pendingRsc; } /** * Helper for the Instant Navigation Testing API. Waits for the navigation lock * to be released before returning. The network request has already completed by * the time this is called, so this only delays writing the dynamic data. * * Not exposed in production builds by default. */ async function waitForNavigationLock() { if ("TURBOPACK compile-time truthy", 1) { const { waitForNavigationLockIfActive } = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation-testing-lock.js [app-ssr] (ecmascript)"); await waitForNavigationLockIfActive(); } } 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; } }), "[project]/node_modules/next/dist/shared/lib/page-path/ensure-leading-slash.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; /** * For a given page path, this function ensures that there is a leading slash. * If there is not a leading slash, one is added, otherwise it is noop. */ Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "ensureLeadingSlash", { enumerable: true, get: function() { return ensureLeadingSlash; } }); function ensureLeadingSlash(path) { return path.startsWith('/') ? path : `/${path}`; } }), "[project]/node_modules/next/dist/shared/lib/router/utils/app-paths.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { compareAppPaths: null, normalizeAppPath: null, normalizeRscURL: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { compareAppPaths: function() { return compareAppPaths; }, normalizeAppPath: function() { return normalizeAppPath; }, normalizeRscURL: function() { return normalizeRscURL; } }); const _ensureleadingslash = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/page-path/ensure-leading-slash.js [app-ssr] (ecmascript)"); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); function normalizeAppPath(route) { return (0, _ensureleadingslash.ensureLeadingSlash)(route.split('/').reduce((pathname, segment, index, segments)=>{ // Empty segments are ignored. if (!segment) { return pathname; } // Groups are ignored. if ((0, _segment.isGroupSegment)(segment)) { return pathname; } // Parallel segments are ignored. if (segment[0] === '@') { return pathname; } // The last segment (if it's a leaf) should be ignored. if ((segment === 'page' || segment === 'route') && index === segments.length - 1) { return pathname; } return `${pathname}/${segment}`; }, '')); } function compareAppPaths(a, b) { const aHasSlot = a.includes('/@'); const bHasSlot = b.includes('/@'); if (aHasSlot && !bHasSlot) return -1; if (!aHasSlot && bHasSlot) return 1; return a.localeCompare(b); } function normalizeRscURL(url) { return url.replace(/\.rsc($|\?)/, '$1'); } }), "[project]/node_modules/next/dist/shared/lib/router/utils/interception-routes.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { INTERCEPTION_ROUTE_MARKERS: null, extractInterceptionRouteInformation: null, isInterceptionRouteAppPath: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { INTERCEPTION_ROUTE_MARKERS: function() { return INTERCEPTION_ROUTE_MARKERS; }, extractInterceptionRouteInformation: function() { return extractInterceptionRouteInformation; }, isInterceptionRouteAppPath: function() { return isInterceptionRouteAppPath; } }); const _apppaths = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/app-paths.js [app-ssr] (ecmascript)"); const INTERCEPTION_ROUTE_MARKERS = [ '(..)(..)', '(.)', '(..)', '(...)' ]; function isInterceptionRouteAppPath(path) { // TODO-APP: add more serious validation return path.split('/').find((segment)=>INTERCEPTION_ROUTE_MARKERS.find((m)=>segment.startsWith(m))) !== undefined; } function extractInterceptionRouteInformation(path) { let interceptingRoute; let marker; let interceptedRoute; for (const segment of path.split('/')){ marker = INTERCEPTION_ROUTE_MARKERS.find((m)=>segment.startsWith(m)); if (marker) { ; [interceptingRoute, interceptedRoute] = path.split(marker, 2); break; } } if (!interceptingRoute || !marker || !interceptedRoute) { throw Object.defineProperty(new Error(`Invalid interception route: ${path}. Must be in the format //(..|...|..)(..)/`), "__NEXT_ERROR_CODE", { value: "E269", enumerable: false, configurable: true }); } interceptingRoute = (0, _apppaths.normalizeAppPath)(interceptingRoute) // normalize the path, e.g. /(blog)/feed -> /feed ; switch(marker){ case '(.)': // (.) indicates that we should match with sibling routes, so we just need to append the intercepted route to the intercepting route if (interceptingRoute === '/') { interceptedRoute = `/${interceptedRoute}`; } else { interceptedRoute = interceptingRoute + '/' + interceptedRoute; } break; case '(..)': // (..) indicates that we should match at one level up, so we need to remove the last segment of the intercepting route if (interceptingRoute === '/') { throw Object.defineProperty(new Error(`Invalid interception route: ${path}. Cannot use (..) marker at the root level, use (.) instead.`), "__NEXT_ERROR_CODE", { value: "E207", enumerable: false, configurable: true }); } interceptedRoute = interceptingRoute.split('/').slice(0, -1).concat(interceptedRoute).join('/'); break; case '(...)': // (...) will match the route segment in the root directory, so we need to use the root directory to prepend the intercepted route interceptedRoute = '/' + interceptedRoute; break; case '(..)(..)': // (..)(..) indicates that we should match at two levels up, so we need to remove the last two segments of the intercepting route const splitInterceptingRoute = interceptingRoute.split('/'); if (splitInterceptingRoute.length <= 2) { throw Object.defineProperty(new Error(`Invalid interception route: ${path}. Cannot use (..)(..) marker at the root level or one level up.`), "__NEXT_ERROR_CODE", { value: "E486", enumerable: false, configurable: true }); } interceptedRoute = splitInterceptingRoute.slice(0, -2).concat(interceptedRoute).join('/'); break; default: throw Object.defineProperty(new Error('Invariant: unexpected marker'), "__NEXT_ERROR_CODE", { value: "E112", enumerable: false, configurable: true }); } return { interceptingRoute, interceptedRoute }; } }), "[project]/node_modules/next/dist/client/components/router-reducer/compute-changed-path.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { computeChangedPath: null, extractPathFromFlightRouterState: null, extractSourcePageFromFlightRouterState: null, getSelectedParams: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { computeChangedPath: function() { return computeChangedPath; }, extractPathFromFlightRouterState: function() { return extractPathFromFlightRouterState; }, extractSourcePageFromFlightRouterState: function() { return extractSourcePageFromFlightRouterState; }, getSelectedParams: function() { return getSelectedParams; } }); const _interceptionroutes = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/interception-routes.js [app-ssr] (ecmascript)"); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const _matchsegments = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/match-segments.js [app-ssr] (ecmascript)"); const removeLeadingSlash = (segment)=>{ return segment[0] === '/' ? segment.slice(1) : segment; }; const segmentToPathname = (segment)=>{ if (typeof segment === 'string') { // 'children' is not a valid path -- it's technically a parallel route that corresponds with the current segment's page // if we don't skip it, then the computed pathname might be something like `/children` which doesn't make sense. if (segment === 'children') return ''; return segment; } return segment[1]; }; const segmentToSourcePagePathname = (segment)=>{ if (typeof segment === 'string') { if (segment === 'children') return ''; if (segment.startsWith(_segment.PAGE_SEGMENT_KEY)) return 'page'; return segment; } const [paramName, , dynamicParamType] = segment; switch(dynamicParamType){ case 'c': return `[...${paramName}]`; case 'ci(..)(..)': return `(..)(..)[...${paramName}]`; case 'ci(.)': return `(.)[...${paramName}]`; case 'ci(..)': return `(..)[...${paramName}]`; case 'ci(...)': return `(...)[...${paramName}]`; case 'oc': return `[[...${paramName}]]`; case 'd': return `[${paramName}]`; case 'di(..)(..)': return `(..)(..)[${paramName}]`; case 'di(.)': return `(.)[${paramName}]`; case 'di(..)': return `(..)[${paramName}]`; case 'di(...)': return `(...)[${paramName}]`; default: dynamicParamType; return `[${paramName}]`; } }; function normalizeSegments(segments) { return segments.reduce((acc, segment)=>{ segment = removeLeadingSlash(segment); if (segment === '' || (0, _segment.isGroupSegment)(segment)) { return acc; } return `${acc}/${segment}`; }, '') || '/'; } function extractPathFromFlightRouterState(flightRouterState) { const segment = Array.isArray(flightRouterState[0]) ? flightRouterState[0][1] : flightRouterState[0]; if (segment === _segment.DEFAULT_SEGMENT_KEY || _interceptionroutes.INTERCEPTION_ROUTE_MARKERS.some((m)=>segment.startsWith(m))) return undefined; if (segment.startsWith(_segment.PAGE_SEGMENT_KEY)) return ''; const segments = [ segmentToPathname(segment) ]; const parallelRoutes = flightRouterState[1] ?? {}; const childrenPath = parallelRoutes.children ? extractPathFromFlightRouterState(parallelRoutes.children) : undefined; if (childrenPath !== undefined) { segments.push(childrenPath); } else { for (const [key, value] of Object.entries(parallelRoutes)){ if (key === 'children') continue; const childPath = extractPathFromFlightRouterState(value); if (childPath !== undefined) { segments.push(childPath); } } } return normalizeSegments(segments); } function extractSourcePageSegmentsFromFlightRouterState(flightRouterState) { const segment = segmentToSourcePagePathname(flightRouterState[0]); if (segment === _segment.DEFAULT_SEGMENT_KEY) { return undefined; } if (segment === 'page') { return [ segment ]; } const parallelRoutes = flightRouterState[1] ?? {}; const childrenPath = parallelRoutes.children ? extractSourcePageSegmentsFromFlightRouterState(parallelRoutes.children) : undefined; if (childrenPath !== undefined) { return segment === '' ? childrenPath : [ removeLeadingSlash(segment), ...childrenPath ]; } for (const [key, value] of Object.entries(parallelRoutes)){ if (key === 'children') continue; const childPath = extractSourcePageSegmentsFromFlightRouterState(value); if (childPath !== undefined) { return segment === '' ? childPath : [ removeLeadingSlash(segment), ...childPath ]; } } return undefined; } function extractSourcePageFromFlightRouterState(flightRouterState) { const sourcePageSegments = extractSourcePageSegmentsFromFlightRouterState(flightRouterState); return sourcePageSegments ? `/${sourcePageSegments.join('/')}` : undefined; } function computeChangedPathImpl(treeA, treeB) { const [segmentA, parallelRoutesA] = treeA; const [segmentB, parallelRoutesB] = treeB; const normalizedSegmentA = segmentToPathname(segmentA); const normalizedSegmentB = segmentToPathname(segmentB); if (_interceptionroutes.INTERCEPTION_ROUTE_MARKERS.some((m)=>normalizedSegmentA.startsWith(m) || normalizedSegmentB.startsWith(m))) { return ''; } if (!(0, _matchsegments.matchSegment)(segmentA, segmentB)) { // once we find where the tree changed, we compute the rest of the path by traversing the tree return extractPathFromFlightRouterState(treeB) ?? ''; } for(const parallelRouterKey in parallelRoutesA){ if (parallelRoutesB[parallelRouterKey]) { const changedPath = computeChangedPathImpl(parallelRoutesA[parallelRouterKey], parallelRoutesB[parallelRouterKey]); if (changedPath !== null) { return `${segmentToPathname(segmentB)}/${changedPath}`; } } } return null; } function computeChangedPath(treeA, treeB) { const changedPath = computeChangedPathImpl(treeA, treeB); if (changedPath == null || changedPath === '/') { return changedPath; } // lightweight normalization to remove route groups return normalizeSegments(changedPath.split('/')); } function getSelectedParams(currentTree, params = {}) { const parallelRoutes = currentTree[1]; for (const parallelRoute of Object.values(parallelRoutes)){ const segment = parallelRoute[0]; const isDynamicParameter = Array.isArray(segment); const segmentValue = isDynamicParameter ? segment[1] : segment; if (!segmentValue || segmentValue.startsWith(_segment.PAGE_SEGMENT_KEY)) continue; // Ensure catchAll and optional catchall are turned into an array const isCatchAll = isDynamicParameter && (segment[2] === 'c' || segment[2] === 'oc'); if (isCatchAll) { params[segment[0]] = segment[1].split('/'); } else if (isDynamicParameter) { params[segment[0]] = segment[1]; } params = getSelectedParams(parallelRoute, params); } return params; } 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; } }), "[project]/node_modules/next/dist/client/lib/javascript-url.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; // Adapted from React's sanitizeURL function found here: https://github.com/facebook/react/blob/b565373afd0cc1988497e1107106e851e8cfb261/packages/react-dom-bindings/src/shared/sanitizeURL.js // A javascript: URL can contain leading C0 control or \u0020 SPACE, // and any newline or tab are filtered out as if they're not part of the URL. // https://url.spec.whatwg.org/#url-parsing // Tab or newline are defined as \r\n\t: // https://infra.spec.whatwg.org/#ascii-tab-or-newline // A C0 control is a code point in the range \u0000 NULL to \u001F // INFORMATION SEPARATOR ONE, inclusive: // https://infra.spec.whatwg.org/#c0-control-or-space Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "isJavaScriptURLString", { enumerable: true, get: function() { return isJavaScriptURLString; } }); const isJavaScriptProtocol = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*:/i; function isJavaScriptURLString(url) { return isJavaScriptProtocol.test('' + url); } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/navigation.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { completeHardNavigation: null, completeSoftNavigation: null, completeTraverseNavigation: null, convertServerPatchToFullTree: null, navigate: null, navigateToKnownRoute: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { completeHardNavigation: function() { return completeHardNavigation; }, completeSoftNavigation: function() { return completeSoftNavigation; }, completeTraverseNavigation: function() { return completeTraverseNavigation; }, convertServerPatchToFullTree: function() { return convertServerPatchToFullTree; }, navigate: function() { return navigate; }, navigateToKnownRoute: function() { return navigateToKnownRoute; } }); const _fetchserverresponse = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js [app-ssr] (ecmascript)"); const _pprnavigations = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/ppr-navigations.js [app-ssr] (ecmascript)"); const _createhreffromurl = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/create-href-from-url.js [app-ssr] (ecmascript)"); const _constants = __turbopack_context__.r("[project]/node_modules/next/dist/lib/constants.js [app-ssr] (ecmascript)"); const _cache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)"); const _optimisticroutes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/optimistic-routes.js [app-ssr] (ecmascript)"); const _cachekey = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-key.js [app-ssr] (ecmascript)"); const _scheduler = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/scheduler.js [app-ssr] (ecmascript)"); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _links = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/links.js [app-ssr] (ecmascript)"); const _routerreducertypes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/router-reducer-types.js [app-ssr] (ecmascript)"); const _computechangedpath = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/compute-changed-path.js [app-ssr] (ecmascript)"); const _javascripturl = __turbopack_context__.r("[project]/node_modules/next/dist/client/lib/javascript-url.js [app-ssr] (ecmascript)"); const _bfcache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/bfcache.js [app-ssr] (ecmascript)"); function navigate(state, url, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, nextUrl, freshnessPolicy, scrollBehavior, navigateType) { // Instant Navigation Testing API: when the lock is active, ensure a // prefetch task has been initiated before proceeding with the navigation. // This guarantees that segment data requests are at least pending, even // for routes that already have a cached route tree. Without this, the // static shell might be incomplete because some segments were never // requested. if ("TURBOPACK compile-time truthy", 1) { const { isNavigationLocked } = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation-testing-lock.js [app-ssr] (ecmascript)"); if (isNavigationLocked()) { return ensurePrefetchThenNavigate(state, url, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, nextUrl, freshnessPolicy, scrollBehavior, navigateType); } } return navigateImpl(state, url, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, nextUrl, freshnessPolicy, scrollBehavior, navigateType); } function navigateImpl(state, url, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, nextUrl, freshnessPolicy, scrollBehavior, navigateType) { const now = Date.now(); const href = url.href; const cacheKey = (0, _cachekey.createCacheKey)(href, nextUrl); const route = (0, _cache.readRouteCacheEntry)(now, cacheKey); if (route !== null && route.status === _cache.EntryStatus.Fulfilled) { // We have a matching prefetch. return navigateUsingPrefetchedRouteTree(now, state, url, currentUrl, currentRenderedSearch, nextUrl, currentCacheNode, currentFlightRouterState, freshnessPolicy, scrollBehavior, navigateType, route); } // There was no matching route tree in the cache. Let's see if we can // construct an "optimistic" route tree using the deprecated search-params // based matching. This is only used when the new optimisticRouting flag is // disabled. // // Do not construct an optimistic route tree if there was a cache hit, but // the entry has a rejected status, since it may have been rejected due to a // rewrite or redirect based on the search params. // // TODO: There are multiple reasons a prefetch might be rejected; we should // track them explicitly and choose what to do here based on that. if ("TURBOPACK compile-time truthy", 1) { if (route === null || route.status !== _cache.EntryStatus.Rejected) { const optimisticRoute = (0, _cache.deprecated_requestOptimisticRouteCacheEntry)(now, url, nextUrl); if (optimisticRoute !== null) { // We have an optimistic route tree. Proceed with the normal flow. return navigateUsingPrefetchedRouteTree(now, state, url, currentUrl, currentRenderedSearch, nextUrl, currentCacheNode, currentFlightRouterState, freshnessPolicy, scrollBehavior, navigateType, optimisticRoute); } } } // There's no matching prefetch for this route in the cache. We must lazily // fetch it from the server before we can perform the navigation. // // TODO: If this is a gesture navigation, instead of performing a // dynamic request, we should do a runtime prefetch. return navigateToUnknownRoute(now, state, url, currentUrl, currentRenderedSearch, nextUrl, currentCacheNode, currentFlightRouterState, freshnessPolicy, scrollBehavior, navigateType).catch(()=>{ // If the navigation fails, return the current state return state; }); } function navigateToKnownRoute(now, state, url, canonicalUrl, navigationSeed, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, freshnessPolicy, nextUrl, scrollBehavior, navigateType, debugInfo, // prediction. Passed through so it can be marked as having a dynamic rewrite // if the server returns a different pathname (indicating dynamic rewrite // behavior). // // When null, the navigation did not use route prediction - either because // the route was already fully cached, or it's a navigation that doesn't // involve prediction (refresh, history traversal, server action, etc.). // In these cases, if a mismatch occurs, we still mark the route as having a // dynamic rewrite by traversing the known route tree (see // dispatchRetryDueToTreeMismatch). routeCacheEntry) { // A version of navigate() that accepts the target route tree as an argument // rather than reading it from the prefetch cache. const accumulation = { separateRefreshUrls: null, scrollRef: null }; // We special case navigations to the exact same URL as the current location. // It's a common UI pattern for apps to refresh when you click a link to the // current page. So when this happens, we refresh the dynamic data in the page // segments. // // Note that this does not apply if the any part of the hash or search query // has changed. This might feel a bit weird but it makes more sense when you // consider that the way to trigger this behavior is to click the same link // multiple times. // // TODO: We should probably refresh the *entire* route when this case occurs, // not just the page segments. Essentially treating it the same as a refresh() // triggered by an action, which is the more explicit way of modeling the UI // pattern described above. // // Also note that this only refreshes the dynamic data, not static/ cached // data. If the page segment is fully static and prefetched, the request is // skipped. (This is also how refresh() works.) const isSamePageNavigation = url.href === currentUrl.href; const task = (0, _pprnavigations.startPPRNavigation)(now, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, navigationSeed.routeTree, navigationSeed.metadataVaryPath, freshnessPolicy, navigationSeed.data, navigationSeed.head, navigationSeed.dynamicStaleAt, isSamePageNavigation, accumulation); if (task !== null) { if (freshnessPolicy !== _pprnavigations.FreshnessPolicy.Gesture) { (0, _pprnavigations.spawnDynamicRequests)(task, url, nextUrl, freshnessPolicy, accumulation, routeCacheEntry, navigateType); } return completeSoftNavigation(state, url, nextUrl, task.route, task.node, navigationSeed.renderedSearch, canonicalUrl, navigateType, scrollBehavior, accumulation.scrollRef, debugInfo); } // Could not perform a SPA navigation. Revert to a full-page (MPA) navigation. return completeHardNavigation(state, url, navigateType); } function navigateUsingPrefetchedRouteTree(now, state, url, currentUrl, currentRenderedSearch, nextUrl, currentCacheNode, currentFlightRouterState, freshnessPolicy, scrollBehavior, navigateType, route) { const routeTree = route.tree; const canonicalUrl = route.canonicalUrl + url.hash; const renderedSearch = route.renderedSearch; const prefetchSeed = { renderedSearch, routeTree, metadataVaryPath: route.metadata.varyPath, data: null, head: null, dynamicStaleAt: (0, _bfcache.computeDynamicStaleAt)(now, _bfcache.UnknownDynamicStaleTime) }; return navigateToKnownRoute(now, state, url, canonicalUrl, prefetchSeed, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, freshnessPolicy, nextUrl, scrollBehavior, navigateType, null, route); } // Used to request all the dynamic data for a route, rather than just a subset, // e.g. during a refresh or a revalidation. Typically this gets constructed // during the normal flow when diffing the route tree, but for an unprefetched // navigation, where we don't know the structure of the target route, we use // this instead. const DynamicRequestTreeForEntireRoute = [ '', {}, null, 'refetch' ]; async function navigateToUnknownRoute(now, state, url, currentUrl, currentRenderedSearch, nextUrl, currentCacheNode, currentFlightRouterState, freshnessPolicy, scrollBehavior, navigateType) { // Runs when a navigation happens but there's no cached prefetch we can use. // Don't bother to wait for a prefetch response; go straight to a full // navigation that contains both static and dynamic data in a single stream. // (This is unlike the old navigation implementation, which instead blocks // the dynamic request until a prefetch request is received.) // // To avoid duplication of logic, we're going to pretend that the tree // returned by the dynamic request is, in fact, a prefetch tree. Then we can // use the same server response to write the actual data into the CacheNode // tree. So it's the same flow as the "happy path" (prefetch, then // navigation), except we use a single server response for both stages. let dynamicRequestTree; switch(freshnessPolicy){ case _pprnavigations.FreshnessPolicy.Default: case _pprnavigations.FreshnessPolicy.HistoryTraversal: case _pprnavigations.FreshnessPolicy.Gesture: dynamicRequestTree = currentFlightRouterState; break; case _pprnavigations.FreshnessPolicy.Hydration: case _pprnavigations.FreshnessPolicy.RefreshAll: case _pprnavigations.FreshnessPolicy.HMRRefresh: dynamicRequestTree = DynamicRequestTreeForEntireRoute; break; default: freshnessPolicy; dynamicRequestTree = currentFlightRouterState; break; } const promiseForDynamicServerResponse = (0, _fetchserverresponse.fetchServerResponse)(url, { flightRouterState: dynamicRequestTree, nextUrl }); const result = await promiseForDynamicServerResponse; if (typeof result === 'string') { // This is an MPA navigation. const redirectUrl = new URL(result, location.origin); return completeHardNavigation(state, redirectUrl, navigateType); } const { flightData, canonicalUrl, renderedSearch, couldBeIntercepted, supportsPerSegmentPrefetching, dynamicStaleTime, staticStageData, runtimePrefetchStream, responseHeaders, debugInfo } = result; // Since the response format of dynamic requests and prefetches is slightly // different, we'll need to massage the data a bit. Create FlightRouterState // tree that simulates what we'd receive as the result of a prefetch. const navigationSeed = convertServerPatchToFullTree(now, currentFlightRouterState, flightData, renderedSearch, dynamicStaleTime); // Learn the route pattern so we can predict it for future navigations. // hasDynamicRewrite is false because this is a fresh navigation to an // unknown route - any rewrite detection happens during the traversal inside // discoverKnownRoute. The hasDynamicRewrite param is only set to true when // retrying after a tree mismatch (see dispatchRetryDueToTreeMismatch). const metadataVaryPath = navigationSeed.metadataVaryPath; if (metadataVaryPath !== null) { (0, _optimisticroutes.discoverKnownRoute)(now, url.pathname, nextUrl, null, navigationSeed.routeTree, metadataVaryPath, couldBeIntercepted, (0, _createhreffromurl.createHrefFromUrl)(canonicalUrl), supportsPerSegmentPrefetching, false // hasDynamicRewrite - not a retry, rewrite detection happens during traversal ); if (staticStageData !== null) { const { response: staticStageResponse, isResponsePartial } = staticStageData; // Write the static stage of the response into the segment cache so that // subsequent navigations can serve cached static segments instantly. (0, _cache.getStaleAt)(now, staticStageResponse.s).then((staleAt)=>{ const buildId = responseHeaders.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? staticStageResponse.b; (0, _cache.writeStaticStageResponseIntoCache)(now, staticStageResponse.f, buildId, staticStageResponse.h, staleAt, currentFlightRouterState, renderedSearch, isResponsePartial); }).catch(()=>{ // The static stage processing failed. Not fatal — the navigation // completed normally, we just won't write into the cache. }); } if (runtimePrefetchStream !== null) { (0, _cache.processRuntimePrefetchStream)(now, runtimePrefetchStream, currentFlightRouterState, renderedSearch).then((processed)=>{ if (processed !== null) { (0, _cache.writeDynamicRenderResponseIntoCache)(now, _types.FetchStrategy.PPRRuntime, processed.flightDatas, processed.buildId, processed.isResponsePartial, processed.headVaryParams, processed.staleAt, processed.navigationSeed, null); } }).catch(()=>{ // The runtime prefetch cache write failed. Not fatal — the // navigation completed normally, we just won't cache runtime data. }); } } return navigateToKnownRoute(now, state, url, (0, _createhreffromurl.createHrefFromUrl)(canonicalUrl), navigationSeed, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, freshnessPolicy, nextUrl, scrollBehavior, navigateType, debugInfo, // came directly from the server. If a mismatch occurs during dynamic data // fetch, the retry handler will traverse the known route tree to mark the // entry as having a dynamic rewrite. null); } function completeHardNavigation(state, url, navigateType) { if ((0, _javascripturl.isJavaScriptURLString)(url.href)) { console.error('Next.js has blocked a javascript: URL as a security precaution.'); return state; } const newState = { canonicalUrl: url.origin === location.origin ? (0, _createhreffromurl.createHrefFromUrl)(url) : url.href, pushRef: { pendingPush: navigateType === 'push', mpaNavigation: true, preserveCustomHistoryState: false }, // TODO: None of the rest of these values are consistent with the incoming // navigation. We rely on the fact that AppRouter will suspend and trigger // a hard navigation before it accesses any of these values. But instead // we should trigger the hard navigation and blocking any subsequent // router updates without updating React. renderedSearch: state.renderedSearch, focusAndScrollRef: state.focusAndScrollRef, cache: state.cache, tree: state.tree, nextUrl: state.nextUrl, previousNextUrl: state.previousNextUrl, debugInfo: null }; return newState; } function completeSoftNavigation(oldState, url, referringNextUrl, tree, cache, renderedSearch, canonicalUrl, navigateType, scrollBehavior, scrollRef, collectedDebugInfo) { // The "Next-Url" is a special representation of the URL that Next.js // uses to implement interception routes. // TODO: Get rid of this extra traversal by computing this during the // same traversal that computes the tree itself. We should also figure out // what is the minimum information needed for the server to correctly // intercept the route. const changedPath = (0, _computechangedpath.computeChangedPath)(oldState.tree, tree); const nextUrlForNewRoute = changedPath ? changedPath : oldState.nextUrl; // This value is stored on the state as `previousNextUrl`; the naming is // confusing. What it represents is the "Next-Url" header that was used to // fetch the incoming route. It's essentially the refererer URL, but in a // Next.js specific format. During refreshes, this is sent back to the server // instead of the current route's "Next-Url" so that the same interception // logic is applied as during the original navigation. const previousNextUrl = referringNextUrl; // Check if the only thing that changed was the hash fragment. const oldUrl = new URL(oldState.canonicalUrl, url); const onlyHashChange = // navigations are always same-origin. url.pathname === oldUrl.pathname && url.search === oldUrl.search && url.hash !== oldUrl.hash; // Determine whether and how the page should scroll after this // navigation. // // By default, we scroll to the segments that were navigated to — i.e. // segments in the new part of the route, as opposed to shared segments // that were already part of the previous route. All newly navigated // segments share a single ScrollRef. When they mount, the first one // to mount initiates the scroll. They share a ref so that only one // scroll happens per navigation. // // If a subsequent navigation produces new segments, those supersede // any pending scroll from the previous navigation by invalidating its // ScrollRef. If a navigation doesn't produce any new segments (e.g. // a refresh where the route structure didn't change), any pending // scrolls from previous navigations are unaffected. // // The branches below handle special cases layered on top of this // default model. let activeScrollRef; let forceScroll; if (scrollBehavior === _routerreducertypes.ScrollBehavior.NoScroll) { // The user explicitly opted out of scrolling (e.g. scroll={false} // on a Link or router.push). // // If this navigation created new scroll targets (scrollRef !== null), // neutralize them. If it didn't, any prior scroll targets carried // forward on the cache nodes via reuseSharedCacheNode remain active. if (scrollRef !== null) { scrollRef.current = false; } activeScrollRef = oldState.focusAndScrollRef.scrollRef; forceScroll = false; } else if (onlyHashChange) { // Hash-only navigations should scroll regardless of per-node state. // Create a fresh ref so the first segment to scroll consumes it. // // Invalidate any scroll ref from a prior navigation that hasn't // been consumed yet. const oldScrollRef = oldState.focusAndScrollRef.scrollRef; if (oldScrollRef !== null) { oldScrollRef.current = false; } // Also invalidate any per-node refs that were accumulated during // this navigation's tree construction — the hash-only ref // supersedes them. if (scrollRef !== null) { scrollRef.current = false; } activeScrollRef = { current: true }; forceScroll = true; } else { // Default case. Use the accumulated scrollRef (may be null if no // new segments were created). The handler checks per-node refs, so // unchanged parallel route slots won't scroll. activeScrollRef = scrollRef; // If this navigation created new scroll targets, invalidate any // pending scroll from a previous navigation. if (scrollRef !== null) { const oldScrollRef = oldState.focusAndScrollRef.scrollRef; if (oldScrollRef !== null) { oldScrollRef.current = false; } } forceScroll = false; } const newState = { canonicalUrl, renderedSearch, pushRef: { pendingPush: navigateType === 'push', mpaNavigation: false, preserveCustomHistoryState: false }, focusAndScrollRef: { scrollRef: activeScrollRef, forceScroll, onlyHashChange, hashFragment: // // Empty hash should trigger default behavior of scrolling layout into // view. #top is handled in layout-router. // // Refer to `ScrollAndFocusHandler` for details on how this is used. scrollBehavior !== _routerreducertypes.ScrollBehavior.NoScroll && url.hash !== '' ? decodeURIComponent(url.hash.slice(1)) : oldState.focusAndScrollRef.hashFragment }, cache, tree, nextUrl: nextUrlForNewRoute, previousNextUrl, debugInfo: collectedDebugInfo }; return newState; } function completeTraverseNavigation(state, url, renderedSearch, cache, tree, nextUrl) { return { // Set canonical url canonicalUrl: (0, _createhreffromurl.createHrefFromUrl)(url), renderedSearch, pushRef: { pendingPush: false, mpaNavigation: false, // Ensures that the custom history state that was set is preserved when applying this update. preserveCustomHistoryState: true }, focusAndScrollRef: state.focusAndScrollRef, cache, // Restore provided tree tree, nextUrl, // TODO: We need to restore previousNextUrl, too, which represents the // Next-Url that was used to fetch the data. Anywhere we fetch using the // canonical URL, there should be a corresponding Next-Url. previousNextUrl: null, debugInfo: null }; } function convertServerPatchToFullTree(now, currentTree, flightData, renderedSearch, dynamicStaleTimeSeconds) { // During a client navigation or prefetch, the server sends back only a patch // for the parts of the tree that have changed. // // This applies the patch to the base tree to create a full representation of // the resulting tree. // // The return type includes a full FlightRouterState tree and a full // CacheNodeSeedData tree. (Conceptually these are the same tree, and should // eventually be unified, but there's still lots of existing code that // operates on FlightRouterState trees alone without the CacheNodeSeedData.) // // TODO: This similar to what apply-router-state-patch-to-tree does. It // will eventually fully replace it. We should get rid of all the remaining // places where we iterate over the server patch format. This should also // eventually replace normalizeFlightData. let baseTree = currentTree; let baseData = null; let head = null; if (flightData !== null) { for (const { segmentPath, tree: treePatch, seedData: dataPatch, head: headPatch } of flightData){ const result = convertServerPatchToFullTreeImpl(baseTree, baseData, treePatch, dataPatch, segmentPath, renderedSearch, 0); baseTree = result.tree; baseData = result.data; // This is the same for all patches per response, so just pick an // arbitrary one head = headPatch; } } const finalFlightRouterState = baseTree; // Convert the final FlightRouterState into a RouteTree type. // // TODO: Eventually, FlightRouterState will evolve to being a transport format // only. The RouteTree type will become the main type used for dealing with // routes on the client, and we'll store it in the state directly. const acc = { metadataVaryPath: null }; const routeTree = (0, _cache.convertRootFlightRouterStateToRouteTree)(finalFlightRouterState, renderedSearch, acc); return { routeTree, metadataVaryPath: acc.metadataVaryPath, data: baseData, renderedSearch, head, dynamicStaleAt: (0, _bfcache.computeDynamicStaleAt)(now, dynamicStaleTimeSeconds) }; } function convertServerPatchToFullTreeImpl(baseRouterState, baseData, treePatch, dataPatch, segmentPath, renderedSearch, index) { if (index === segmentPath.length) { // We reached the part of the tree that we need to patch. return { tree: treePatch, data: dataPatch }; } // segmentPath represents the parent path of subtree. It's a repeating // pattern of parallel route key and segment: // // [string, Segment, string, Segment, string, Segment, ...] // // This path tells us which part of the base tree to apply the tree patch. // // NOTE: We receive the FlightRouterState patch in the same request as the // seed data patch. Therefore we don't need to worry about diffing the segment // values; we can assume the server sent us a correct result. const updatedParallelRouteKey = segmentPath[index]; // const segment: Segment = segmentPath[index + 1] <-- Not used, see note above const baseTreeChildren = baseRouterState[1]; const baseSeedDataChildren = baseData !== null ? baseData[1] : null; const newTreeChildren = {}; const newSeedDataChildren = {}; for(const parallelRouteKey in baseTreeChildren){ const childBaseRouterState = baseTreeChildren[parallelRouteKey]; const childBaseSeedData = baseSeedDataChildren !== null ? baseSeedDataChildren[parallelRouteKey] ?? null : null; if (parallelRouteKey === updatedParallelRouteKey) { const result = convertServerPatchToFullTreeImpl(childBaseRouterState, childBaseSeedData, treePatch, dataPatch, segmentPath, renderedSearch, // the end of the segment path. index + 2); newTreeChildren[parallelRouteKey] = result.tree; newSeedDataChildren[parallelRouteKey] = result.data; } else { // This child is not being patched. Copy it over as-is. newTreeChildren[parallelRouteKey] = childBaseRouterState; newSeedDataChildren[parallelRouteKey] = childBaseSeedData; } } let clonedTree; let clonedSeedData; // Clone all the fields except the children. // Clone the FlightRouterState tree. Based on equivalent logic in // apply-router-state-patch-to-tree, but should confirm whether we need to // copy all of these fields. Not sure the server ever sends, e.g. the // refetch marker. clonedTree = [ baseRouterState[0], newTreeChildren ]; if (2 in baseRouterState) { const compressedRefreshState = baseRouterState[2]; if (compressedRefreshState !== undefined && compressedRefreshState !== null) { // Since this part of the tree was patched with new data, any parent // refresh states should be updated to reflect the new rendered search // value. (The refresh state acts like a "context provider".) All pages // within the same server response share the same renderedSearch value, // but the same RouteTree could be composed from multiple different // routes, and multiple responses. clonedTree[2] = [ compressedRefreshState[0], renderedSearch ]; } } if (3 in baseRouterState) { clonedTree[3] = baseRouterState[3]; } if (4 in baseRouterState) { clonedTree[4] = baseRouterState[4]; } // Clone the CacheNodeSeedData tree. const isEmptySeedDataPartial = true; clonedSeedData = [ null, newSeedDataChildren, null, isEmptySeedDataPartial, null ]; return { tree: clonedTree, data: clonedSeedData }; } /** * Instant Navigation Testing API: ensures a prefetch task has been initiated * and completed before proceeding with the navigation. This guarantees that * segment data requests are at least pending, even for routes whose route * tree is already cached. * * After the prefetch completes, delegates to the normal navigation flow. */ async function ensurePrefetchThenNavigate(state, url, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, nextUrl, freshnessPolicy, scrollBehavior, navigateType) { const link = (0, _links.getLinkForCurrentNavigation)(); const fetchStrategy = link !== null ? link.fetchStrategy : _types.FetchStrategy.PPR; // Transition the cookie to captured-SPA immediately, before waiting // for the prefetch. This ensures the devtools panel can update its UI // right away, even if the prefetch takes time (e.g. dev compilation). // The "to" tree starts as null and is filled in after the prefetch // resolves and the navigation produces a new router state. const { transitionToCapturedSPA, updateCapturedSPAToTree } = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation-testing-lock.js [app-ssr] (ecmascript)"); transitionToCapturedSPA(currentFlightRouterState, null); const cacheKey = (0, _cachekey.createCacheKey)(url.href, nextUrl); await new Promise((resolve)=>{ (0, _scheduler.schedulePrefetchTask)(cacheKey, currentFlightRouterState, fetchStrategy, _types.PrefetchPriority.Default, null, resolve // _onComplete callback ); }); // Prefetch is complete. Proceed with the normal navigation flow, which // will now find the route in the cache. const result = await navigateImpl(state, url, currentUrl, currentRenderedSearch, currentCacheNode, currentFlightRouterState, nextUrl, freshnessPolicy, scrollBehavior, navigateType); // Update the cookie with the resolved "to" tree so the devtools // panel can display both routes immediately. updateCapturedSPAToTree(currentFlightRouterState, result.tree); return result; } 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; } }), "[project]/node_modules/next/dist/client/components/router-reducer/reducers/navigate-reducer.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { DYNAMIC_STALETIME_MS: null, STATIC_STALETIME_MS: null, navigateReducer: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { DYNAMIC_STALETIME_MS: function() { return DYNAMIC_STALETIME_MS; }, STATIC_STALETIME_MS: function() { return STATIC_STALETIME_MS; }, navigateReducer: function() { return navigateReducer; } }); const _navigation = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation.js [app-ssr] (ecmascript)"); const _cache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)"); const _pprnavigations = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/ppr-navigations.js [app-ssr] (ecmascript)"); const DYNAMIC_STALETIME_MS = Number(("TURBOPACK compile-time value", "0")) * 1000; const STATIC_STALETIME_MS = (0, _cache.getStaleTimeMs)(Number(("TURBOPACK compile-time value", "300"))); function navigateReducer(state, action) { const { url, isExternalUrl, navigateType, scrollBehavior } = action; if (isExternalUrl) { return (0, _navigation.completeHardNavigation)(state, url, navigateType); } // Handles case where `` tag is present, // which will trigger an MPA navigation. if (document.getElementById('__next-page-redirect')) { return (0, _navigation.completeHardNavigation)(state, url, navigateType); } // Temporary glue code between the router reducer and the new navigation // implementation. Eventually we'll rewrite the router reducer to a // state machine. const currentUrl = new URL(state.canonicalUrl, location.origin); const currentRenderedSearch = state.renderedSearch; return (0, _navigation.navigate)(state, url, currentUrl, currentRenderedSearch, state.cache, state.tree, state.nextUrl, _pprnavigations.FreshnessPolicy.Default, scrollBehavior, navigateType); } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/bfcache.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { UnknownDynamicStaleTime: null, computeDynamicStaleAt: null, invalidateBfCache: null, readFromBFCache: null, readFromBFCacheDuringRegularNavigation: null, updateBFCacheEntryStaleAt: null, writeHeadToBFCache: null, writeToBFCache: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { UnknownDynamicStaleTime: function() { return UnknownDynamicStaleTime; }, computeDynamicStaleAt: function() { return computeDynamicStaleAt; }, invalidateBfCache: function() { return invalidateBfCache; }, readFromBFCache: function() { return readFromBFCache; }, readFromBFCacheDuringRegularNavigation: function() { return readFromBFCacheDuringRegularNavigation; }, updateBFCacheEntryStaleAt: function() { return updateBFCacheEntryStaleAt; }, writeHeadToBFCache: function() { return writeHeadToBFCache; }, writeToBFCache: function() { return writeToBFCache; } }); const _navigatereducer = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/reducers/navigate-reducer.js [app-ssr] (ecmascript)"); const _cachemap = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-map.js [app-ssr] (ecmascript)"); const UnknownDynamicStaleTime = -1; function computeDynamicStaleAt(now, dynamicStaleTimeSeconds) { return dynamicStaleTimeSeconds !== UnknownDynamicStaleTime ? now + dynamicStaleTimeSeconds * 1000 : now + _navigatereducer.DYNAMIC_STALETIME_MS; } const bfcacheMap = (0, _cachemap.createCacheMap)(); let currentBfCacheVersion = 0; function invalidateBfCache() { if ("TURBOPACK compile-time truthy", 1) { return; } //TURBOPACK unreachable ; } function writeToBFCache(now, varyPath, rsc, prefetchRsc, head, prefetchHead, dynamicStaleAt) { if ("TURBOPACK compile-time truthy", 1) { return; } //TURBOPACK unreachable ; const entry = undefined; const isRevalidation = undefined; } function writeHeadToBFCache(now, varyPath, head, prefetchHead, dynamicStaleAt) { // Read the special "segment" that represents the head data. writeToBFCache(now, varyPath, head, prefetchHead, null, null, dynamicStaleAt); } function updateBFCacheEntryStaleAt(varyPath, newStaleAt) { if ("TURBOPACK compile-time truthy", 1) { return; } //TURBOPACK unreachable ; const isRevalidation = undefined; // Read with staleness bypass (-1) so we can update even stale entries const entry = undefined; } function readFromBFCache(varyPath) { if ("TURBOPACK compile-time truthy", 1) { return null; } //TURBOPACK unreachable ; const isRevalidation = undefined; } function readFromBFCacheDuringRegularNavigation(now, varyPath) { if ("TURBOPACK compile-time truthy", 1) { return null; } //TURBOPACK unreachable ; const isRevalidation = undefined; } 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; } }), "[project]/node_modules/next/dist/client/dev/debug-channel.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { createDebugChannel: null, getOrCreateDebugChannelReadableWriterPair: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { createDebugChannel: function() { return createDebugChannel; }, getOrCreateDebugChannelReadableWriterPair: function() { return getOrCreateDebugChannelReadableWriterPair; } }); const _approuterheaders = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)"); const _invarianterror = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/invariant-error.js [app-ssr] (ecmascript)"); const pairs = new Map(); function getOrCreateDebugChannelReadableWriterPair(requestId) { let pair = pairs.get(requestId); if (!pair) { const { readable, writable } = new TransformStream(); pair = { readable, writer: writable.getWriter() }; pairs.set(requestId, pair); pair.writer.closed.finally(()=>pairs.delete(requestId)); } return pair; } function createDebugChannel(requestHeaders) { let requestId; if (requestHeaders) { requestId = requestHeaders[_approuterheaders.NEXT_REQUEST_ID_HEADER] ?? undefined; if (!requestId) { throw Object.defineProperty(new _invarianterror.InvariantError(`Expected a ${JSON.stringify(_approuterheaders.NEXT_REQUEST_ID_HEADER)} request header.`), "__NEXT_ERROR_CODE", { value: "E854", enumerable: false, configurable: true }); } } else { requestId = self.__next_r; if (!requestId) { throw Object.defineProperty(new _invarianterror.InvariantError(`Expected a request ID to be defined for the document via self.__next_r.`), "__NEXT_ERROR_CODE", { value: "E806", enumerable: false, configurable: true }); } } const { readable } = getOrCreateDebugChannelReadableWriterPair(requestId); return { readable }; } 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; } }), "[project]/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { createFetch: null, createFromNextReadableStream: null, decodeStaticStage: null, fetchServerResponse: null, processFetch: null, resolveStaticStageData: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { createFetch: function() { return createFetch; }, createFromNextReadableStream: function() { return createFromNextReadableStream; }, decodeStaticStage: function() { return decodeStaticStage; }, fetchServerResponse: function() { return fetchServerResponse; }, processFetch: function() { return processFetch; }, resolveStaticStageData: function() { return resolveStaticStageData; } }); const _client = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client.js [app-ssr] (ecmascript)"); const _invarianterror = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/invariant-error.js [app-ssr] (ecmascript)"); const _approuterheaders = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)"); const _appcallserver = __turbopack_context__.r("[project]/node_modules/next/dist/client/app-call-server.js [app-ssr] (ecmascript)"); const _appfindsourcemapurl = __turbopack_context__.r("[project]/node_modules/next/dist/client/app-find-source-map-url.js [app-ssr] (ecmascript)"); const _flightdatahelpers = __turbopack_context__.r("[project]/node_modules/next/dist/client/flight-data-helpers.js [app-ssr] (ecmascript)"); const _setcachebustingsearchparam = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.js [app-ssr] (ecmascript)"); const _routeparams = __turbopack_context__.r("[project]/node_modules/next/dist/client/route-params.js [app-ssr] (ecmascript)"); const _deploymentid = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/deployment-id.js [app-ssr] (ecmascript)"); const _navigationbuildid = __turbopack_context__.r("[project]/node_modules/next/dist/client/navigation-build-id.js [app-ssr] (ecmascript)"); const _constants = __turbopack_context__.r("[project]/node_modules/next/dist/lib/constants.js [app-ssr] (ecmascript)"); const _cache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)"); const _bfcache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/bfcache.js [app-ssr] (ecmascript)"); const createFromReadableStream = _client.createFromReadableStream; const createFromFetch = _client.createFromFetch; let createDebugChannel; if ("TURBOPACK compile-time truthy", 1) { createDebugChannel = __turbopack_context__.r("[project]/node_modules/next/dist/client/dev/debug-channel.js [app-ssr] (ecmascript)").createDebugChannel; } function doMpaNavigation(url) { return (0, _routeparams.urlToUrlWithoutFlightMarker)(new URL(url, location.origin)).toString(); } let isPageUnloading = false; if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; async function fetchServerResponse(url, options) { const { flightRouterState, nextUrl } = options; const headers = { // Enable flight response [_approuterheaders.RSC_HEADER]: '1', // Provide the current router state [_approuterheaders.NEXT_ROUTER_STATE_TREE_HEADER]: (0, _flightdatahelpers.prepareFlightRouterStateForRequest)(flightRouterState, options.isHmrRefresh) }; if (("TURBOPACK compile-time value", "development") === 'development' && options.isHmrRefresh) { headers[_approuterheaders.NEXT_HMR_REFRESH_HEADER] = '1'; } if (nextUrl) { headers[_approuterheaders.NEXT_URL] = nextUrl; } // In static export mode, we need to modify the URL to request the .txt file, // but we should preserve the original URL for the canonical URL and error handling. const originalUrl = url; try { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; // Typically, during a navigation, we decode the response using Flight's // `createFromFetch` API, which accepts a `fetch` promise. // TODO: Remove this check once the old PPR flag is removed const isLegacyPPR = ("TURBOPACK compile-time value", false) && !("TURBOPACK compile-time value", false); const shouldImmediatelyDecode = !isLegacyPPR; const res = await createFetch(url, headers, 'auto', shouldImmediatelyDecode); const responseUrl = (0, _routeparams.urlToUrlWithoutFlightMarker)(new URL(res.url)); const canonicalUrl = res.redirected ? responseUrl : originalUrl; const contentType = res.headers.get('content-type') || ''; const interception = !!res.headers.get('vary')?.includes(_approuterheaders.NEXT_URL); const postponed = !!res.headers.get(_approuterheaders.NEXT_DID_POSTPONE_HEADER); let isFlightResponse = contentType.startsWith(_approuterheaders.RSC_CONTENT_TYPE_HEADER); if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; // If fetch returns something different than flight response handle it like a mpa navigation // If the fetch was not 200, we also handle it like a mpa navigation if (!isFlightResponse || !res.ok || !res.body) { // in case the original URL came with a hash, preserve it before redirecting to the new URL if (url.hash) { responseUrl.hash = url.hash; } return doMpaNavigation(responseUrl.toString()); } // We may navigate to a page that requires a different Webpack runtime. // In prod, every page will have the same Webpack runtime. // In dev, the Webpack runtime is minimal for each page. // We need to ensure the Webpack runtime is updated before executing client-side JS of the new page. // TODO: This needs to happen in the Flight Client. // Or Webpack needs to include the runtime update in the Flight response as // a blocking script. if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; let flightResponsePromise = res.flightResponsePromise; if (flightResponsePromise === null) { // Typically, `createFetch` would have already started decoding the // Flight response. If it hasn't, though, we need to decode it now. // TODO: This should only be reachable if legacy PPR is enabled (i.e. PPR // without Cache Components). Remove this branch once legacy PPR // is deleted. flightResponsePromise = createFromNextReadableStream(res.body, headers, { allowPartialStream: postponed }); } const [flightResponse, cacheData] = await Promise.all([ flightResponsePromise, res.cacheData ]); if ((res.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? flightResponse.b) !== (0, _navigationbuildid.getNavigationBuildId)()) { // The server build does not match the client build. return doMpaNavigation(res.url); } const normalizedFlightData = (0, _flightdatahelpers.normalizeFlightData)(flightResponse.f); if (typeof normalizedFlightData === 'string') { return doMpaNavigation(normalizedFlightData); } const staticStageData = cacheData !== null ? await resolveStaticStageData(cacheData, flightResponse, headers) : null; return { flightData: normalizedFlightData, canonicalUrl: canonicalUrl, // TODO: We should be able to read this from the rewrite header, not the // Flight response. Theoretically they should always agree, but there are // currently some cases where it's incorrect for interception routes. We // can always trust the value in the response body. However, per-segment // prefetch responses don't embed the value in the body; they rely on the // header alone. So we need to investigate why the header is sometimes // wrong for interception routes. renderedSearch: flightResponse.q, couldBeIntercepted: interception, supportsPerSegmentPrefetching: flightResponse.S, postponed, // The dynamicStaleTime is only present in the response body when // a page exports unstable_dynamicStaleTime and this is a dynamic render. // When absent (UnknownDynamicStaleTime), the client falls back to the // global DYNAMIC_STALETIME_MS. The value is in seconds. dynamicStaleTime: flightResponse.d ?? _bfcache.UnknownDynamicStaleTime, staticStageData, runtimePrefetchStream: flightResponse.p ?? null, responseHeaders: res.headers, debugInfo: flightResponsePromise._debugInfo ?? null }; } catch (err) { if (!isPageUnloading) { console.error(`Failed to fetch RSC payload for ${originalUrl}. Falling back to browser navigation.`, err); } // If fetch fails handle it like a mpa navigation // TODO-APP: Add a test for the case where a CORS request fails, e.g. external url redirect coming from the response. // See https://github.com/vercel/next.js/issues/43605#issuecomment-1451617521 for a reproduction. return originalUrl.toString(); } } async function processFetch(response) { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; return { response, cacheData: null }; } async function resolveStaticStageData(cacheData, flightResponse, headers) { const { isResponsePartial, responseBodyClone } = cacheData; if (responseBodyClone) { if (!isResponsePartial) { // Fully static — cache the entire decoded response as-is. responseBodyClone.cancel(); return { response: flightResponse, isResponsePartial: false }; } if (flightResponse.l !== undefined) { // Partially static — truncate the body clone at the byte boundary and // decode it. const response = await decodeStaticStage(responseBodyClone, flightResponse.l, headers); return { response, isResponsePartial: true }; } // No caching — cancel the unused clone. responseBodyClone.cancel(); } return null; } async function decodeStaticStage(responseBodyClone, staticStageByteLengthPromise, headers) { const staticStageByteLength = await staticStageByteLengthPromise; const truncatedStream = truncateStream(responseBodyClone, staticStageByteLength); return createFromNextReadableStream(truncatedStream, headers, { allowPartialStream: true }); } async function createFetch(url, headers, fetchPriority, shouldImmediatelyDecode, signal) { // TODO: In output: "export" mode, the headers do nothing. Omit them (and the // cache busting search param) from the request so they're // maximally cacheable. if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; const deploymentId = (0, _deploymentid.getDeploymentId)(); if (deploymentId) { headers['x-deployment-id'] = deploymentId; } if ("TURBOPACK compile-time truthy", 1) { if (self.__next_r) { headers[_approuterheaders.NEXT_HTML_REQUEST_ID_HEADER] = self.__next_r; } // Create a new request ID for the server action request. The server uses // this to tag debug information sent via WebSocket to the client, which // then routes those chunks to the debug channel associated with this ID. headers[_approuterheaders.NEXT_REQUEST_ID_HEADER] = crypto.getRandomValues(new Uint32Array(1))[0].toString(16); } const fetchOptions = { // Backwards compat for older browsers. `same-origin` is the default in modern browsers. credentials: 'same-origin', headers, priority: fetchPriority || undefined, signal }; // `fetchUrl` is slightly different from `url` because we add a cache-busting // search param to it. This should not leak outside of this function, so we // track them separately. let fetchUrl = new URL(url); await (0, _setcachebustingsearchparam.setCacheBustingSearchParam)(fetchUrl, headers); let processed = fetch(fetchUrl, fetchOptions).then(processFetch); let fetchPromise = processed.then(({ response })=>response); // Immediately pass the fetch promise to the Flight client so that the debug // info includes the latency from the client to the server. The internal timer // in React starts as soon as `createFromFetch` is called. // // The only case where we don't do this is during a prefetch, because a // top-level prefetch response never blocks a navigation; if it hasn't already // been written into the cache by the time the navigation happens, the router // will go straight to a dynamic request. let flightResponsePromise = shouldImmediatelyDecode ? createFromNextFetch(fetchPromise, headers) : null; let browserResponse = await fetchPromise; // If the server responds with a redirect (e.g. 307), and the redirected // location does not contain the cache busting search param set in the // original request, the response is likely invalid — when following the // redirect, the browser forwards the request headers, but since the cache // busting search param is missing, the server will reject the request due to // a mismatch. // // Ideally, we would be able to intercept the redirect response and perform it // manually, instead of letting the browser automatically follow it, but this // is not allowed by the fetch API. // // So instead, we must "replay" the redirect by fetching the new location // again, but this time we'll append the cache busting search param to prevent // a mismatch. // // TODO: We can optimize Next.js's built-in middleware APIs by returning a // custom status code, to prevent the browser from automatically following it. // // This does not affect Server Action-based redirects; those are encoded // differently, as part of the Flight body. It only affects redirects that // occur in a middleware or a third-party proxy. let redirected = browserResponse.redirected; if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; // Remove the cache busting search param from the response URL, to prevent it // from leaking outside of this function. const responseUrl = new URL(browserResponse.url, fetchUrl); responseUrl.searchParams.delete(_approuterheaders.NEXT_RSC_UNION_QUERY); const rscResponse = { url: responseUrl.href, // This is true if any redirects occurred, either automatically by the // browser, or manually by us. So it's different from // `browserResponse.redirected`, which only tells us whether the browser // followed a redirect, and only for the last response in the chain. redirected, // These can be copied from the last browser response we received. We // intentionally only expose the subset of fields that are actually used // elsewhere in the codebase. ok: browserResponse.ok, headers: browserResponse.headers, body: browserResponse.body, status: browserResponse.status, // This is the exact promise returned by `createFromFetch`. It contains // debug information that we need to transfer to any derived promises that // are later rendered by React. flightResponsePromise: flightResponsePromise, cacheData: processed.then(({ cacheData })=>cacheData) }; return rscResponse; } function createFromNextReadableStream(flightStream, requestHeaders, options) { return createFromReadableStream(flightStream, { callServer: _appcallserver.callServer, findSourceMapURL: _appfindsourcemapurl.findSourceMapURL, debugChannel: createDebugChannel && createDebugChannel(requestHeaders), unstable_allowPartialStream: options?.allowPartialStream }); } function createFromNextFetch(promiseForResponse, requestHeaders) { return createFromFetch(promiseForResponse, { callServer: _appcallserver.callServer, findSourceMapURL: _appfindsourcemapurl.findSourceMapURL, debugChannel: createDebugChannel && createDebugChannel(requestHeaders) }); } function truncateStream(stream, byteLength) { const reader = stream.getReader(); let remaining = byteLength; return new ReadableStream({ async pull (controller) { if (remaining <= 0) { reader.cancel(); controller.close(); return; } const { done, value } = await reader.read(); if (done) { controller.close(); return; } if (value.byteLength <= remaining) { controller.enqueue(value); remaining -= value.byteLength; } else { controller.enqueue(value.subarray(0, remaining)); remaining = 0; reader.cancel(); controller.close(); } }, cancel () { reader.cancel(); } }); } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { EntryStatus: null, attemptToFulfillDynamicSegmentFromBFCache: null, attemptToUpgradeSegmentFromBFCache: null, canNewFetchStrategyProvideMoreContent: null, convertReusedFlightRouterStateToRouteTree: null, convertRootFlightRouterStateToRouteTree: null, convertRouteTreeToFlightRouterState: null, createDetachedSegmentCacheEntry: null, createMetadataRouteTree: null, deprecated_requestOptimisticRouteCacheEntry: null, fetchInlinedSegmentsOnCacheMiss: null, fetchRouteOnCacheMiss: null, fetchSegmentOnCacheMiss: null, fetchSegmentPrefetchesUsingDynamicRequest: null, fulfillRouteCacheEntry: null, getCurrentRouteCacheVersion: null, getCurrentSegmentCacheVersion: null, getStaleAt: null, getStaleTimeMs: null, invalidateEntirePrefetchCache: null, invalidateRouteCacheEntries: null, invalidateSegmentCacheEntries: null, markRouteEntryAsDynamicRewrite: null, overwriteRevalidatingSegmentCacheEntry: null, pingInvalidationListeners: null, processRuntimePrefetchStream: null, readOrCreateRevalidatingSegmentEntry: null, readOrCreateRouteCacheEntry: null, readOrCreateSegmentCacheEntry: null, readRouteCacheEntry: null, readSegmentCacheEntry: null, stripIsPartialByte: null, upgradeToPendingSegment: null, upsertSegmentEntry: null, waitForSegmentCacheEntry: null, writeDynamicRenderResponseIntoCache: null, writeRouteIntoCache: null, writeStaticStageResponseIntoCache: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { EntryStatus: function() { return EntryStatus; }, attemptToFulfillDynamicSegmentFromBFCache: function() { return attemptToFulfillDynamicSegmentFromBFCache; }, attemptToUpgradeSegmentFromBFCache: function() { return attemptToUpgradeSegmentFromBFCache; }, canNewFetchStrategyProvideMoreContent: function() { return canNewFetchStrategyProvideMoreContent; }, convertReusedFlightRouterStateToRouteTree: function() { return convertReusedFlightRouterStateToRouteTree; }, convertRootFlightRouterStateToRouteTree: function() { return convertRootFlightRouterStateToRouteTree; }, convertRouteTreeToFlightRouterState: function() { return convertRouteTreeToFlightRouterState; }, createDetachedSegmentCacheEntry: function() { return createDetachedSegmentCacheEntry; }, createMetadataRouteTree: function() { return createMetadataRouteTree; }, deprecated_requestOptimisticRouteCacheEntry: function() { return deprecated_requestOptimisticRouteCacheEntry; }, fetchInlinedSegmentsOnCacheMiss: function() { return fetchInlinedSegmentsOnCacheMiss; }, fetchRouteOnCacheMiss: function() { return fetchRouteOnCacheMiss; }, fetchSegmentOnCacheMiss: function() { return fetchSegmentOnCacheMiss; }, fetchSegmentPrefetchesUsingDynamicRequest: function() { return fetchSegmentPrefetchesUsingDynamicRequest; }, fulfillRouteCacheEntry: function() { return fulfillRouteCacheEntry; }, getCurrentRouteCacheVersion: function() { return getCurrentRouteCacheVersion; }, getCurrentSegmentCacheVersion: function() { return getCurrentSegmentCacheVersion; }, getStaleAt: function() { return getStaleAt; }, getStaleTimeMs: function() { return getStaleTimeMs; }, invalidateEntirePrefetchCache: function() { return invalidateEntirePrefetchCache; }, invalidateRouteCacheEntries: function() { return invalidateRouteCacheEntries; }, invalidateSegmentCacheEntries: function() { return invalidateSegmentCacheEntries; }, markRouteEntryAsDynamicRewrite: function() { return markRouteEntryAsDynamicRewrite; }, overwriteRevalidatingSegmentCacheEntry: function() { return overwriteRevalidatingSegmentCacheEntry; }, pingInvalidationListeners: function() { return pingInvalidationListeners; }, processRuntimePrefetchStream: function() { return processRuntimePrefetchStream; }, readOrCreateRevalidatingSegmentEntry: function() { return readOrCreateRevalidatingSegmentEntry; }, readOrCreateRouteCacheEntry: function() { return readOrCreateRouteCacheEntry; }, readOrCreateSegmentCacheEntry: function() { return readOrCreateSegmentCacheEntry; }, readRouteCacheEntry: function() { return readRouteCacheEntry; }, readSegmentCacheEntry: function() { return readSegmentCacheEntry; }, stripIsPartialByte: function() { return stripIsPartialByte; }, upgradeToPendingSegment: function() { return upgradeToPendingSegment; }, upsertSegmentEntry: function() { return upsertSegmentEntry; }, waitForSegmentCacheEntry: function() { return waitForSegmentCacheEntry; }, writeDynamicRenderResponseIntoCache: function() { return writeDynamicRenderResponseIntoCache; }, writeRouteIntoCache: function() { return writeRouteIntoCache; }, writeStaticStageResponseIntoCache: function() { return writeStaticStageResponseIntoCache; } }); const _varyparamsdecoding = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment-cache/vary-params-decoding.js [app-ssr] (ecmascript)"); const _approuterheaders = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/app-router-headers.js [app-ssr] (ecmascript)"); const _fetchserverresponse = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js [app-ssr] (ecmascript)"); const _scheduler = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/scheduler.js [app-ssr] (ecmascript)"); const _varypath = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/vary-path.js [app-ssr] (ecmascript)"); const _createhreffromurl = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/create-href-from-url.js [app-ssr] (ecmascript)"); const _cachekey = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-key.js [app-ssr] (ecmascript)"); const _routeparams = __turbopack_context__.r("[project]/node_modules/next/dist/client/route-params.js [app-ssr] (ecmascript)"); const _cachemap = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-map.js [app-ssr] (ecmascript)"); const _segmentvalueencoding = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.js [app-ssr] (ecmascript)"); const _flightdatahelpers = __turbopack_context__.r("[project]/node_modules/next/dist/client/flight-data-helpers.js [app-ssr] (ecmascript)"); const _navigatereducer = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/reducers/navigate-reducer.js [app-ssr] (ecmascript)"); const _links = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/links.js [app-ssr] (ecmascript)"); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _promisewithresolvers = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/promise-with-resolvers.js [app-ssr] (ecmascript)"); const _bfcache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/bfcache.js [app-ssr] (ecmascript)"); const _optimisticroutes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/optimistic-routes.js [app-ssr] (ecmascript)"); const _navigation = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation.js [app-ssr] (ecmascript)"); const _navigationbuildid = __turbopack_context__.r("[project]/node_modules/next/dist/client/navigation-build-id.js [app-ssr] (ecmascript)"); const _constants = __turbopack_context__.r("[project]/node_modules/next/dist/lib/constants.js [app-ssr] (ecmascript)"); function getStaleTimeMs(staleTimeSeconds) { return Math.max(staleTimeSeconds, 30) * 1000; } var EntryStatus = /*#__PURE__*/ function(EntryStatus) { EntryStatus[EntryStatus["Empty"] = 0] = "Empty"; EntryStatus[EntryStatus["Pending"] = 1] = "Pending"; EntryStatus[EntryStatus["Fulfilled"] = 2] = "Fulfilled"; EntryStatus[EntryStatus["Rejected"] = 3] = "Rejected"; return EntryStatus; }({}); const isOutputExportMode = ("TURBOPACK compile-time value", "development") === 'production' && ("TURBOPACK compile-time value", void 0) === 'export'; const MetadataOnlyRequestTree = [ '', {}, null, 'metadata-only' ]; let routeCacheMap = (0, _cachemap.createCacheMap)(); let segmentCacheMap = (0, _cachemap.createCacheMap)(); // All invalidation listeners for the whole cache are tracked in single set. // Since we don't yet support tag or path-based invalidation, there's no point // tracking them any more granularly than this. Once we add granular // invalidation, that may change, though generally the model is to just notify // the listeners and allow the caller to poll the prefetch cache with a new // prefetch task if desired. let invalidationListeners = null; // Incrementing counters used to track cache invalidations. Route and segment // caches have separate versions so they can be invalidated independently. // Invalidation does not eagerly evict anything from the cache; entries are // lazily evicted when read. let currentRouteCacheVersion = 0; let currentSegmentCacheVersion = 0; function getCurrentRouteCacheVersion() { return currentRouteCacheVersion; } function getCurrentSegmentCacheVersion() { return currentSegmentCacheVersion; } function invalidateEntirePrefetchCache(nextUrl, tree) { currentRouteCacheVersion++; currentSegmentCacheVersion++; (0, _links.pingVisibleLinks)(nextUrl, tree); pingInvalidationListeners(nextUrl, tree); } function invalidateRouteCacheEntries(nextUrl, tree) { currentRouteCacheVersion++; (0, _links.pingVisibleLinks)(nextUrl, tree); pingInvalidationListeners(nextUrl, tree); } function invalidateSegmentCacheEntries(nextUrl, tree) { currentSegmentCacheVersion++; (0, _links.pingVisibleLinks)(nextUrl, tree); pingInvalidationListeners(nextUrl, tree); } function attachInvalidationListener(task) { // This function is called whenever a prefetch task reads a cache entry. If // the task has an onInvalidate function associated with it — i.e. the one // optionally passed to router.prefetch(onInvalidate) — then we attach that // listener to the every cache entry that the task reads. Then, if an entry // is invalidated, we call the function. if (task.onInvalidate !== null) { if (invalidationListeners === null) { invalidationListeners = new Set([ task ]); } else { invalidationListeners.add(task); } } } function notifyInvalidationListener(task) { const onInvalidate = task.onInvalidate; if (onInvalidate !== null) { // Clear the callback from the task object to guarantee it's not called more // than once. task.onInvalidate = null; // This is a user-space function, so we must wrap in try/catch. try { onInvalidate(); } catch (error) { if (typeof reportError === 'function') { reportError(error); } else { console.error(error); } } } } function pingInvalidationListeners(nextUrl, tree) { // The rough equivalent of pingVisibleLinks, but for onInvalidate callbacks. // This is called when the Next-Url or the base tree changes, since those // may affect the result of a prefetch task. It's also called after a // cache invalidation. if (invalidationListeners !== null) { const tasks = invalidationListeners; invalidationListeners = null; for (const task of tasks){ if ((0, _scheduler.isPrefetchTaskDirty)(task, nextUrl, tree)) { notifyInvalidationListener(task); } } } } function readRouteCacheEntry(now, key) { const varyPath = (0, _varypath.getRouteVaryPath)(key.pathname, key.search, key.nextUrl); const isRevalidation = false; const existingEntry = (0, _cachemap.getFromCacheMap)(now, getCurrentRouteCacheVersion(), routeCacheMap, varyPath, isRevalidation); if (existingEntry !== null) { return existingEntry; } // No cache hit. Attempt to construct from template using the new // optimistic routing mechanism (pattern-based matching). if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; return null; } function readSegmentCacheEntry(now, varyPath) { const isRevalidation = false; return (0, _cachemap.getFromCacheMap)(now, getCurrentSegmentCacheVersion(), segmentCacheMap, varyPath, isRevalidation); } function readRevalidatingSegmentCacheEntry(now, varyPath) { const isRevalidation = true; return (0, _cachemap.getFromCacheMap)(now, getCurrentSegmentCacheVersion(), segmentCacheMap, varyPath, isRevalidation); } function waitForSegmentCacheEntry(pendingEntry) { // Because the entry is pending, there's already a in-progress request. // Attach a promise to the entry that will resolve when the server responds. let promiseWithResolvers = pendingEntry.promise; if (promiseWithResolvers === null) { promiseWithResolvers = pendingEntry.promise = (0, _promisewithresolvers.createPromiseWithResolvers)(); } else { // There's already a promise we can use } return promiseWithResolvers.promise; } function createDetachedRouteCacheEntry() { return { canonicalUrl: null, status: 0, blockedTasks: null, tree: null, metadata: null, // This is initialized to true because we don't know yet whether the route // could be intercepted. It's only set to false once we receive a response // from the server. couldBeIntercepted: true, // Similarly, we don't yet know if the route supports PPR. supportsPerSegmentPrefetching: false, renderedSearch: null, // Map-related fields ref: null, size: 0, // Since this is an empty entry, there's no reason to ever evict it. It will // be updated when the data is populated. staleAt: Infinity, version: getCurrentRouteCacheVersion() }; } function readOrCreateRouteCacheEntry(now, task, key) { attachInvalidationListener(task); const existingEntry = readRouteCacheEntry(now, key); if (existingEntry !== null) { return existingEntry; } // Create a pending entry and add it to the cache. const pendingEntry = createDetachedRouteCacheEntry(); const varyPath = (0, _varypath.getRouteVaryPath)(key.pathname, key.search, key.nextUrl); const isRevalidation = false; (0, _cachemap.setInCacheMap)(routeCacheMap, varyPath, pendingEntry, isRevalidation); return pendingEntry; } function deprecated_requestOptimisticRouteCacheEntry(now, requestedUrl, nextUrl) { // This function is called during a navigation when there was no matching // route tree in the prefetch cache. Before de-opting to a blocking, // unprefetched navigation, we will first attempt to construct an "optimistic" // route tree by checking the cache for similar routes. // // Check if there's a route with the same pathname, but with different // search params. We can then base our optimistic route tree on this entry. // // Conceptually, we are simulating what would happen if we did perform a // prefetch the requested URL, under the assumption that the server will // not redirect or rewrite the request in a different manner than the // base route tree. This assumption might not hold, in which case we'll have // to recover when we perform the dynamic navigation request. However, this // is what would happen if a route were dynamically rewritten/redirected // in between the prefetch and the navigation. So the logic needs to exist // to handle this case regardless. // Look for a route with the same pathname, but with an empty search string. // TODO: There's nothing inherently special about the empty search string; // it's chosen somewhat arbitrarily, with the rationale that it's the most // likely one to exist. But we should update this to match _any_ search // string. The plan is to generalize this logic alongside other improvements // related to "fallback" cache entries. const requestedSearch = requestedUrl.search; if (requestedSearch === '') { // The caller would have already checked if a route with an empty search // string is in the cache. So we can bail out here. return null; } const urlWithoutSearchParams = new URL(requestedUrl); urlWithoutSearchParams.search = ''; const routeWithNoSearchParams = readRouteCacheEntry(now, (0, _cachekey.createCacheKey)(urlWithoutSearchParams.href, nextUrl)); if (routeWithNoSearchParams === null || routeWithNoSearchParams.status !== 2) { // Bail out of constructing an optimistic route tree. This will result in // a blocking, unprefetched navigation. return null; } // Now we have a base route tree we can "patch" with our optimistic values. // Optimistically assume that redirects for the requested pathname do // not vary on the search string. Therefore, if the base route was // redirected to a different search string, then the optimistic route // should be redirected to the same search string. Otherwise, we use // the requested search string. const canonicalUrlForRouteWithNoSearchParams = new URL(routeWithNoSearchParams.canonicalUrl, requestedUrl.origin); const optimisticCanonicalSearch = canonicalUrlForRouteWithNoSearchParams.search !== '' ? canonicalUrlForRouteWithNoSearchParams.search : requestedSearch; // Similarly, optimistically assume that rewrites for the requested // pathname do not vary on the search string. Therefore, if the base // route was rewritten to a different search string, then the optimistic // route should be rewritten to the same search string. Otherwise, we use // the requested search string. const optimisticRenderedSearch = routeWithNoSearchParams.renderedSearch !== '' ? routeWithNoSearchParams.renderedSearch : requestedSearch; const optimisticUrl = new URL(routeWithNoSearchParams.canonicalUrl, location.origin); optimisticUrl.search = optimisticCanonicalSearch; const optimisticCanonicalUrl = (0, _createhreffromurl.createHrefFromUrl)(optimisticUrl); const optimisticRouteTree = deprecated_createOptimisticRouteTree(routeWithNoSearchParams.tree, optimisticRenderedSearch); const optimisticMetadataTree = deprecated_createOptimisticRouteTree(routeWithNoSearchParams.metadata, optimisticRenderedSearch); // Clone the base route tree, and override the relevant fields with our // optimistic values. const optimisticEntry = { canonicalUrl: optimisticCanonicalUrl, status: 2, // This isn't cloned because it's instance-specific blockedTasks: null, tree: optimisticRouteTree, metadata: optimisticMetadataTree, couldBeIntercepted: routeWithNoSearchParams.couldBeIntercepted, supportsPerSegmentPrefetching: routeWithNoSearchParams.supportsPerSegmentPrefetching, hasDynamicRewrite: routeWithNoSearchParams.hasDynamicRewrite, // Override the rendered search with the optimistic value. renderedSearch: optimisticRenderedSearch, // Map-related fields ref: null, size: 0, staleAt: routeWithNoSearchParams.staleAt, version: routeWithNoSearchParams.version }; // Do not insert this entry into the cache. It only exists so we can // perform the current navigation. Just return it to the caller. return optimisticEntry; } function deprecated_createOptimisticRouteTree(tree, newRenderedSearch) { // Create a new route tree that identical to the original one except for // the rendered search string, which is contained in the vary path. let clonedSlots = null; const originalSlots = tree.slots; if (originalSlots !== null) { clonedSlots = {}; for(const parallelRouteKey in originalSlots){ const childTree = originalSlots[parallelRouteKey]; clonedSlots[parallelRouteKey] = deprecated_createOptimisticRouteTree(childTree, newRenderedSearch); } } // We only need to clone the vary path if the route is a page. if (tree.isPage) { return { requestKey: tree.requestKey, segment: tree.segment, refreshState: tree.refreshState, varyPath: (0, _varypath.clonePageVaryPathWithNewSearchParams)(tree.varyPath, newRenderedSearch), isPage: true, slots: clonedSlots, prefetchHints: tree.prefetchHints }; } return { requestKey: tree.requestKey, segment: tree.segment, refreshState: tree.refreshState, varyPath: tree.varyPath, isPage: false, slots: clonedSlots, prefetchHints: tree.prefetchHints }; } function readOrCreateSegmentCacheEntry(now, fetchStrategy, tree) { const existingEntry = readSegmentCacheEntry(now, tree.varyPath); if (existingEntry !== null) { return existingEntry; } // Create a pending entry and add it to the cache. The stale time is set to a // default value; the actual stale time will be set when the entry is // fulfilled with data from the server response. const varyPathForRequest = (0, _varypath.getSegmentVaryPathForRequest)(fetchStrategy, tree); const pendingEntry = createDetachedSegmentCacheEntry(now); const isRevalidation = false; (0, _cachemap.setInCacheMap)(segmentCacheMap, varyPathForRequest, pendingEntry, isRevalidation); return pendingEntry; } function readOrCreateRevalidatingSegmentEntry(now, fetchStrategy, tree) { // This function is called when we've already confirmed that a particular // segment is cached, but we want to perform another request anyway in case it // returns more complete and/or fresher data than we already have. The logic // for deciding whether to replace the existing entry is handled elsewhere; // this function just handles retrieving a cache entry that we can use to // track the revalidation. // // The reason revalidations are stored in the cache is because we need to be // able to dedupe multiple revalidation requests. The reason they have to be // handled specially is because we shouldn't overwrite a "normal" entry if // one exists at the same keypath. So, for each internal cache location, there // is a special "revalidation" slot that is used solely for this purpose. // // You can think of it as if all the revalidation entries were stored in a // separate cache map from the canonical entries, and then transfered to the // canonical cache map once the request is complete — this isn't how it's // actually implemented, since it's more efficient to store them in the same // data structure as the normal entries, but that's how it's modeled // conceptually. // TODO: Once we implement Fallback behavior for params, where an entry is // re-keyed based on response information, we'll need to account for the // possibility that the keypath of the previous entry is more generic than // the keypath of the revalidating entry. In other words, the server could // return a less generic entry upon revalidation. For now, though, this isn't // a concern because the keypath is based solely on the prefetch strategy, // not on data contained in the response. const existingEntry = readRevalidatingSegmentCacheEntry(now, tree.varyPath); if (existingEntry !== null) { return existingEntry; } // Create a pending entry and add it to the cache. The stale time is set to a // default value; the actual stale time will be set when the entry is // fulfilled with data from the server response. const varyPathForRequest = (0, _varypath.getSegmentVaryPathForRequest)(fetchStrategy, tree); const pendingEntry = createDetachedSegmentCacheEntry(now); const isRevalidation = true; (0, _cachemap.setInCacheMap)(segmentCacheMap, varyPathForRequest, pendingEntry, isRevalidation); return pendingEntry; } function overwriteRevalidatingSegmentCacheEntry(now, fetchStrategy, tree) { // This function is called when we've already decided to replace an existing // revalidation entry. Create a new entry and write it into the cache, // overwriting the previous value. The stale time is set to a default value; // the actual stale time will be set when the entry is fulfilled with data // from the server response. const varyPathForRequest = (0, _varypath.getSegmentVaryPathForRequest)(fetchStrategy, tree); const pendingEntry = createDetachedSegmentCacheEntry(now); const isRevalidation = true; (0, _cachemap.setInCacheMap)(segmentCacheMap, varyPathForRequest, pendingEntry, isRevalidation); return pendingEntry; } function upsertSegmentEntry(now, varyPath, candidateEntry) { // We have a new entry that has not yet been inserted into the cache. Before // we do so, we need to confirm whether it takes precedence over the existing // entry (if one exists). // TODO: We should not upsert an entry if its key was invalidated in the time // since the request was made. We can do that by passing the "owner" entry to // this function and confirming it's the same as `existingEntry`. if ((0, _cachemap.isValueExpired)(now, getCurrentSegmentCacheVersion(), candidateEntry)) { // The entry is expired. We cannot upsert it. return null; } const existingEntry = readSegmentCacheEntry(now, varyPath); if (existingEntry !== null) { // Don't replace a more specific segment with a less-specific one. A case where this // might happen is if the existing segment was fetched via // ``. if (// than the segment we already have in the cache, so it can't have more content. candidateEntry.fetchStrategy !== existingEntry.fetchStrategy && !canNewFetchStrategyProvideMoreContent(existingEntry.fetchStrategy, candidateEntry.fetchStrategy) || // The existing entry isn't partial, but the new one is. // (TODO: can this be true if `candidateEntry.fetchStrategy >= existingEntry.fetchStrategy`?) !existingEntry.isPartial && candidateEntry.isPartial) { // We're going to leave revalidating entry in the cache so that it doesn't // get revalidated again unnecessarily. Downgrade the Fulfilled entry to // Rejected and null out the data so it can be garbage collected. We leave // `staleAt` intact to prevent subsequent revalidation attempts only until // the entry expires. const rejectedEntry = candidateEntry; rejectedEntry.status = 3; rejectedEntry.rsc = null; return null; } // Evict the existing entry from the cache. (0, _cachemap.deleteFromCacheMap)(existingEntry); } const isRevalidation = false; (0, _cachemap.setInCacheMap)(segmentCacheMap, varyPath, candidateEntry, isRevalidation); return candidateEntry; } function createDetachedSegmentCacheEntry(now) { // Default stale time for pending segment cache entries. The actual stale time // is set when the entry is fulfilled with data from the server response. const staleAt = now + 30 * 1000; const emptyEntry = { status: 0, // Default to assuming the fetch strategy will be PPR. This will be updated // when a fetch is actually initiated. fetchStrategy: _types.FetchStrategy.PPR, rsc: null, isPartial: true, promise: null, // Map-related fields ref: null, size: 0, staleAt, version: 0 }; return emptyEntry; } function upgradeToPendingSegment(emptyEntry, fetchStrategy) { const pendingEntry = emptyEntry; pendingEntry.status = 1; pendingEntry.fetchStrategy = fetchStrategy; if (fetchStrategy === _types.FetchStrategy.Full) { // We can assume the response will contain the full segment data. Set this // to false so we know it's OK to omit this segment from any navigation // requests that may happen while the data is still pending. pendingEntry.isPartial = false; } // Set the version here, since this is right before the request is initiated. // The next time the segment cache version is incremented, the entry will // effectively be evicted. This happens before initiating the request, rather // than when receiving the response, because it's guaranteed to happen // before the data is read on the server. pendingEntry.version = getCurrentSegmentCacheVersion(); return pendingEntry; } function attemptToFulfillDynamicSegmentFromBFCache(now, segment, tree) { // Attempts to fulfill an empty segment cache entry using data from the // bfcache. This is only valid during a Full prefetch (i.e. one that includes // dynamic data), because the bfcache stores data from navigations which // always include dynamic data. // We always use the canonical vary path when checking the bfcache. This is // the same operation we'd use to access the cache during a // regular navigation. const varyPath = tree.varyPath; // Read from the BFCache without expiring it (pass -1). We check freshness // ourselves using navigatedAt, because the BFCache's staleAt may have been // overridden by a per-page unstable_dynamicStaleTime and can't be used to // derive the original request time. const bfcacheEntry = (0, _bfcache.readFromBFCache)(varyPath); if (bfcacheEntry !== null) { // The stale time for dynamic prefetches (default: 5 mins) is different // from the stale time for regular navigations (default: 0 secs). Use // navigatedAt to compute the correct expiry for prefetch purposes. const dynamicPrefetchStaleAt = bfcacheEntry.navigatedAt + _navigatereducer.STATIC_STALETIME_MS; if (now > dynamicPrefetchStaleAt) { return null; } const pendingSegment = upgradeToPendingSegment(segment, _types.FetchStrategy.Full); const isPartial = false; return fulfillSegmentCacheEntry(pendingSegment, bfcacheEntry.rsc, dynamicPrefetchStaleAt, isPartial); } return null; } function attemptToUpgradeSegmentFromBFCache(now, tree) { const varyPath = tree.varyPath; const bfcacheEntry = (0, _bfcache.readFromBFCache)(varyPath); if (bfcacheEntry !== null) { const dynamicPrefetchStaleAt = bfcacheEntry.navigatedAt + _navigatereducer.STATIC_STALETIME_MS; if (now > dynamicPrefetchStaleAt) { return null; } const pendingSegment = upgradeToPendingSegment(createDetachedSegmentCacheEntry(now), _types.FetchStrategy.Full); const isPartial = false; const newEntry = fulfillSegmentCacheEntry(pendingSegment, bfcacheEntry.rsc, dynamicPrefetchStaleAt, isPartial); const segmentVaryPath = (0, _varypath.getSegmentVaryPathForRequest)(_types.FetchStrategy.Full, tree); const upserted = upsertSegmentEntry(now, segmentVaryPath, newEntry); if (upserted !== null && upserted.status === 2) { return upserted; } } return null; } function pingBlockedTasks(entry) { const blockedTasks = entry.blockedTasks; if (blockedTasks !== null) { for (const task of blockedTasks){ (0, _scheduler.pingPrefetchTask)(task); } entry.blockedTasks = null; } } function createMetadataRouteTree(metadataVaryPath) { // The Head is not actually part of the route tree, but other than that, it's // fetched and cached like a segment. Some functions expect a RouteTree // object, so rather than fork the logic in all those places, we use this // "fake" one. const metadata = { requestKey: _segmentvalueencoding.HEAD_REQUEST_KEY, segment: _segmentvalueencoding.HEAD_REQUEST_KEY, refreshState: null, varyPath: metadataVaryPath, // The metadata isn't really a "page" (though it isn't really a "segment" // either) but for the purposes of how this field is used, it behaves like // one. If this logic ever gets more complex we can change this to an enum. isPage: true, slots: null, prefetchHints: 0 }; return metadata; } function fulfillRouteCacheEntry(now, entry, tree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching) { // Get the rendered search from the vary path const renderedSearch = (0, _varypath.getRenderedSearchFromVaryPath)(metadataVaryPath) ?? ''; const fulfilledEntry = entry; fulfilledEntry.status = 2; fulfilledEntry.tree = tree; fulfilledEntry.metadata = createMetadataRouteTree(metadataVaryPath); // Route structure is essentially static — it only changes on deploy. // Always use the static stale time. // NOTE: An exception is rewrites/redirects in middleware or proxy, which can // change routes dynamically. We have other strategies for handling those. fulfilledEntry.staleAt = now + _navigatereducer.STATIC_STALETIME_MS; fulfilledEntry.couldBeIntercepted = couldBeIntercepted; fulfilledEntry.canonicalUrl = canonicalUrl; fulfilledEntry.renderedSearch = renderedSearch; fulfilledEntry.supportsPerSegmentPrefetching = supportsPerSegmentPrefetching; fulfilledEntry.hasDynamicRewrite = false; pingBlockedTasks(entry); return fulfilledEntry; } function writeRouteIntoCache(now, pathname, nextUrl, tree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching) { const pendingEntry = createDetachedRouteCacheEntry(); const fulfilledEntry = fulfillRouteCacheEntry(now, pendingEntry, tree, metadataVaryPath, couldBeIntercepted, canonicalUrl, supportsPerSegmentPrefetching); const renderedSearch = fulfilledEntry.renderedSearch; const varyPath = (0, _varypath.getFulfilledRouteVaryPath)(pathname, renderedSearch, nextUrl, couldBeIntercepted); const isRevalidation = false; (0, _cachemap.setInCacheMap)(routeCacheMap, varyPath, fulfilledEntry, isRevalidation); return fulfilledEntry; } function markRouteEntryAsDynamicRewrite(entry) { entry.hasDynamicRewrite = true; // Note: The caller is responsible for also calling invalidateRouteCacheEntries // to invalidate other entries that may have been derived from this template // before we knew it had a dynamic rewrite. } function fulfillSegmentCacheEntry(segmentCacheEntry, rsc, staleAt, isPartial) { const fulfilledEntry = segmentCacheEntry; fulfilledEntry.status = 2; fulfilledEntry.rsc = rsc; fulfilledEntry.staleAt = staleAt; fulfilledEntry.isPartial = isPartial; // Resolve any listeners that were waiting for this data. if (segmentCacheEntry.promise !== null) { segmentCacheEntry.promise.resolve(fulfilledEntry); // Free the promise for garbage collection. fulfilledEntry.promise = null; } return fulfilledEntry; } function rejectRouteCacheEntry(entry, staleAt) { const rejectedEntry = entry; rejectedEntry.status = 3; rejectedEntry.staleAt = staleAt; pingBlockedTasks(entry); } function rejectSegmentCacheEntry(entry, staleAt) { const rejectedEntry = entry; rejectedEntry.status = 3; rejectedEntry.staleAt = staleAt; if (entry.promise !== null) { // NOTE: We don't currently propagate the reason the prefetch was canceled // but we could by accepting a `reason` argument. entry.promise.resolve(null); entry.promise = null; } } function convertRootTreePrefetchToRouteTree(rootTree, renderedPathname, renderedSearch, acc) { // Remove trailing and leading slashes const pathnameParts = renderedPathname.split('/').filter((p)=>p !== ''); const index = 0; const rootSegment = _segmentvalueencoding.ROOT_SEGMENT_REQUEST_KEY; return convertTreePrefetchToRouteTree(rootTree.tree, rootSegment, null, _segmentvalueencoding.ROOT_SEGMENT_REQUEST_KEY, pathnameParts, index, renderedSearch, acc); } function convertTreePrefetchToRouteTree(prefetch, segment, partialVaryPath, requestKey, pathnameParts, pathnamePartsIndex, renderedSearch, acc) { // Converts the route tree sent by the server into the format used by the // cache. The cached version of the tree includes additional fields, such as a // cache key for each segment. Since this is frequently accessed, we compute // it once instead of on every access. This same cache key is also used to // request the segment from the server. let slots = null; let isPage; let varyPath; const prefetchSlots = prefetch.slots; if (prefetchSlots !== null) { isPage = false; varyPath = (0, _varypath.finalizeLayoutVaryPath)(requestKey, partialVaryPath); slots = {}; for(let parallelRouteKey in prefetchSlots){ const childPrefetch = prefetchSlots[parallelRouteKey]; const childSegmentName = childPrefetch.name; const childParam = childPrefetch.param; let childDoesAppearInURL; let childSegment; let childPartialVaryPath; if (childParam !== null) { // This segment is parameterized. Get the param from the pathname. const childParamValue = (0, _routeparams.parseDynamicParamFromURLPart)(childParam.type, pathnameParts, pathnamePartsIndex); // Assign a cache key to the segment, based on the param value. In the // pre-Segment Cache implementation, the server computes this and sends // it in the body of the response. In the Segment Cache implementation, // the server sends an empty string and we fill it in here. // TODO: We're intentionally not adding the search param to page // segments here; it's tracked separately and added back during a read. // This would clearer if we waited to construct the segment until it's // read from the cache, since that's effectively what we're // doing anyway. const childParamKey = // cacheComponents is enabled. childParam.key !== null ? childParam.key : (0, _routeparams.getCacheKeyForDynamicParam)(childParamValue, ''); childPartialVaryPath = (0, _varypath.appendLayoutVaryPath)(partialVaryPath, childParamKey, childSegmentName); childSegment = [ childSegmentName, childParamKey, childParam.type, childParam.siblings ]; childDoesAppearInURL = true; } else { // This segment does not have a param. Inherit the partial vary path of // the parent. childPartialVaryPath = partialVaryPath; childSegment = childSegmentName; childDoesAppearInURL = (0, _routeparams.doesStaticSegmentAppearInURL)(childSegmentName); } // Only increment the index if the segment appears in the URL. If it's a // "virtual" segment, like a route group, it remains the same. const childPathnamePartsIndex = childDoesAppearInURL ? pathnamePartsIndex + 1 : pathnamePartsIndex; const childRequestKeyPart = (0, _segmentvalueencoding.createSegmentRequestKeyPart)(childSegment); const childRequestKey = (0, _segmentvalueencoding.appendSegmentRequestKeyPart)(requestKey, parallelRouteKey, childRequestKeyPart); slots[parallelRouteKey] = convertTreePrefetchToRouteTree(childPrefetch, childSegment, childPartialVaryPath, childRequestKey, pathnameParts, childPathnamePartsIndex, renderedSearch, acc); } } else { if (requestKey.endsWith(_segment.PAGE_SEGMENT_KEY)) { // This is a page segment. isPage = true; varyPath = (0, _varypath.finalizePageVaryPath)(requestKey, renderedSearch, partialVaryPath); // The metadata "segment" is not part the route tree, but it has the same // conceptual params as a page segment. Write the vary path into the // accumulator object. If there are multiple parallel pages, we use the // first one. Which page we choose is arbitrary as long as it's // consistently the same one every time every time. See // finalizeMetadataVaryPath for more details. if (acc.metadataVaryPath === null) { acc.metadataVaryPath = (0, _varypath.finalizeMetadataVaryPath)(requestKey, renderedSearch, partialVaryPath); } } else { // This is a layout segment. isPage = false; varyPath = (0, _varypath.finalizeLayoutVaryPath)(requestKey, partialVaryPath); } } return { requestKey, segment, refreshState: null, // TODO: Cheating the type system here a bit because TypeScript can't tell // that the type of isPage and varyPath are consistent. The fix would be to // create separate constructors and call the appropriate one from each of // the branches above. Just seems a bit overkill only for one field so I'll // leave it as-is for now. If isPage were wrong it would break the behavior // and we'd catch it quickly, anyway. varyPath: varyPath, isPage: isPage, slots, prefetchHints: prefetch.prefetchHints }; } function convertRootFlightRouterStateToRouteTree(flightRouterState, renderedSearch, acc) { return convertFlightRouterStateToRouteTree(flightRouterState, _segmentvalueencoding.ROOT_SEGMENT_REQUEST_KEY, null, renderedSearch, acc); } function convertReusedFlightRouterStateToRouteTree(parentRouteTree, parallelRouteKey, flightRouterState, renderedSearch, acc) { // Create a RouteTree for a FlightRouterState that was reused from an older // route. This happens during a navigation when a parallel route slot does not // match the target route; we reuse whatever slot was already active. // Unlike a FlightRouterState, the RouteTree type contains backreferences to // the parent segments. Append the vary path to the parent's vary path. const parentPartialVaryPath = parentRouteTree.isPage ? (0, _varypath.getPartialPageVaryPath)(parentRouteTree.varyPath) : (0, _varypath.getPartialLayoutVaryPath)(parentRouteTree.varyPath); const segment = flightRouterState[0]; // And the request key. const parentRequestKey = parentRouteTree.requestKey; const requestKeyPart = (0, _segmentvalueencoding.createSegmentRequestKeyPart)(segment); const requestKey = (0, _segmentvalueencoding.appendSegmentRequestKeyPart)(parentRequestKey, parallelRouteKey, requestKeyPart); return convertFlightRouterStateToRouteTree(flightRouterState, requestKey, parentPartialVaryPath, renderedSearch, acc); } function convertFlightRouterStateToRouteTree(flightRouterState, requestKey, parentPartialVaryPath, parentRenderedSearch, acc) { const originalSegment = flightRouterState[0]; // If the FlightRouterState has a refresh state, then this segment is part of // an inactive parallel route. It has a different rendered search query than // the outer parent route. In order to construct the inactive route correctly, // we must restore the query that was originally used to render it. const compressedRefreshState = flightRouterState[2] ?? null; const refreshState = compressedRefreshState !== null ? { canonicalUrl: compressedRefreshState[0], renderedSearch: compressedRefreshState[1] } : null; const renderedSearch = refreshState !== null ? refreshState.renderedSearch : parentRenderedSearch; let segment; let partialVaryPath; let isPage; let varyPath; if (Array.isArray(originalSegment)) { isPage = false; const paramCacheKey = originalSegment[1]; const paramName = originalSegment[0]; partialVaryPath = (0, _varypath.appendLayoutVaryPath)(parentPartialVaryPath, paramCacheKey, paramName); varyPath = (0, _varypath.finalizeLayoutVaryPath)(requestKey, partialVaryPath); segment = originalSegment; } else { // This segment does not have a param. Inherit the partial vary path of // the parent. partialVaryPath = parentPartialVaryPath; if (requestKey.endsWith(_segment.PAGE_SEGMENT_KEY)) { // This is a page segment. isPage = true; // The navigation implementation expects the search params to be included // in the segment. However, in the case of a static response, the search // params are omitted. So the client needs to add them back in when reading // from the Segment Cache. // // For consistency, we'll do this for dynamic responses, too. // // TODO: We should move search params out of FlightRouterState and handle // them entirely on the client, similar to our plan for dynamic params. segment = _segment.PAGE_SEGMENT_KEY; varyPath = (0, _varypath.finalizePageVaryPath)(requestKey, renderedSearch, partialVaryPath); // The metadata "segment" is not part the route tree, but it has the same // conceptual params as a page segment. Write the vary path into the // accumulator object. If there are multiple parallel pages, we use the // first one. Which page we choose is arbitrary as long as it's // consistently the same one every time every time. See // finalizeMetadataVaryPath for more details. if (acc.metadataVaryPath === null) { acc.metadataVaryPath = (0, _varypath.finalizeMetadataVaryPath)(requestKey, renderedSearch, partialVaryPath); } } else { // This is a layout segment. isPage = false; segment = originalSegment; varyPath = (0, _varypath.finalizeLayoutVaryPath)(requestKey, partialVaryPath); } } let slots = null; const parallelRoutes = flightRouterState[1]; for(let parallelRouteKey in parallelRoutes){ const childRouterState = parallelRoutes[parallelRouteKey]; const childSegment = childRouterState[0]; // TODO: Eventually, the param values will not be included in the response // from the server. We'll instead fill them in on the client by parsing // the URL. This is where we'll do that. const childRequestKeyPart = (0, _segmentvalueencoding.createSegmentRequestKeyPart)(childSegment); const childRequestKey = (0, _segmentvalueencoding.appendSegmentRequestKeyPart)(requestKey, parallelRouteKey, childRequestKeyPart); const childTree = convertFlightRouterStateToRouteTree(childRouterState, childRequestKey, partialVaryPath, renderedSearch, acc); if (slots === null) { slots = { [parallelRouteKey]: childTree }; } else { slots[parallelRouteKey] = childTree; } } return { requestKey, segment, refreshState, // TODO: Cheating the type system here a bit because TypeScript can't tell // that the type of isPage and varyPath are consistent. The fix would be to // create separate constructors and call the appropriate one from each of // the branches above. Just seems a bit overkill only for one field so I'll // leave it as-is for now. If isPage were wrong it would break the behavior // and we'd catch it quickly, anyway. varyPath: varyPath, isPage: isPage, slots, prefetchHints: flightRouterState[4] ?? 0 }; } function convertRouteTreeToFlightRouterState(routeTree) { const parallelRoutes = {}; if (routeTree.slots !== null) { for(const parallelRouteKey in routeTree.slots){ parallelRoutes[parallelRouteKey] = convertRouteTreeToFlightRouterState(routeTree.slots[parallelRouteKey]); } } const flightRouterState = [ routeTree.segment, parallelRoutes, null, null ]; return flightRouterState; } async function fetchRouteOnCacheMiss(entry, key) { // This function is allowed to use async/await because it contains the actual // fetch that gets issued on a cache miss. Notice it writes the result to the // cache entry directly, rather than return data that is then written by // the caller. const pathname = key.pathname; const search = key.search; const nextUrl = key.nextUrl; const segmentPath = '/_tree'; const headers = { [_approuterheaders.RSC_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER]: segmentPath }; if (nextUrl !== null) { headers[_approuterheaders.NEXT_URL] = nextUrl; } // Tell the server to perform a static pre-render for the Instant Navigation // Testing API. Static pre-renders don't normally happen during development. addInstantPrefetchHeaderIfLocked(headers); try { const url = new URL(pathname + search, location.origin); let response; let urlAfterRedirects; if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; else { // "Server" mode. We can use request headers instead of the pathname. // TODO: The eventual plan is to get rid of our custom request headers and // encode everything into the URL, using a similar strategy to the // "output: export" block above. response = await fetchPrefetchResponse(url, headers); urlAfterRedirects = response !== null && response.redirected ? new URL(response.url) : url; } if (!response || !response.ok || // 204 is a Cache miss. Though theoretically this shouldn't happen when // PPR is enabled, because we always respond to route tree requests, even // if it needs to be blockingly generated on demand. response.status === 204 || !response.body) { // Server responded with an error, or with a miss. We should still cache // the response, but we can try again after 10 seconds. rejectRouteCacheEntry(entry, Date.now() + 10 * 1000); return null; } // TODO: The canonical URL is the href without the origin. I think // historically the reason for this is because the initial canonical URL // gets passed as a prop to the top-level React component, which means it // needs to be computed during SSR. If it were to include the origin, it // would need to always be same as location.origin on the client, to prevent // a hydration mismatch. To sidestep this complexity, we omit the origin. // // However, since this is neither a native URL object nor a fully qualified // URL string, we need to be careful about how we use it. To prevent subtle // mistakes, we should create a special type for it, instead of just string. // Or, we should just use a (readonly) URL object instead. The type of the // prop that we pass to seed the initial state does not need to be the same // type as the state itself. const canonicalUrl = (0, _createhreffromurl.createHrefFromUrl)(urlAfterRedirects); // Check whether the response varies based on the Next-Url header. const varyHeader = response.headers.get('vary'); const couldBeIntercepted = varyHeader !== null && varyHeader.includes(_approuterheaders.NEXT_URL); // TODO: The `closed` promise was originally used to track when a streaming // network connection closes, so the scheduler could limit concurrent // connections. Now that prefetch responses are buffered, `closed` is // resolved immediately after buffering — before the outer function even // returns. This mechanism is only still meaningful for dynamic (Full) // prefetches, which use incremental streaming. Consider removing the // `closed` plumbing for buffered prefetch paths. const closed = (0, _promisewithresolvers.createPromiseWithResolvers)(); // This checks whether the response was served from the per-segment cache, // rather than the old prefetching flow. If it fails, it implies that PPR // is disabled on this route. const routeIsPPREnabled = response.headers.get(_approuterheaders.NEXT_DID_POSTPONE_HEADER) === '2' || // In output: "export" mode, we can't rely on response headers. But if we // receive a well-formed response, we can assume it's a static response, // because all data is static in this mode. isOutputExportMode; if (routeIsPPREnabled) { const { stream: prefetchStream, size: responseSize } = await createNonTaskyPrefetchResponseStream(response.body); closed.resolve(); (0, _cachemap.setSizeInCacheMap)(entry, responseSize); const serverData = await (0, _fetchserverresponse.createFromNextReadableStream)(prefetchStream, headers, { allowPartialStream: true }); if ((response.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? serverData.buildId) !== (0, _navigationbuildid.getNavigationBuildId)()) { // The server build does not match the client. Treat as a 404. During // an actual navigation, the router will trigger an MPA navigation. // TODO: We should cache the fact that this is an MPA navigation. rejectRouteCacheEntry(entry, Date.now() + 10 * 1000); return null; } // Get the params that were used to render the target page. These may // be different from the params in the request URL, if the page // was rewritten. const renderedPathname = (0, _routeparams.getRenderedPathname)(response); const renderedSearch = (0, _routeparams.getRenderedSearch)(response); // Convert the server-sent data into the RouteTree format used by the // client cache. // // During this traversal, we accumulate additional data into this // "accumulator" object. const acc = { metadataVaryPath: null }; const routeTree = convertRootTreePrefetchToRouteTree(serverData, renderedPathname, renderedSearch, acc); const metadataVaryPath = acc.metadataVaryPath; if (metadataVaryPath === null) { rejectRouteCacheEntry(entry, Date.now() + 10 * 1000); return null; } (0, _optimisticroutes.discoverKnownRoute)(Date.now(), pathname, nextUrl, entry, routeTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, routeIsPPREnabled, false // hasDynamicRewrite ); } else { // PPR is not enabled for this route. The server responds with a // different format (FlightRouterState) that we need to convert. // TODO: We will unify the responses eventually. I'm keeping the types // separate for now because FlightRouterState has so many // overloaded concerns. const { stream: prefetchStream, size: responseSize } = await createNonTaskyPrefetchResponseStream(response.body); closed.resolve(); (0, _cachemap.setSizeInCacheMap)(entry, responseSize); const serverData = await (0, _fetchserverresponse.createFromNextReadableStream)(prefetchStream, headers, { allowPartialStream: true }); if ((response.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? serverData.b) !== (0, _navigationbuildid.getNavigationBuildId)()) { // The server build does not match the client. Treat as a 404. During // an actual navigation, the router will trigger an MPA navigation. // TODO: We should cache the fact that this is an MPA navigation. rejectRouteCacheEntry(entry, Date.now() + 10 * 1000); return null; } // Read head vary params synchronously. Individual segments carry their // own thenables in CacheNodeSeedData. const headVaryParamsThenable = serverData.h; const headVaryParams = headVaryParamsThenable !== null ? (0, _varyparamsdecoding.readVaryParams)(headVaryParamsThenable) : null; writeDynamicTreeResponseIntoCache(Date.now(), // using the LoadingBoundary fetch strategy, so mark their cache entries accordingly. _types.FetchStrategy.LoadingBoundary, response, serverData, entry, couldBeIntercepted, canonicalUrl, routeIsPPREnabled, headVaryParams, pathname, nextUrl); } if (!couldBeIntercepted) { // This route will never be intercepted. So we can use this entry for all // requests to this route, regardless of the Next-Url header. This works // because when reading the cache we always check for a valid // non-intercepted entry first. // Re-key the entry. The `set` implementation handles removing it from // its previous position in the cache. We don't need to do anything to // update the LRU, because the entry is already in it. // TODO: Treat this as an upsert — should check if an entry already // exists at the new keypath, and if so, whether we should keep that // one instead. const fulfilledVaryPath = (0, _varypath.getFulfilledRouteVaryPath)(pathname, search, nextUrl, couldBeIntercepted); const isRevalidation = false; (0, _cachemap.setInCacheMap)(routeCacheMap, fulfilledVaryPath, entry, isRevalidation); } // Return a promise that resolves when the network connection closes, so // the scheduler can track the number of concurrent network connections. return { value: null, closed: closed.promise }; } catch (error) { // Either the connection itself failed, or something bad happened while // decoding the response. rejectRouteCacheEntry(entry, Date.now() + 10 * 1000); return null; } } async function fetchSegmentOnCacheMiss(route, segmentCacheEntry, routeKey, tree) { // This function is allowed to use async/await because it contains the actual // fetch that gets issued on a cache miss. Notice it writes the result to the // cache entry directly, rather than return data that is then written by // the caller. // // Segment fetches are non-blocking so we don't need to ping the scheduler // on completion. // Use the canonical URL to request the segment, not the original URL. These // are usually the same, but the canonical URL will be different if the route // tree response was redirected. To avoid an extra waterfall on every segment // request, we pass the redirected URL instead of the original one. const url = new URL(route.canonicalUrl, location.origin); const nextUrl = routeKey.nextUrl; const requestKey = tree.requestKey; const normalizedRequestKey = requestKey === _segmentvalueencoding.ROOT_SEGMENT_REQUEST_KEY ? // `_index` instead of as an empty string. This should be treated as // an implementation detail and not as a stable part of the protocol. // It just needs to match the equivalent logic that happens when // prerendering the responses. It should not leak outside of Next.js. '/_index' : requestKey; const headers = { [_approuterheaders.RSC_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER]: normalizedRequestKey }; if (nextUrl !== null) { headers[_approuterheaders.NEXT_URL] = nextUrl; } // Tell the server to perform a static pre-render for the Instant Navigation // Testing API. Static pre-renders don't normally happen during development. addInstantPrefetchHeaderIfLocked(headers); const requestUrl = ("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : url; try { const response = await fetchPrefetchResponse(requestUrl, headers); if (!response || !response.ok || response.status === 204 || // Cache miss // This checks whether the response was served from the per-segment cache, // rather than the old prefetching flow. If it fails, it implies that PPR // is disabled on this route. Theoretically this should never happen // because we only issue requests for segments once we've verified that // the route supports PPR. response.headers.get(_approuterheaders.NEXT_DID_POSTPONE_HEADER) !== '2' && // In output: "export" mode, we can't rely on response headers. But if // we receive a well-formed response, we can assume it's a static // response, because all data is static in this mode. !isOutputExportMode || !response.body) { // Server responded with an error, or with a miss. We should still cache // the response, but we can try again after 10 seconds. rejectSegmentCacheEntry(segmentCacheEntry, Date.now() + 10 * 1000); return null; } // See TODO in fetchRouteOnCacheMiss about removing `closed` for // buffered prefetch paths. const closed = (0, _promisewithresolvers.createPromiseWithResolvers)(); const { stream: prefetchStream, size: responseSize } = await createNonTaskyPrefetchResponseStream(response.body); closed.resolve(); (0, _cachemap.setSizeInCacheMap)(segmentCacheEntry, responseSize); const serverData = await (0, _fetchserverresponse.createFromNextReadableStream)(prefetchStream, headers, { allowPartialStream: true }); if ((response.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? serverData.buildId) !== (0, _navigationbuildid.getNavigationBuildId)()) { // The server build does not match the client. Treat as a 404. During // an actual navigation, the router will trigger an MPA navigation. rejectSegmentCacheEntry(segmentCacheEntry, Date.now() + 10 * 1000); return null; } const now = Date.now(); const staleAt = now + getStaleTimeMs(serverData.staleTime); const fulfilledEntry = fulfillSegmentCacheEntry(segmentCacheEntry, serverData.rsc, staleAt, serverData.isPartial); // If the server tells us which params the segment varies by, we can re-key // the entry to a more generic vary path. This allows the entry to be reused // across different param values for params that the segment doesn't // actually depend on. const varyParams = serverData.varyParams; const fulfilledVaryPath = ("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : (0, _varypath.getSegmentVaryPathForRequest)(segmentCacheEntry.fetchStrategy, tree); // Re-key and upsert the entry at the fulfilled vary path. This ensures // the entry is stored at the most generic path possible based on which // params the segment actually depends on. upsertSegmentEntry(now, fulfilledVaryPath, fulfilledEntry); return { value: fulfilledEntry, // Return a promise that resolves when the network connection closes, so // the scheduler can track the number of concurrent network connections. closed: closed.promise }; } catch (error) { // Either the connection itself failed, or something bad happened while // decoding the response. rejectSegmentCacheEntry(segmentCacheEntry, Date.now() + 10 * 1000); return null; } } async function fetchInlinedSegmentsOnCacheMiss(route, routeKey, tree, spawnedEntries) { // When prefetch inlining is enabled, all segment data for a route is bundled // into a single /_inlined response instead of individual per-segment // requests. This function fetches that response and walks the tree to fill // all segment cache entries at once. const url = new URL(route.canonicalUrl, location.origin); const nextUrl = routeKey.nextUrl; const headers = { [_approuterheaders.RSC_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER]: '/' + _segment.PAGE_SEGMENT_KEY }; if (nextUrl !== null) { headers[_approuterheaders.NEXT_URL] = nextUrl; } addInstantPrefetchHeaderIfLocked(headers); try { const response = await fetchPrefetchResponse(url, headers); if (!response || !response.ok || response.status === 204 || response.headers.get(_approuterheaders.NEXT_DID_POSTPONE_HEADER) !== '2' && !isOutputExportMode || !response.body) { rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } // See TODO in fetchRouteOnCacheMiss about removing `closed` for // buffered prefetch paths. const closed = (0, _promisewithresolvers.createPromiseWithResolvers)(); const { stream: prefetchStream } = await createNonTaskyPrefetchResponseStream(response.body); closed.resolve(); const serverData = await (0, _fetchserverresponse.createFromNextReadableStream)(prefetchStream, headers, { allowPartialStream: true }); if ((response.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? serverData.tree.segment.buildId) !== (0, _navigationbuildid.getNavigationBuildId)()) { rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } const now = Date.now(); // Walk the inlined tree in parallel with the RouteTree and fill // segment cache entries. fillInlinedSegmentEntries(now, route, tree, serverData.tree, spawnedEntries); // Fill the head entry. const headStaleAt = now + getStaleTimeMs(serverData.head.staleTime); const headKey = route.metadata.requestKey; const ownedHeadEntry = spawnedEntries.get(headKey); if (ownedHeadEntry !== undefined) { fulfillSegmentCacheEntry(ownedHeadEntry, serverData.head.rsc, headStaleAt, serverData.head.isPartial); } else { // The head was already cached. Try to upsert if the entry is empty. const existingEntry = readOrCreateSegmentCacheEntry(now, _types.FetchStrategy.PPR, route.metadata); if (existingEntry.status === 0) { fulfillSegmentCacheEntry(upgradeToPendingSegment(existingEntry, _types.FetchStrategy.PPR), serverData.head.rsc, headStaleAt, serverData.head.isPartial); } } // Reject any remaining entries that were not fulfilled by the response. rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return { value: null, closed: closed.promise }; } catch (error) { rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } } function fillInlinedSegmentEntries(now, route, tree, inlinedNode, spawnedEntries) { // Check if the spawned entries map has an entry for this segment's key. const segment = inlinedNode.segment; const staleAt = now + getStaleTimeMs(segment.staleTime); const ownedEntry = spawnedEntries.get(tree.requestKey); if (ownedEntry !== undefined) { // We own this entry. Fulfill it directly. fulfillSegmentCacheEntry(ownedEntry, segment.rsc, staleAt, segment.isPartial); } else { // Not owned by us — this is extra data from the inlined response for a // segment that was already cached. Try to upsert if the entry is empty. const existingEntry = readOrCreateSegmentCacheEntry(now, _types.FetchStrategy.PPR, tree); if (existingEntry.status === 0) { fulfillSegmentCacheEntry(upgradeToPendingSegment(existingEntry, _types.FetchStrategy.PPR), segment.rsc, staleAt, segment.isPartial); } } // Recurse into children. if (tree.slots !== null && inlinedNode.slots !== null) { for(const parallelRouteKey in tree.slots){ const childTree = tree.slots[parallelRouteKey]; const childInlinedNode = inlinedNode.slots[parallelRouteKey]; if (childInlinedNode !== undefined) { fillInlinedSegmentEntries(now, route, childTree, childInlinedNode, spawnedEntries); } } } } async function fetchSegmentPrefetchesUsingDynamicRequest(task, route, fetchStrategy, dynamicRequestTree, spawnedEntries) { const key = task.key; const url = new URL(route.canonicalUrl, location.origin); const nextUrl = key.nextUrl; if (spawnedEntries.size === 1 && spawnedEntries.has(route.metadata.requestKey)) { // The only thing pending is the head. Instruct the server to // skip over everything else. dynamicRequestTree = MetadataOnlyRequestTree; } const headers = { [_approuterheaders.RSC_HEADER]: '1', [_approuterheaders.NEXT_ROUTER_STATE_TREE_HEADER]: (0, _flightdatahelpers.prepareFlightRouterStateForRequest)(dynamicRequestTree) }; if (nextUrl !== null) { headers[_approuterheaders.NEXT_URL] = nextUrl; } switch(fetchStrategy){ case _types.FetchStrategy.Full: { break; } case _types.FetchStrategy.PPRRuntime: { headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] = '2'; break; } case _types.FetchStrategy.LoadingBoundary: { headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] = '1'; break; } default: { fetchStrategy; } } try { const response = await fetchPrefetchResponse(url, headers); if (!response || !response.ok || !response.body) { // Server responded with an error, or with a miss. We should still cache // the response, but we can try again after 10 seconds. rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } const renderedSearch = (0, _routeparams.getRenderedSearch)(response); if (renderedSearch !== route.renderedSearch) { // The search params that were used to render the target page are // different from the search params in the request URL. This only happens // when there's a dynamic rewrite in between the tree prefetch and the // data prefetch. // TODO: For now, since this is an edge case, we reject the prefetch, but // the proper way to handle this is to evict the stale route tree entry // then fill the cache with the new response. rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } // Track when the network connection closes. Only meaningful for Full // (dynamic) prefetches which use incremental streaming. For buffered // paths, this is resolved immediately — see TODO in fetchRouteOnCacheMiss. const closed = (0, _promisewithresolvers.createPromiseWithResolvers)(); let fulfilledEntries = null; let prefetchStream; let bufferedResponseSize = null; if (fetchStrategy === _types.FetchStrategy.Full) { // Full prefetches are dynamic responses stored in the prefetch cache. // They don't carry vary params or other cache metadata, so there's no // need to buffer them. Use the incremental version to allow data to be // processed as it arrives. prefetchStream = createIncrementalPrefetchResponseStream(response.body, closed.resolve, function onResponseSizeUpdate(totalBytesReceivedSoFar) { // When processing a dynamic response, we don't know how large each // individual segment is, so approximate by assigning each segment // the average of the total response size. if (fulfilledEntries === null) { // Haven't received enough data yet to know which segments // were included. return; } const averageSize = totalBytesReceivedSoFar / fulfilledEntries.length; for (const entry of fulfilledEntries){ (0, _cachemap.setSizeInCacheMap)(entry, averageSize); } }); } else { const { stream, size } = await createNonTaskyPrefetchResponseStream(response.body); closed.resolve(); prefetchStream = stream; bufferedResponseSize = size; } const [serverData, cacheData] = await Promise.all([ (0, _fetchserverresponse.createFromNextReadableStream)(prefetchStream, headers, { allowPartialStream: true }), response.cacheData ]); // Read head vary params synchronously. Individual segments carry their // own thenables in CacheNodeSeedData. const headVaryParamsThenable = serverData.h; const headVaryParams = headVaryParamsThenable !== null ? (0, _varyparamsdecoding.readVaryParams)(headVaryParamsThenable) : null; const now = Date.now(); const staleAt = await getStaleAt(now, serverData.s, response); // PPRRuntime prefetches are partial when the server marks the response // as '~' (Partial). Full/LoadingBoundary prefetches are always complete. const isResponsePartial = fetchStrategy === _types.FetchStrategy.PPRRuntime && (cacheData?.isResponsePartial ?? false); // Aside from writing the data into the cache, this function also returns // the entries that were fulfilled, so we can streamingly update their sizes // in the LRU as more data comes in. const buildId = response.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? serverData.b; const flightDatas = (0, _flightdatahelpers.normalizeFlightData)(serverData.f); if (typeof flightDatas === 'string') { rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } const navigationSeed = (0, _navigation.convertServerPatchToFullTree)(now, dynamicRequestTree, flightDatas, renderedSearch, _bfcache.UnknownDynamicStaleTime); fulfilledEntries = writeDynamicRenderResponseIntoCache(now, fetchStrategy, flightDatas, buildId, isResponsePartial, headVaryParams, staleAt, navigationSeed, spawnedEntries); // For buffered responses, update LRU sizes now that we know which // entries were fulfilled. if (bufferedResponseSize !== null && fulfilledEntries !== null && fulfilledEntries.length > 0) { const averageSize = bufferedResponseSize / fulfilledEntries.length; for (const entry of fulfilledEntries){ (0, _cachemap.setSizeInCacheMap)(entry, averageSize); } } // Return a promise that resolves when the network connection closes, so // the scheduler can track the number of concurrent network connections. return { value: null, closed: closed.promise }; } catch (error) { rejectSegmentEntriesIfStillPending(spawnedEntries, Date.now() + 10 * 1000); return null; } } function writeDynamicTreeResponseIntoCache(now, fetchStrategy, response, serverData, entry, couldBeIntercepted, canonicalUrl, routeIsPPREnabled, headVaryParams, originalPathname, nextUrl) { const renderedSearch = (0, _routeparams.getRenderedSearch)(response); const normalizedFlightDataResult = (0, _flightdatahelpers.normalizeFlightData)(serverData.f); if (// MPA navigation. typeof normalizedFlightDataResult === 'string' || normalizedFlightDataResult.length !== 1) { rejectRouteCacheEntry(entry, now + 10 * 1000); return; } const flightData = normalizedFlightDataResult[0]; if (!flightData.isRootRender) { // Unexpected response format. rejectRouteCacheEntry(entry, now + 10 * 1000); return; } const flightRouterState = flightData.tree; // If the response was postponed, segments may contain dynamic holes. // The head has its own partiality flag (flightDataEntry.isHeadPartial) // which is handled separately in writeDynamicRenderResponseIntoCache. const isResponsePartial = response.headers.get(_approuterheaders.NEXT_DID_POSTPONE_HEADER) === '1'; // Convert the server-sent data into the RouteTree format used by the // client cache. // // During this traversal, we accumulate additional data into this // "accumulator" object. const acc = { metadataVaryPath: null }; const routeTree = convertRootFlightRouterStateToRouteTree(flightRouterState, renderedSearch, acc); const metadataVaryPath = acc.metadataVaryPath; if (metadataVaryPath === null) { rejectRouteCacheEntry(entry, now + 10 * 1000); return; } (0, _optimisticroutes.discoverKnownRoute)(now, originalPathname, nextUrl, entry, routeTree, metadataVaryPath, couldBeIntercepted, canonicalUrl, routeIsPPREnabled, false // hasDynamicRewrite ); // If the server sent segment data as part of the response, we should write // it into the cache to prevent a second, redundant prefetch request. // TODO: This is a leftover branch from before Client Segment Cache was // enabled everywhere. Tree prefetches should never include segment data. We // can delete it. Leaving for a subsequent PR. const navigationSeed = (0, _navigation.convertServerPatchToFullTree)(now, flightRouterState, normalizedFlightDataResult, renderedSearch, _bfcache.UnknownDynamicStaleTime); const buildId = response.headers.get(_constants.NEXT_NAV_DEPLOYMENT_ID_HEADER) ?? serverData.b; writeDynamicRenderResponseIntoCache(now, fetchStrategy, normalizedFlightDataResult, buildId, isResponsePartial, headVaryParams, getStaleAtFromHeader(now, response), navigationSeed, null); } function rejectSegmentEntriesIfStillPending(entries, staleAt) { const fulfilledEntries = []; for (const entry of entries.values()){ if (entry.status === 1) { rejectSegmentCacheEntry(entry, staleAt); } else if (entry.status === 2) { fulfilledEntries.push(entry); } } return fulfilledEntries; } function writeDynamicRenderResponseIntoCache(now, fetchStrategy, flightDatas, buildId, isResponsePartial, headVaryParams, staleAt, navigationSeed, spawnedEntries) { if (buildId && buildId !== (0, _navigationbuildid.getNavigationBuildId)()) { // The server build does not match the client. Treat as a 404. During // an actual navigation, the router will trigger an MPA navigation. if (spawnedEntries !== null) { rejectSegmentEntriesIfStillPending(spawnedEntries, now + 10 * 1000); } return null; } const routeTree = navigationSeed.routeTree; const metadataTree = navigationSeed.metadataVaryPath !== null ? createMetadataRouteTree(navigationSeed.metadataVaryPath) : null; for (const flightDataEntry of flightDatas){ const seedData = flightDataEntry.seedData; if (seedData !== null) { // The data sent by the server represents only a subtree of the app. We // need to find the part of the task tree that matches the response. // // segmentPath represents the parent path of subtree. It's a repeating // pattern of parallel route key and segment: // // [string, Segment, string, Segment, string, Segment, ...] const segmentPath = flightDataEntry.segmentPath; let tree = routeTree; for(let i = 0; i < segmentPath.length; i += 2){ const parallelRouteKey = segmentPath[i]; if (tree?.slots?.[parallelRouteKey] !== undefined) { tree = tree.slots[parallelRouteKey]; } else { if (spawnedEntries !== null) { rejectSegmentEntriesIfStillPending(spawnedEntries, now + 10 * 1000); } return null; } } writeSeedDataIntoCache(now, fetchStrategy, tree, staleAt, seedData, isResponsePartial, spawnedEntries); } const head = flightDataEntry.head; if (head !== null && metadataTree !== null) { // When Cache Components is enabled, the server conservatively marks // the head as partial during static generation (isPossiblyPartialHead // in app-render.tsx), even for fully static pages where the head is // actually complete. When the response is non-partial, we override // this since the server confirmed no dynamic content exists. // // Without Cache Components, the server always sends the correct // isHeadPartial value, so no override is needed. const isHeadPartial = ("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : flightDataEntry.isHeadPartial; fulfillEntrySpawnedByRuntimePrefetch(now, fetchStrategy, head, isHeadPartial, staleAt, // parameter. headVaryParams, metadataTree, spawnedEntries); } } // Any entry that's still pending was intentionally not rendered by the // server, because it was inside the loading boundary. Mark them as rejected // so we know not to fetch them again. // TODO: If PPR is enabled on some routes but not others, then it's possible // that a different page is able to do a per-segment prefetch of one of the // segments we're marking as rejected here. We should mark on the segment // somehow that the reason for the rejection is because of a non-PPR prefetch. // That way a per-segment prefetch knows to disregard the rejection. if (spawnedEntries !== null) { const fulfilledEntries = rejectSegmentEntriesIfStillPending(spawnedEntries, now + 10 * 1000); return fulfilledEntries; } return null; } function writeSeedDataIntoCache(now, fetchStrategy, tree, staleAt, seedData, isResponsePartial, entriesOwnedByCurrentTask) { // This function is used to write the result of a runtime server request // (CacheNodeSeedData) into the prefetch cache. const rsc = seedData[0]; const isPartial = rsc === null || isResponsePartial; const varyParamsThenable = seedData[4]; // Each segment carries its own vary params thenable in the seed data. The // thenable resolves to the set of params the segment accessed during render. // A null thenable means tracking was not enabled (not a prerender). const varyParams = varyParamsThenable !== null ? (0, _varyparamsdecoding.readVaryParams)(varyParamsThenable) : null; fulfillEntrySpawnedByRuntimePrefetch(now, fetchStrategy, rsc, isPartial, staleAt, varyParams, tree, entriesOwnedByCurrentTask); // Recursively write the child data into the cache. const slots = tree.slots; if (slots !== null) { const seedDataChildren = seedData[1]; for(const parallelRouteKey in slots){ const childTree = slots[parallelRouteKey]; const childSeedData = seedDataChildren[parallelRouteKey]; if (childSeedData !== null && childSeedData !== undefined) { writeSeedDataIntoCache(now, fetchStrategy, childTree, staleAt, childSeedData, isResponsePartial, entriesOwnedByCurrentTask); } } } } function fulfillEntrySpawnedByRuntimePrefetch(now, fetchStrategy, rsc, isPartial, staleAt, segmentVaryParams, tree, entriesOwnedByCurrentTask) { // We should only write into cache entries that are owned by us. Or create // a new one and write into that. We must never write over an entry that was // created by a different task, because that causes data races. const ownedEntry = entriesOwnedByCurrentTask !== null ? entriesOwnedByCurrentTask.get(tree.requestKey) : undefined; if (ownedEntry !== undefined) { const fulfilledEntry = fulfillSegmentCacheEntry(ownedEntry, rsc, staleAt, isPartial); // Re-key the entry based on which params the segment actually depends on. if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; } else { // There's no matching entry. Attempt to create a new one. const possiblyNewEntry = readOrCreateSegmentCacheEntry(now, fetchStrategy, tree); if (possiblyNewEntry.status === 0) { // Confirmed this is a new entry. We can fulfill it. const newEntry = possiblyNewEntry; const fulfilledEntry = fulfillSegmentCacheEntry(upgradeToPendingSegment(newEntry, fetchStrategy), rsc, staleAt, isPartial); // Re-key the entry based on which params the segment actually depends on. if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; } else { // There was already an entry in the cache. But we may be able to // replace it with the new one from the server. const newEntry = fulfillSegmentCacheEntry(upgradeToPendingSegment(createDetachedSegmentCacheEntry(now), fetchStrategy), rsc, staleAt, isPartial); // Use the fulfilled vary path if available, otherwise fall back to // the request vary path. const varyPath = ("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : (0, _varypath.getSegmentVaryPathForRequest)(fetchStrategy, tree); upsertSegmentEntry(now, varyPath, newEntry); } } } async function fetchPrefetchResponse(url, headers) { const fetchPriority = 'low'; // When issuing a prefetch request, don't immediately decode the response; we // use the lower level `createFromResponse` API instead because we need to do // some extra processing of the response stream. See // `createNonTaskyPrefetchResponseStream` for more details. const shouldImmediatelyDecode = false; const response = await (0, _fetchserverresponse.createFetch)(url, headers, fetchPriority, shouldImmediatelyDecode); if (!response.ok) { return null; } // Check the content type if ("TURBOPACK compile-time falsy", 0) { // In output: "export" mode, we relaxed about the content type, since it's // not Next.js that's serving the response. If the status is OK, assume the // response is valid. If it's not a valid response, the Flight client won't // be able to decode it, and we'll treat it as a miss. } else { const contentType = response.headers.get('content-type'); const isFlightResponse = contentType && contentType.startsWith(_approuterheaders.RSC_CONTENT_TYPE_HEADER); if (!isFlightResponse) { return null; } } return response; } async function createNonTaskyPrefetchResponseStream(body) { // Buffer the entire response before passing it to the Flight client. This // ensures that when Flight processes the stream, all model data is available // synchronously. This is important for readVaryParams, which synchronously // checks the thenable status — if data arrived in multiple network chunks, // the thenables might not yet be fulfilled. // // TODO: There are too many intermediate stream transformations in the // prefetch response pipeline (e.g. stripIsPartialByte, this function). // These could all be consolidated into a single transformation. Refactor // once the cached navigations experiment lands. // // Read the entire response from the network. const reader = body.getReader(); const chunks = []; let size = 0; while(true){ const { done, value } = await reader.read(); if (done) break; chunks.push(value); size += value.byteLength; } // Concatenate into a single chunk so that Flight's processBinaryChunk // processes all rows synchronously in one call. Multiple chunks would not // be sufficient: even though reader.read() resolves as a microtask for // already-enqueued data, the `await` continuation from // createFromReadableStream can interleave between chunks. If the root // model row isn't the first row (e.g. outlined values come first), the // PromiseResolveThenableJob from `await` can cause the root to initialize // eagerly, scheduling the continuation before remaining chunks (including // promise value rows) are processed. A single chunk avoids this. let buffer; if (chunks.length === 1) { buffer = chunks[0]; } else if (chunks.length > 1) { buffer = new Uint8Array(size); let offset = 0; for (const chunk of chunks){ buffer.set(chunk, offset); offset += chunk.byteLength; } } else { buffer = new Uint8Array(0); } const stream = new ReadableStream({ start (controller) { controller.enqueue(buffer); controller.close(); } }); return { stream, size }; } /** * Creates a streaming (non-buffered) prefetch response stream for dynamic/Full * prefetches. These are essentially dynamic responses that get stored in the * prefetch cache — they don't carry vary params or other cache metadata that * requires synchronous thenable resolution, so there's no need to buffer them. * They should continue to stream so consumers can process data as it arrives. */ function createIncrementalPrefetchResponseStream(originalFlightStream, onStreamClose, onResponseSizeUpdate) { // While processing the original stream, we incrementally update the size // of the cache entry in the LRU. let totalByteLength = 0; const reader = originalFlightStream.getReader(); return new ReadableStream({ async pull (controller) { while(true){ const { done, value } = await reader.read(); if (!done) { // Pass to the target stream and keep consuming the Flight response // from the server. controller.enqueue(value); // Incrementally update the size of the cache entry in the LRU. totalByteLength += value.byteLength; onResponseSizeUpdate(totalByteLength); continue; } controller.close(); onStreamClose(); return; } } }); } function addSegmentPathToUrlInOutputExportMode(url, segmentPath) { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; return url; } function canNewFetchStrategyProvideMoreContent(currentStrategy, newStrategy) { return currentStrategy < newStrategy; } /** * Adds the instant prefetch header if the navigation lock is active. * Uses a lazy require to ensure dead code elimination. */ function addInstantPrefetchHeaderIfLocked(headers) { if ("TURBOPACK compile-time truthy", 1) { const { isNavigationLocked } = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/navigation-testing-lock.js [app-ssr] (ecmascript)"); if (isNavigationLocked()) { headers[_approuterheaders.NEXT_INSTANT_PREFETCH_HEADER] = '1'; } } } function getStaleAtFromHeader(now, response) { const staleTimeSeconds = parseInt(response.headers.get(_approuterheaders.NEXT_ROUTER_STALE_TIME_HEADER) ?? '', 10); const staleTimeMs = !isNaN(staleTimeSeconds) ? getStaleTimeMs(staleTimeSeconds) : _navigatereducer.STATIC_STALETIME_MS; return now + staleTimeMs; } async function getStaleAt(now, staleTimeIterable, response) { if (staleTimeIterable !== undefined) { // Iterate the async iterable and take the last yielded value. The server // yields updated staleTime values during the render; the last one is the // final staleTime. let staleTimeSeconds; for await (const value of staleTimeIterable){ staleTimeSeconds = value; } if (staleTimeSeconds !== undefined) { const staleTimeMs = isNaN(staleTimeSeconds) ? _navigatereducer.STATIC_STALETIME_MS : getStaleTimeMs(staleTimeSeconds); return now + staleTimeMs; } } if (response !== undefined) { return getStaleAtFromHeader(now, response); } return now + _navigatereducer.STATIC_STALETIME_MS; } function writeStaticStageResponseIntoCache(now, flightData, buildId, headVaryParamsThenable, staleAt, baseTree, renderedSearch, isResponsePartial) { const fetchStrategy = isResponsePartial ? _types.FetchStrategy.PPR : _types.FetchStrategy.Full; const headVaryParams = headVaryParamsThenable !== null ? (0, _varyparamsdecoding.readVaryParams)(headVaryParamsThenable) : null; const flightDatas = (0, _flightdatahelpers.normalizeFlightData)(flightData); if (typeof flightDatas === 'string') { return; } const navigationSeed = (0, _navigation.convertServerPatchToFullTree)(now, baseTree, flightDatas, renderedSearch, _bfcache.UnknownDynamicStaleTime); writeDynamicRenderResponseIntoCache(now, fetchStrategy, flightDatas, buildId, isResponsePartial, headVaryParams, staleAt, navigationSeed, null // spawnedEntries — no pre-created entries; will create or upsert ); } async function processRuntimePrefetchStream(now, runtimePrefetchStream, baseTree, renderedSearch) { const { stream, isPartial } = await stripIsPartialByte(runtimePrefetchStream); const serverData = await (0, _fetchserverresponse.createFromNextReadableStream)(stream, undefined, { allowPartialStream: true }); const headVaryParamsThenable = serverData.h; const headVaryParams = headVaryParamsThenable !== null ? (0, _varyparamsdecoding.readVaryParams)(headVaryParamsThenable) : null; const staleAt = await getStaleAt(now, serverData.s); const flightDatas = (0, _flightdatahelpers.normalizeFlightData)(serverData.f); if (typeof flightDatas === 'string') { return null; } const navigationSeed = (0, _navigation.convertServerPatchToFullTree)(now, baseTree, flightDatas, renderedSearch, _bfcache.UnknownDynamicStaleTime); return { flightDatas, navigationSeed, buildId: serverData.b, isResponsePartial: isPartial, headVaryParams, staleAt }; } async function stripIsPartialByte(stream) { // When there is no recognized marker byte, the fallback depends on whether // Cached Navigations is enabled. When enabled, dynamic navigation responses // don't have a marker but may contain dynamic holes, so they are treated as // partial. When disabled, unmarked responses are treated as non-partial. const defaultIsPartial = !!("TURBOPACK compile-time value", false); const reader = stream.getReader(); const { done, value } = await reader.read(); if (done || !value || value.byteLength === 0) { return { stream: new ReadableStream({ start: (c)=>c.close() }), isPartial: defaultIsPartial }; } const firstByte = value[0]; const hasMarker = firstByte === 0x23 || firstByte === 0x7e; const isPartial = hasMarker ? firstByte === 0x7e : defaultIsPartial; const remainder = hasMarker ? value.byteLength > 1 ? value.subarray(1) : null : value; return { isPartial, stream: new ReadableStream({ start (controller) { if (remainder) { controller.enqueue(remainder); } }, async pull (controller) { const result = await reader.read(); if (result.done) { controller.close(); } else { controller.enqueue(result.value); } } }) }; } 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; } }), "[project]/node_modules/next/dist/client/components/segment-cache/scheduler.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { cancelPrefetchTask: null, isPrefetchTaskDirty: null, pingPrefetchScheduler: null, pingPrefetchTask: null, reschedulePrefetchTask: null, schedulePrefetchTask: null, startRevalidationCooldown: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { cancelPrefetchTask: function() { return cancelPrefetchTask; }, isPrefetchTaskDirty: function() { return isPrefetchTaskDirty; }, pingPrefetchScheduler: function() { return pingPrefetchScheduler; }, pingPrefetchTask: function() { return pingPrefetchTask; }, reschedulePrefetchTask: function() { return reschedulePrefetchTask; }, schedulePrefetchTask: function() { return schedulePrefetchTask; }, startRevalidationCooldown: function() { return startRevalidationCooldown; } }); const _approutertypes = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/app-router-types.js [app-ssr] (ecmascript)"); const _matchsegments = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/match-segments.js [app-ssr] (ecmascript)"); const _cache = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache.js [app-ssr] (ecmascript)"); const _cachekey = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-key.js [app-ssr] (ecmascript)"); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _segment = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/segment.js [app-ssr] (ecmascript)"); const _lru = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/lru.js [app-ssr] (ecmascript)"); const scheduleMicrotask = typeof queueMicrotask === 'function' ? queueMicrotask : (fn)=>Promise.resolve().then(fn).catch((error)=>setTimeout(()=>{ throw error; })); const taskHeap = []; let inProgressRequests = 0; let sortIdCounter = 0; let didScheduleMicrotask = false; // The most recently hovered (or touched, etc) link, i.e. the most recent task // scheduled at Intent priority. There's only ever a single task at Intent // priority at a time. We reserve special network bandwidth for this task only. let mostRecentlyHoveredLink = null; // CDN cache propagation delay after revalidation (in milliseconds) const REVALIDATION_COOLDOWN_MS = 300; // Timeout handle for the revalidation cooldown. When non-null, prefetch // requests are blocked to allow CDN cache propagation. let revalidationCooldownTimeoutHandle = null; function startRevalidationCooldown() { // Clear any existing timeout in case multiple revalidations happen // in quick succession. if (revalidationCooldownTimeoutHandle !== null) { clearTimeout(revalidationCooldownTimeoutHandle); } // Schedule the cooldown to expire after the delay. revalidationCooldownTimeoutHandle = setTimeout(()=>{ revalidationCooldownTimeoutHandle = null; // Retry the prefetch queue now that the cooldown has expired. pingPrefetchScheduler(); }, REVALIDATION_COOLDOWN_MS); } function schedulePrefetchTask(key, treeAtTimeOfPrefetch, fetchStrategy, priority, onInvalidate, _onComplete) { // Spawn a new prefetch task const task = { key, treeAtTimeOfPrefetch, routeCacheVersion: (0, _cache.getCurrentRouteCacheVersion)(), segmentCacheVersion: (0, _cache.getCurrentSegmentCacheVersion)(), priority, phase: 1, hasBackgroundWork: false, spawnedRuntimePrefetches: null, fetchStrategy, sortId: sortIdCounter++, isCanceled: false, onInvalidate, _heapIndex: -1 }; if ("TURBOPACK compile-time truthy", 1) { task._onComplete = _onComplete; } trackMostRecentlyHoveredLink(task); heapPush(taskHeap, task); // Schedule an async task to process the queue. // // The main reason we process the queue in an async task is for batching. // It's common for a single JS task/event to trigger multiple prefetches. // By deferring to a microtask, we only process the queue once per JS task. // If they have different priorities, it also ensures they are processed in // the optimal order. pingPrefetchScheduler(); return task; } function cancelPrefetchTask(task) { // Remove the prefetch task from the queue. If the task already completed, // then this is a no-op. // // We must also explicitly mark the task as canceled so that a blocked task // does not get added back to the queue when it's pinged by the network. task.isCanceled = true; heapDelete(taskHeap, task); if ("TURBOPACK compile-time truthy", 1) { // Call completion callback. In practice this shouldn't be reached for // test-initiated prefetches since cancellation is only used by the Link // component when elements scroll out of viewport. const onComplete = task._onComplete; task._onComplete = undefined; onComplete?.(); } } function reschedulePrefetchTask(task, treeAtTimeOfPrefetch, fetchStrategy, priority) { // Bump the prefetch task to the top of the queue, as if it were a fresh // task. This is essentially the same as canceling the task and scheduling // a new one, except it reuses the original object. // // The primary use case is to increase the priority of a Link-initated // prefetch on hover. // // Note: _onComplete is not reset here because it's preserved on the same // task object. When the rescheduled task completes, the original callback // will still be invoked. // Un-cancel the task, in case it was previously canceled. task.isCanceled = false; task.phase = 1; // Assign a new sort ID to move it ahead of all other tasks at the same // priority level. (Higher sort IDs are processed first.) task.sortId = sortIdCounter++; task.priority = // Intent priority, even if the rescheduled priority is lower. task === mostRecentlyHoveredLink ? _types.PrefetchPriority.Intent : priority; task.treeAtTimeOfPrefetch = treeAtTimeOfPrefetch; task.fetchStrategy = fetchStrategy; trackMostRecentlyHoveredLink(task); if (task._heapIndex !== -1) { // The task is already in the queue. heapResift(taskHeap, task); } else { heapPush(taskHeap, task); } pingPrefetchScheduler(); } function isPrefetchTaskDirty(task, nextUrl, tree) { // This is used to quickly bail out of a prefetch task if the result is // guaranteed to not have changed since the task was initiated. This is // strictly an optimization — theoretically, if it always returned true, no // behavior should change because a full prefetch task will effectively // perform the same checks. return task.routeCacheVersion !== (0, _cache.getCurrentRouteCacheVersion)() || task.segmentCacheVersion !== (0, _cache.getCurrentSegmentCacheVersion)() || task.treeAtTimeOfPrefetch !== tree || task.key.nextUrl !== nextUrl; } function trackMostRecentlyHoveredLink(task) { // Track the mostly recently hovered link, i.e. the most recently scheduled // task at Intent priority. There must only be one such task at a time. if (task.priority === _types.PrefetchPriority.Intent && task !== mostRecentlyHoveredLink) { if (mostRecentlyHoveredLink !== null) { // Bump the previously hovered link's priority down to Default. if (mostRecentlyHoveredLink.priority !== _types.PrefetchPriority.Background) { mostRecentlyHoveredLink.priority = _types.PrefetchPriority.Default; heapResift(taskHeap, mostRecentlyHoveredLink); } } mostRecentlyHoveredLink = task; } } function pingPrefetchScheduler() { if (didScheduleMicrotask) { // Already scheduled a task to process the queue return; } didScheduleMicrotask = true; scheduleMicrotask(processQueueInMicrotask); } /** * Checks if we've exceeded the maximum number of concurrent prefetch requests, * to avoid saturating the browser's internal network queue. This is a * cooperative limit — prefetch tasks should check this before issuing * new requests. * * Also checks if we're within the revalidation cooldown window, during which * prefetch requests are delayed to allow CDN cache propagation. */ function hasNetworkBandwidth(task) { // Check if we're within the revalidation cooldown window if (revalidationCooldownTimeoutHandle !== null) { // We're within the cooldown window. Return false to prevent prefetching. // When the cooldown expires, the timeout will call ensureWorkIsScheduled() // to retry the queue. return false; } // TODO: Also check if there's an in-progress navigation. We should never // add prefetch requests to the network queue if an actual navigation is // taking place, to ensure there's sufficient bandwidth for render-blocking // data and resources. // TODO: Consider reserving some amount of bandwidth for static prefetches. if (task.priority === _types.PrefetchPriority.Intent) { // The most recently hovered link is allowed to exceed the default limit. // // The goal is to always have enough bandwidth to start a new prefetch // request when hovering over a link. // // However, because we don't abort in-progress requests, it's still possible // we'll run out of bandwidth. When links are hovered in quick succession, // there could be multiple hover requests running simultaneously. return inProgressRequests < 12; } // The default limit is lower than the limit for a hovered link. return inProgressRequests < 4; } function spawnPrefetchSubtask(prefetchSubtask) { // When the scheduler spawns an async task, we don't await its result. // Instead, the async task writes its result directly into the cache, then // pings the scheduler to continue. // // We process server responses streamingly, so the prefetch subtask will // likely resolve before we're finished receiving all the data. The subtask // result includes a promise that resolves once the network connection is // closed. The scheduler uses this to control network bandwidth by tracking // and limiting the number of concurrent requests. inProgressRequests++; return prefetchSubtask.then((result)=>{ if (result === null) { // The prefetch task errored before it could start processing the // network stream. Assume the connection is closed. onPrefetchConnectionClosed(); return null; } // Wait for the connection to close before freeing up more bandwidth. result.closed.then(onPrefetchConnectionClosed); return result.value; }); } function onPrefetchConnectionClosed() { inProgressRequests--; // Notify the scheduler that we have more bandwidth, and can continue // processing tasks. pingPrefetchScheduler(); } function pingPrefetchTask(task) { // "Ping" a prefetch that's already in progress to notify it of new data. if (task.isCanceled || // Check if prefetch is already queued. task._heapIndex !== -1) { return; } // Add the task back to the queue. heapPush(taskHeap, task); pingPrefetchScheduler(); } function processQueueInMicrotask() { didScheduleMicrotask = false; // We aim to minimize how often we read the current time. Since nearly all // functions in the prefetch scheduler are synchronous, we can read the time // once and pass it as an argument wherever it's needed. const now = Date.now(); // Process the task queue until we run out of network bandwidth. let task = heapPeek(taskHeap); while(task !== null && hasNetworkBandwidth(task)){ task.routeCacheVersion = (0, _cache.getCurrentRouteCacheVersion)(); task.segmentCacheVersion = (0, _cache.getCurrentSegmentCacheVersion)(); const exitStatus = pingRoute(now, task); // These fields are only valid for a single attempt. Reset them after each // iteration of the task queue. const hasBackgroundWork = task.hasBackgroundWork; task.hasBackgroundWork = false; task.spawnedRuntimePrefetches = null; switch(exitStatus){ case 0: // The task yielded because there are too many requests in progress. // Stop processing tasks until we have more bandwidth. return; case 1: // The task is blocked. It needs more data before it can proceed. // Keep the task out of the queue until the server responds. heapPop(taskHeap); // Continue to the next task task = heapPeek(taskHeap); continue; case 2: if (task.phase === 1) { // Finished prefetching the route tree. Proceed to prefetching // the segments. task.phase = 0; heapResift(taskHeap, task); } else if (hasBackgroundWork) { // The task spawned additional background work. Reschedule the task // at background priority. task.priority = _types.PrefetchPriority.Background; heapResift(taskHeap, task); } else { // The prefetch is complete. Continue to the next task. if ("TURBOPACK compile-time truthy", 1) { // Notify the Instant Navigation Testing API that the prefetch has // completed, so it can proceed with navigation. const onComplete = task._onComplete; task._onComplete = undefined; onComplete?.(); } heapPop(taskHeap); } task = heapPeek(taskHeap); continue; default: exitStatus; } } // Run LRU cleanup only when the scheduler is fully idle: no queued tasks and // no in-progress requests. At that point, all active prefetch tasks have // finished reading from the cache (moving recently used entries to the front // of the list), so only genuinely stale data gets evicted. if (task === null && inProgressRequests === 0) { (0, _lru.cleanup)(); } } /** * Check this during a prefetch task to determine if background work can be * performed. If so, it evaluates to `true`. Otherwise, it returns `false`, * while also scheduling a background task to run later. Usage: * * @example * if (background(task)) { * // Perform background-pri work * } */ function background(task) { if (task.priority === _types.PrefetchPriority.Background) { return true; } task.hasBackgroundWork = true; return false; } function pingRoute(now, task) { const key = task.key; const route = (0, _cache.readOrCreateRouteCacheEntry)(now, task, key); const exitStatus = pingRootRouteTree(now, task, route); if (exitStatus !== 0 && key.search !== '') { // If the URL has a non-empty search string, also prefetch the pathname // without the search string. We use the searchless route tree as a base for // optimistic routing; see requestOptimisticRouteCacheEntry for details. // // Note that we don't need to prefetch any of the segment data. Just the // route tree. // // TODO: This is a temporary solution; the plan is to replace this by adding // a wildcard lookup method to the TupleMap implementation. This is // non-trivial to implement because it needs to account for things like // fallback route entries, hence this temporary workaround. const url = new URL(key.pathname, location.origin); const keyWithoutSearch = (0, _cachekey.createCacheKey)(url.href, key.nextUrl); const routeWithoutSearch = (0, _cache.readOrCreateRouteCacheEntry)(now, task, keyWithoutSearch); switch(routeWithoutSearch.status){ case _cache.EntryStatus.Empty: { if (background(task)) { routeWithoutSearch.status = _cache.EntryStatus.Pending; spawnPrefetchSubtask((0, _cache.fetchRouteOnCacheMiss)(routeWithoutSearch, keyWithoutSearch)); } break; } case _cache.EntryStatus.Pending: case _cache.EntryStatus.Fulfilled: case _cache.EntryStatus.Rejected: { break; } default: routeWithoutSearch; } } return exitStatus; } function pingRootRouteTree(now, task, route) { switch(route.status){ case _cache.EntryStatus.Empty: { // Route is not yet cached, and there's no request already in progress. // Spawn a task to request the route, load it into the cache, and ping // the task to continue. // TODO: There are multiple strategies in the API for prefetching // a route. Currently we've only implemented the main one: per-segment, // static-data only. // // There's also `` // which prefetch both static *and* dynamic data. // Similarly, we need to fallback to the old, per-page // behavior if PPR is disabled for a route (via the incremental opt-in). // // Those cases will be handled here. spawnPrefetchSubtask((0, _cache.fetchRouteOnCacheMiss)(route, task.key)); // If the request takes longer than a minute, a subsequent request should // retry instead of waiting for this one. When the response is received, // this value will be replaced by a new value based on the stale time sent // from the server. // TODO: We should probably also manually abort the fetch task, to reclaim // server bandwidth. route.staleAt = now + 60 * 1000; // Upgrade to Pending so we know there's already a request in progress route.status = _cache.EntryStatus.Pending; // Intentional fallthrough to the Pending branch } case _cache.EntryStatus.Pending: { // Still pending. We can't start prefetching the segments until the route // tree has loaded. Add the task to the set of blocked tasks so that it // is notified when the route tree is ready. const blockedTasks = route.blockedTasks; if (blockedTasks === null) { route.blockedTasks = new Set([ task ]); } else { blockedTasks.add(task); } return 1; } case _cache.EntryStatus.Rejected: { // Route tree failed to load. Treat as a 404. return 2; } case _cache.EntryStatus.Fulfilled: { if (task.phase !== 0) { // Do not prefetch segment data until we've entered the segment phase. return 2; } // Recursively fill in the segment tree. if (!hasNetworkBandwidth(task)) { // Stop prefetching segments until there's more bandwidth. return 0; } const tree = route.tree; // A task's fetch strategy gets set to `PPR` for any "auto" prefetch. // If it turned out that the route isn't PPR-enabled, we need to use `LoadingBoundary` instead. // We don't need to do this for runtime prefetches, because those are only available in // `cacheComponents`, where every route is PPR. let fetchStrategy; if (tree.prefetchHints & _approutertypes.PrefetchHint.SubtreeHasInstant) { // If `instant` is defined anywhere on the target route, ignore the // fetch strategy and switch to unified strategy used by Cache // Components (called `PPR` for now, will likely be renamed). // // In practice, this just means that a "full" prefetch () has no effect. You're meant to use Runtime // Prefetching instead — that's the new pattern that replaces // prefetch={true}. // // The reason we check for `instant` rather than the `cacheComponents` // flag is to support incremental adoption. `prefetch={true}` will // continue to work until you opt into `instant`. fetchStrategy = _types.FetchStrategy.PPR; } else if (task.fetchStrategy === _types.FetchStrategy.PPR) { fetchStrategy = route.supportsPerSegmentPrefetching ? _types.FetchStrategy.PPR : _types.FetchStrategy.LoadingBoundary; } else { fetchStrategy = task.fetchStrategy; } switch(fetchStrategy){ case _types.FetchStrategy.PPR: { // For Cache Components pages, each segment may be prefetched // statically or using a runtime request, based on various // configurations and heuristics. We'll do this in two passes: first // traverse the tree and perform all the static prefetches. // // Then, if there are any segments that need a runtime request, // do another pass to perform a runtime prefetch. pingStaticHead(now, task, route); const exitStatus = pingSharedPartOfCacheComponentsTree(now, task, route, task.treeAtTimeOfPrefetch, tree); if (exitStatus === 0) { // Child yielded without finishing. return 0; } const spawnedRuntimePrefetches = task.spawnedRuntimePrefetches; if (spawnedRuntimePrefetches !== null) { // During the first pass, we discovered segments that require a // runtime prefetch. Do a second pass to construct a request tree. const spawnedEntries = new Map(); pingRuntimeHead(now, task, route, spawnedEntries, _types.FetchStrategy.PPRRuntime); const requestTree = pingRuntimePrefetches(now, task, route, tree, spawnedRuntimePrefetches, spawnedEntries); let needsDynamicRequest = spawnedEntries.size > 0; if (needsDynamicRequest) { // Perform a dynamic prefetch request and populate the cache with // the result. spawnPrefetchSubtask((0, _cache.fetchSegmentPrefetchesUsingDynamicRequest)(task, route, _types.FetchStrategy.PPRRuntime, requestTree, spawnedEntries)); } } return 2; } case _types.FetchStrategy.Full: case _types.FetchStrategy.PPRRuntime: case _types.FetchStrategy.LoadingBoundary: { // Prefetch multiple segments using a single dynamic request. // TODO: We can consolidate this branch with previous one by modeling // it as if the first segment in the new tree has runtime prefetching // enabled. Will do this as a follow-up refactor. Might want to remove // the special metatdata case below first. In the meantime, it's not // really that much duplication, just would be nice to remove one of // these codepaths. const spawnedEntries = new Map(); pingRuntimeHead(now, task, route, spawnedEntries, fetchStrategy); const dynamicRequestTree = diffRouteTreeAgainstCurrent(now, task, route, task.treeAtTimeOfPrefetch, tree, spawnedEntries, fetchStrategy); let needsDynamicRequest = spawnedEntries.size > 0; if (needsDynamicRequest) { spawnPrefetchSubtask((0, _cache.fetchSegmentPrefetchesUsingDynamicRequest)(task, route, fetchStrategy, dynamicRequestTree, spawnedEntries)); } return 2; } default: fetchStrategy; } break; } default: { route; } } return 2; } function pingStaticHead(now, task, route) { // The Head data for a page (metadata, viewport) is not really a route // segment, in the sense that it doesn't appear in the route tree. But we // store it in the cache as if it were, using a special key. pingStaticSegmentData(now, task, route, (0, _cache.readOrCreateSegmentCacheEntry)(now, _types.FetchStrategy.PPR, route.metadata), task.key, route.metadata); } function pingRuntimeHead(now, task, route, spawnedEntries, fetchStrategy) { pingRouteTreeAndIncludeDynamicData(now, task, route, route.metadata, false, spawnedEntries, // and LoadingBoundary fetchStrategy === _types.FetchStrategy.LoadingBoundary ? _types.FetchStrategy.Full : fetchStrategy); } // TODO: Rename dynamic -> runtime throughout this module function pingSharedPartOfCacheComponentsTree(now, task, route, oldTree, newTree) { // When Cache Components is enabled (or PPR, or a fully static route when PPR // is disabled; those cases are treated equivalently to Cache Components), we // start by prefetching each segment individually. Once we reach the "new" // part of the tree — the part that doesn't exist on the current page — we // may choose to switch to a runtime prefetch instead, based on the // information sent by the server in the route tree. // // The traversal starts in the "shared" part of the tree. Once we reach the // "new" part of the tree, we switch to a different traversal, // pingNewPartOfCacheComponentsTree. // Prefetch this segment's static data. const segment = (0, _cache.readOrCreateSegmentCacheEntry)(now, task.fetchStrategy, newTree); pingStaticSegmentData(now, task, route, segment, task.key, newTree); // Recursively ping the children. const oldTreeChildren = oldTree[1]; const newTreeChildren = newTree.slots; if (newTreeChildren !== null) { for(const parallelRouteKey in newTreeChildren){ if (!hasNetworkBandwidth(task)) { // Stop prefetching segments until there's more bandwidth. return 0; } const newTreeChild = newTreeChildren[parallelRouteKey]; const newTreeChildSegment = newTreeChild.segment; const oldTreeChild = oldTreeChildren[parallelRouteKey]; const oldTreeChildSegment = oldTreeChild?.[0]; let childExitStatus; if (oldTreeChildSegment !== undefined && doesCurrentSegmentMatchCachedSegment(route, newTreeChildSegment, oldTreeChildSegment)) { // We're still in the "shared" part of the tree. childExitStatus = pingSharedPartOfCacheComponentsTree(now, task, route, oldTreeChild, newTreeChild); } else { // We've entered the "new" part of the tree. Switch // traversal functions. childExitStatus = pingNewPartOfCacheComponentsTree(now, task, route, newTreeChild); } if (childExitStatus === 0) { // Child yielded without finishing. return 0; } } } return 2; } function pingNewPartOfCacheComponentsTree(now, task, route, tree) { // We're now prefetching in the "new" part of the tree, the part that doesn't // exist on the current page. (In other words, we're deeper than the // shared layouts.) Segments in here default to being prefetched statically. // However, if the server instructs us to, we may switch to a runtime // prefetch instead. Traverse the tree and check at each segment. if (tree.prefetchHints & _approutertypes.PrefetchHint.HasRuntimePrefetch) { // This route has a runtime prefetch response. Since we're below the shared // layout, everything from this point should be prefetched using a single, // combined runtime request, rather than using per-segment static requests. // This is true even if some of the child segments are known to be fully // static — once we've decided to perform a runtime prefetch, we might as // well respond with the static segments in the same roundtrip. (That's how // regular navigations work, too.) We'll still skip over segments that are // already cached, though. // // It's the server's responsibility to set a reasonable value of // `hasRuntimePrefetch`. Currently it's user-defined, but eventually, the // server may send a value of `false` even if the user opts in, if it // determines during build that the route is always fully static. There are // more optimizations we can do once we implement fallback param // tracking, too. // // Use the task object to collect the segments that need a runtime prefetch. // This will signal to the outer task queue that a second traversal is // required to construct a request tree. if (task.spawnedRuntimePrefetches === null) { task.spawnedRuntimePrefetches = new Set([ tree.requestKey ]); } else { task.spawnedRuntimePrefetches.add(tree.requestKey); } // Then exit the traversal without prefetching anything further. return 2; } // This segment should not be runtime prefetched. Prefetch its static data. const segment = (0, _cache.readOrCreateSegmentCacheEntry)(now, task.fetchStrategy, tree); pingStaticSegmentData(now, task, route, segment, task.key, tree); if (tree.slots !== null) { if (!hasNetworkBandwidth(task)) { // Stop prefetching segments until there's more bandwidth. return 0; } // Recursively ping the children. for(const parallelRouteKey in tree.slots){ const childTree = tree.slots[parallelRouteKey]; const childExitStatus = pingNewPartOfCacheComponentsTree(now, task, route, childTree); if (childExitStatus === 0) { // Child yielded without finishing. return 0; } } } // This segment and all its children have finished prefetching. return 2; } function diffRouteTreeAgainstCurrent(now, task, route, oldTree, newTree, spawnedEntries, fetchStrategy) { // This is a single recursive traversal that does multiple things: // - Finds the parts of the target route (newTree) that are not part of // of the current page (oldTree) by diffing them, using the same algorithm // as a real navigation. // - Constructs a request tree (FlightRouterState) that describes which // segments need to be prefetched and which ones are already cached. // - Creates a set of pending cache entries for the segments that need to // be prefetched, so that a subsequent prefetch task does not request the // same segments again. const oldTreeChildren = oldTree[1]; const newTreeChildren = newTree.slots; let requestTreeChildren = {}; if (newTreeChildren !== null) { for(const parallelRouteKey in newTreeChildren){ const newTreeChild = newTreeChildren[parallelRouteKey]; const newTreeChildSegment = newTreeChild.segment; const oldTreeChild = oldTreeChildren[parallelRouteKey]; const oldTreeChildSegment = oldTreeChild?.[0]; if (oldTreeChildSegment !== undefined && doesCurrentSegmentMatchCachedSegment(route, newTreeChildSegment, oldTreeChildSegment)) { // This segment is already part of the current route. Keep traversing. const requestTreeChild = diffRouteTreeAgainstCurrent(now, task, route, oldTreeChild, newTreeChild, spawnedEntries, fetchStrategy); requestTreeChildren[parallelRouteKey] = requestTreeChild; } else { // This segment is not part of the current route. We're entering a // part of the tree that we need to prefetch (unless everything is // already cached). switch(fetchStrategy){ case _types.FetchStrategy.LoadingBoundary: { // When PPR is disabled, we can't prefetch per segment. We must // fallback to the old prefetch behavior and send a dynamic request. // Only routes that include a loading boundary can be prefetched in // this way. // // This is simlar to a "full" prefetch, but we're much more // conservative about which segments to include in the request. // // The server will only render up to the first loading boundary // inside new part of the tree. If there's no loading boundary // anywhere in the tree, the server will never return any data, so // we can skip the request. const subtreeHasLoadingBoundary = (newTreeChild.prefetchHints & (_approutertypes.PrefetchHint.SegmentHasLoadingBoundary | _approutertypes.PrefetchHint.SubtreeHasLoadingBoundary)) !== 0; const requestTreeChild = subtreeHasLoadingBoundary ? pingPPRDisabledRouteTreeUpToLoadingBoundary(now, task, route, newTreeChild, null, spawnedEntries) : (0, _cache.convertRouteTreeToFlightRouterState)(newTreeChild); requestTreeChildren[parallelRouteKey] = requestTreeChild; break; } case _types.FetchStrategy.PPRRuntime: { // This is a runtime prefetch. Fetch all cacheable data in the tree, // not just the static PPR shell. const requestTreeChild = pingRouteTreeAndIncludeDynamicData(now, task, route, newTreeChild, false, spawnedEntries, fetchStrategy); requestTreeChildren[parallelRouteKey] = requestTreeChild; break; } case _types.FetchStrategy.Full: { // This is a "full" prefetch. Fetch all the data in the tree, both // static and dynamic. We issue roughly the same request that we // would during a real navigation. The goal is that once the // navigation occurs, the router should not have to fetch any // additional data. // // Although the response will include dynamic data, opting into a // Full prefetch — via — implicitly // instructs the cache to treat the response as "static", or non- // dynamic, since the whole point is to cache it for // future navigations. // // Construct a tree (currently a FlightRouterState) that represents // which segments need to be prefetched and which ones are already // cached. If the tree is empty, then we can exit. Otherwise, we'll // send the request tree to the server and use the response to // populate the segment cache. const requestTreeChild = pingRouteTreeAndIncludeDynamicData(now, task, route, newTreeChild, false, spawnedEntries, fetchStrategy); requestTreeChildren[parallelRouteKey] = requestTreeChild; break; } default: fetchStrategy; } } } } const requestTree = [ newTree.segment, requestTreeChildren, null, null ]; return requestTree; } function pingPPRDisabledRouteTreeUpToLoadingBoundary(now, task, route, tree, refetchMarkerContext, spawnedEntries) { // This function is similar to pingRouteTreeAndIncludeDynamicData, except the // server is only going to return a minimal loading state — it will stop // rendering at the first loading boundary. Whereas a Full prefetch is // intentionally aggressive and tries to pretfetch all the data that will be // needed for a navigation, a LoadingBoundary prefetch is much more // conservative. For example, it will omit from the request tree any segment // that is already cached, regardles of whether it's partial or full. By // contrast, a Full prefetch will refetch partial segments. // "inside-shared-layout" tells the server where to start looking for a // loading boundary. let refetchMarker = refetchMarkerContext === null ? 'inside-shared-layout' : null; const segment = (0, _cache.readOrCreateSegmentCacheEntry)(now, task.fetchStrategy, tree); switch(segment.status){ case _cache.EntryStatus.Empty: { // This segment is not cached. Add a refetch marker so the server knows // to start rendering here. // TODO: Instead of a "refetch" marker, we could just omit this subtree's // FlightRouterState from the request tree. I think this would probably // already work even without any updates to the server. For consistency, // though, I'll send the full tree and we'll look into this later as part // of a larger redesign of the request protocol. // Add the pending cache entry to the result map. spawnedEntries.set(tree.requestKey, (0, _cache.upgradeToPendingSegment)(segment, // might not include it in the pending response. If another route is able // to issue a per-segment request, we'll do that in the background. _types.FetchStrategy.LoadingBoundary)); if (refetchMarkerContext !== 'refetch') { refetchMarker = refetchMarkerContext = 'refetch'; } else { // There's already a parent with a refetch marker, so we don't need // to add another one. } break; } case _cache.EntryStatus.Fulfilled: { // The segment is already cached. const segmentHasLoadingBoundary = (tree.prefetchHints & _approutertypes.PrefetchHint.SegmentHasLoadingBoundary) !== 0; if (segmentHasLoadingBoundary) { // This segment has a loading boundary, which means the server won't // render its children. So there's nothing left to prefetch along this // path. We can bail out. return (0, _cache.convertRouteTreeToFlightRouterState)(tree); } break; } case _cache.EntryStatus.Pending: { break; } case _cache.EntryStatus.Rejected: { break; } default: segment; } const requestTreeChildren = {}; if (tree.slots !== null) { for(const parallelRouteKey in tree.slots){ const childTree = tree.slots[parallelRouteKey]; requestTreeChildren[parallelRouteKey] = pingPPRDisabledRouteTreeUpToLoadingBoundary(now, task, route, childTree, refetchMarkerContext, spawnedEntries); } } const requestTree = [ tree.segment, requestTreeChildren, null, refetchMarker ]; return requestTree; } function pingRouteTreeAndIncludeDynamicData(now, task, route, tree, isInsideRefetchingParent, spawnedEntries, fetchStrategy) { // The tree we're constructing is the same shape as the tree we're navigating // to. But even though this is a "new" tree, some of the individual segments // may be cached as a result of other route prefetches. // // So we need to find the first uncached segment along each path add an // explicit "refetch" marker so the server knows where to start rendering. // Once the server starts rendering along a path, it keeps rendering the // entire subtree. const segment = (0, _cache.readOrCreateSegmentCacheEntry)(now, // and we have to use the former here. // We can have a task with `FetchStrategy.PPR` where some of its segments are configured to // always use runtime prefetching (via `export const prefetch`), and those should check for // entries that include search params. fetchStrategy, tree); let spawnedSegment = null; switch(segment.status){ case _cache.EntryStatus.Empty: { // This segment is not cached. if (fetchStrategy === _types.FetchStrategy.Full) { // Check if there's a matching entry in the bfcache. If so, fulfill the // segment using the bfcache entry instead of issuing a new request. const fulfilled = (0, _cache.attemptToFulfillDynamicSegmentFromBFCache)(now, segment, tree); if (fulfilled !== null) { break; } } // Include it in the request. spawnedSegment = (0, _cache.upgradeToPendingSegment)(segment, fetchStrategy); break; } case _cache.EntryStatus.Fulfilled: { // The segment is already cached. if (segment.isPartial && (0, _cache.canNewFetchStrategyProvideMoreContent)(segment.fetchStrategy, fetchStrategy)) { // The cached segment contains dynamic holes, and was prefetched using a // less specific strategy than the current one. This means we're in one // of these cases: // - we have a static prefetch, and we're doing a runtime prefetch // - we have a static or runtime prefetch, and we're doing a Full // prefetch (or a navigation). // In either case, we need to include it in the request to get a more // specific (or full) version. However, if there's a non-stale bfcache // entry from a previous navigation, prefer that over making a new // request. if (fetchStrategy === _types.FetchStrategy.Full) { const fulfilled = (0, _cache.attemptToUpgradeSegmentFromBFCache)(now, tree); if (fulfilled !== null) { break; } } spawnedSegment = pingFullSegmentRevalidation(now, tree, fetchStrategy); } break; } case _cache.EntryStatus.Pending: case _cache.EntryStatus.Rejected: { // There's either another prefetch currently in progress, or the previous // attempt failed. If the new strategy can provide more content, fetch it again. if ((0, _cache.canNewFetchStrategyProvideMoreContent)(segment.fetchStrategy, fetchStrategy)) { spawnedSegment = pingFullSegmentRevalidation(now, tree, fetchStrategy); } break; } default: segment; } const requestTreeChildren = {}; if (tree.slots !== null) { for(const parallelRouteKey in tree.slots){ const childTree = tree.slots[parallelRouteKey]; requestTreeChildren[parallelRouteKey] = pingRouteTreeAndIncludeDynamicData(now, task, route, childTree, isInsideRefetchingParent || spawnedSegment !== null, spawnedEntries, fetchStrategy); } } if (spawnedSegment !== null) { // Add the pending entry to the result map. spawnedEntries.set(tree.requestKey, spawnedSegment); } // Don't bother to add a refetch marker if one is already present in a parent. const refetchMarker = !isInsideRefetchingParent && spawnedSegment !== null ? 'refetch' : null; const requestTree = [ tree.segment, requestTreeChildren, null, refetchMarker ]; return requestTree; } function pingRuntimePrefetches(now, task, route, tree, spawnedRuntimePrefetches, spawnedEntries) { // Construct a request tree (FlightRouterState) for a runtime prefetch. If // a segment is part of the runtime prefetch, the tree is constructed by // diffing against what's already in the prefetch cache. Otherwise, we send // a regular FlightRouterState with no special markers. // // See pingRouteTreeAndIncludeDynamicData for details. if (spawnedRuntimePrefetches.has(tree.requestKey)) { // This segment needs a runtime prefetch. return pingRouteTreeAndIncludeDynamicData(now, task, route, tree, false, spawnedEntries, _types.FetchStrategy.PPRRuntime); } let requestTreeChildren = {}; const slots = tree.slots; if (slots !== null) { for(const parallelRouteKey in slots){ const childTree = slots[parallelRouteKey]; requestTreeChildren[parallelRouteKey] = pingRuntimePrefetches(now, task, route, childTree, spawnedRuntimePrefetches, spawnedEntries); } } // This segment is not part of the runtime prefetch. Clone the base tree. const requestTree = [ tree.segment, requestTreeChildren, null, null ]; return requestTree; } function pingStaticSegmentData(now, task, route, segment, routeKey, tree) { switch(segment.status){ case _cache.EntryStatus.Empty: if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; // Upgrade to Pending so we know there's already a request in progress spawnPrefetchSubtask((0, _cache.fetchSegmentOnCacheMiss)(route, (0, _cache.upgradeToPendingSegment)(segment, _types.FetchStrategy.PPR), routeKey, tree)); break; case _cache.EntryStatus.Pending: { // There's already a request in progress. Depending on what kind of // request it is, we may want to revalidate it. switch(segment.fetchStrategy){ case _types.FetchStrategy.PPR: case _types.FetchStrategy.PPRRuntime: case _types.FetchStrategy.Full: break; case _types.FetchStrategy.LoadingBoundary: // There's a pending request, but because it's using the old // prefetching strategy, we can't be sure if it will be fulfilled by // the response — it might be inside the loading boundary. Perform // a revalidation, but because it's speculative, wait to do it at // background priority. if (background(task)) { // TODO: Instead of speculatively revalidating, consider including // `hasLoading` in the route tree prefetch response. pingPPRSegmentRevalidation(now, route, routeKey, tree); } break; default: segment.fetchStrategy; } break; } case _cache.EntryStatus.Rejected: { // The existing entry in the cache was rejected. Depending on how it // was originally fetched, we may or may not want to revalidate it. switch(segment.fetchStrategy){ case _types.FetchStrategy.PPR: case _types.FetchStrategy.PPRRuntime: case _types.FetchStrategy.Full: break; case _types.FetchStrategy.LoadingBoundary: // There's a rejected entry, but it was fetched using the loading // boundary strategy. So the reason it wasn't returned by the server // might just be because it was inside a loading boundary. Or because // there was a dynamic rewrite. Revalidate it using the per- // segment strategy. // // Because a rejected segment will definitely prevent the segment (and // all of its children) from rendering, we perform this revalidation // immediately instead of deferring it to a background task. pingPPRSegmentRevalidation(now, route, routeKey, tree); break; default: segment.fetchStrategy; } break; } case _cache.EntryStatus.Fulfilled: break; default: segment; } // Segments do not have dependent tasks, so once the prefetch is initiated, // there's nothing else for us to do (except write the server data into the // entry, which is handled by `fetchSegmentOnCacheMiss`). } /** * Walks the RouteTree (including the head metadata) and collects any segments * that are still Empty into a Map, upgrading them to Pending. These entries * will be fulfilled by the inlined prefetch response. */ function collectInlinedEntries(now, route) { const entries = new Map(); collectInlinedEntriesImpl(now, route.tree, entries); // Also collect the head/metadata entry. const headEntry = (0, _cache.readOrCreateSegmentCacheEntry)(now, _types.FetchStrategy.PPR, route.metadata); if (headEntry.status === _cache.EntryStatus.Empty) { entries.set(route.metadata.requestKey, (0, _cache.upgradeToPendingSegment)(headEntry, _types.FetchStrategy.PPR)); } return entries; } function collectInlinedEntriesImpl(now, tree, entries) { const entry = (0, _cache.readOrCreateSegmentCacheEntry)(now, _types.FetchStrategy.PPR, tree); if (entry.status === _cache.EntryStatus.Empty) { entries.set(tree.requestKey, (0, _cache.upgradeToPendingSegment)(entry, _types.FetchStrategy.PPR)); } if (tree.slots !== null) { for(const parallelRouteKey in tree.slots){ collectInlinedEntriesImpl(now, tree.slots[parallelRouteKey], entries); } } } function pingPPRSegmentRevalidation(now, route, routeKey, tree) { const revalidatingSegment = (0, _cache.readOrCreateRevalidatingSegmentEntry)(now, _types.FetchStrategy.PPR, tree); switch(revalidatingSegment.status){ case _cache.EntryStatus.Empty: // Spawn a prefetch request. The fetch function handles upserting // the entry at the correct fulfilled vary path upon completion. spawnPrefetchSubtask((0, _cache.fetchSegmentOnCacheMiss)(route, (0, _cache.upgradeToPendingSegment)(revalidatingSegment, _types.FetchStrategy.PPR), routeKey, tree)); break; case _cache.EntryStatus.Pending: break; case _cache.EntryStatus.Fulfilled: case _cache.EntryStatus.Rejected: break; default: revalidatingSegment; } } function pingFullSegmentRevalidation(now, tree, fetchStrategy) { const revalidatingSegment = (0, _cache.readOrCreateRevalidatingSegmentEntry)(now, fetchStrategy, tree); if (revalidatingSegment.status === _cache.EntryStatus.Empty) { // During a Full/PPRRuntime prefetch, a single dynamic request is made for all the // segments that we need. So we don't initiate a request here directly. By // returning a pending entry from this function, it signals to the caller // that this segment should be included in the request that's sent to // the server. const pendingSegment = (0, _cache.upgradeToPendingSegment)(revalidatingSegment, fetchStrategy); // The upsert is handled by fulfillEntrySpawnedByRuntimePrefetch // when the dynamic prefetch response is written into the cache. return pendingSegment; } else { // There's already a revalidation in progress. const nonEmptyRevalidatingSegment = revalidatingSegment; if ((0, _cache.canNewFetchStrategyProvideMoreContent)(nonEmptyRevalidatingSegment.fetchStrategy, fetchStrategy)) { // The existing revalidation was fetched using a less specific strategy. // Reset it and start a new revalidation. const emptySegment = (0, _cache.overwriteRevalidatingSegmentCacheEntry)(now, fetchStrategy, tree); const pendingSegment = (0, _cache.upgradeToPendingSegment)(emptySegment, fetchStrategy); // The upsert is handled by fulfillEntrySpawnedByRuntimePrefetch // when the dynamic prefetch response is written into the cache. return pendingSegment; } switch(nonEmptyRevalidatingSegment.status){ case _cache.EntryStatus.Pending: // There's already an in-progress prefetch that includes this segment. return null; case _cache.EntryStatus.Fulfilled: case _cache.EntryStatus.Rejected: // A previous revalidation attempt finished, but we chose not to replace // the existing entry in the cache. Don't try again until or unless the // revalidation entry expires. return null; default: nonEmptyRevalidatingSegment; return null; } } } function doesCurrentSegmentMatchCachedSegment(route, currentSegment, cachedSegment) { if (cachedSegment === _segment.PAGE_SEGMENT_KEY) { // In the FlightRouterState stored by the router, the page segment has the // rendered search params appended to the name of the segment. In the // prefetch cache, however, this is stored separately. So, when comparing // the router's current FlightRouterState to the cached FlightRouterState, // we need to make sure we compare both parts of the segment. // TODO: This is not modeled clearly. We use the same type, // FlightRouterState, for both the CacheNode tree _and_ the prefetch cache // _and_ the server response format, when conceptually those are three // different things and treated in different ways. We should encode more of // this information into the type design so mistakes are less likely. return currentSegment === (0, _segment.addSearchParamsIfPageSegment)(_segment.PAGE_SEGMENT_KEY, Object.fromEntries(new URLSearchParams(route.renderedSearch))); } // Non-page segments are compared using the same function as the server return (0, _matchsegments.matchSegment)(cachedSegment, currentSegment); } // ----------------------------------------------------------------------------- // The remainder of the module is a MinHeap implementation. Try not to put any // logic below here unless it's related to the heap algorithm. We can extract // this to a separate module if/when we need multiple kinds of heaps. // ----------------------------------------------------------------------------- function compareQueuePriority(a, b) { // Since the queue is a MinHeap, this should return a positive number if b is // higher priority than a, and a negative number if a is higher priority // than b. // `priority` is an integer, where higher numbers are higher priority. const priorityDiff = b.priority - a.priority; if (priorityDiff !== 0) { return priorityDiff; } // If the priority is the same, check which phase the prefetch is in — is it // prefetching the route tree, or the segments? Route trees are prioritized. const phaseDiff = b.phase - a.phase; if (phaseDiff !== 0) { return phaseDiff; } // Finally, check the insertion order. `sortId` is an incrementing counter // assigned to prefetches. We want to process the newest prefetches first. return b.sortId - a.sortId; } function heapPush(heap, node) { const index = heap.length; heap.push(node); node._heapIndex = index; heapSiftUp(heap, node, index); } function heapPeek(heap) { return heap.length === 0 ? null : heap[0]; } function heapPop(heap) { if (heap.length === 0) { return null; } const first = heap[0]; first._heapIndex = -1; const last = heap.pop(); if (last !== first) { heap[0] = last; last._heapIndex = 0; heapSiftDown(heap, last, 0); } return first; } function heapDelete(heap, node) { const index = node._heapIndex; if (index !== -1) { node._heapIndex = -1; if (heap.length !== 0) { const last = heap.pop(); if (last !== node) { heap[index] = last; last._heapIndex = index; heapSiftDown(heap, last, index); } } } } function heapResift(heap, node) { const index = node._heapIndex; if (index !== -1) { if (index === 0) { heapSiftDown(heap, node, 0); } else { const parentIndex = index - 1 >>> 1; const parent = heap[parentIndex]; if (compareQueuePriority(parent, node) > 0) { // The parent is larger. Sift up. heapSiftUp(heap, node, index); } else { // The parent is smaller (or equal). Sift down. heapSiftDown(heap, node, index); } } } } function heapSiftUp(heap, node, i) { let index = i; while(index > 0){ const parentIndex = index - 1 >>> 1; const parent = heap[parentIndex]; if (compareQueuePriority(parent, node) > 0) { // The parent is larger. Swap positions. heap[parentIndex] = node; node._heapIndex = parentIndex; heap[index] = parent; parent._heapIndex = index; index = parentIndex; } else { // The parent is smaller. Exit. return; } } } function heapSiftDown(heap, node, i) { let index = i; const length = heap.length; const halfLength = length >>> 1; while(index < halfLength){ const leftIndex = (index + 1) * 2 - 1; const left = heap[leftIndex]; const rightIndex = leftIndex + 1; const right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those. if (compareQueuePriority(left, node) < 0) { if (rightIndex < length && compareQueuePriority(right, left) < 0) { heap[index] = right; right._heapIndex = index; heap[rightIndex] = node; node._heapIndex = rightIndex; index = rightIndex; } else { heap[index] = left; left._heapIndex = index; heap[leftIndex] = node; node._heapIndex = leftIndex; index = leftIndex; } } else if (rightIndex < length && compareQueuePriority(right, node) < 0) { heap[index] = right; right._heapIndex = index; heap[rightIndex] = node; node._heapIndex = rightIndex; index = rightIndex; } else { // Neither child is smaller. Exit. return; } } } 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; } }), "[project]/node_modules/next/dist/client/components/links.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { IDLE_LINK_STATUS: null, PENDING_LINK_STATUS: null, getLinkForCurrentNavigation: null, mountFormInstance: null, mountLinkInstance: null, onLinkVisibilityChanged: null, onNavigationIntent: null, pingVisibleLinks: null, setLinkForCurrentNavigation: null, unmountLinkForCurrentNavigation: null, unmountPrefetchableInstance: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { IDLE_LINK_STATUS: function() { return IDLE_LINK_STATUS; }, PENDING_LINK_STATUS: function() { return PENDING_LINK_STATUS; }, getLinkForCurrentNavigation: function() { return getLinkForCurrentNavigation; }, mountFormInstance: function() { return mountFormInstance; }, mountLinkInstance: function() { return mountLinkInstance; }, onLinkVisibilityChanged: function() { return onLinkVisibilityChanged; }, onNavigationIntent: function() { return onNavigationIntent; }, pingVisibleLinks: function() { return pingVisibleLinks; }, setLinkForCurrentNavigation: function() { return setLinkForCurrentNavigation; }, unmountLinkForCurrentNavigation: function() { return unmountLinkForCurrentNavigation; }, unmountPrefetchableInstance: function() { return unmountPrefetchableInstance; } }); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _cachekey = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/cache-key.js [app-ssr] (ecmascript)"); const _scheduler = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/scheduler.js [app-ssr] (ecmascript)"); const _react = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js [app-ssr] (ecmascript)"); // Tracks the most recently navigated link instance. When null, indicates // the current navigation was not initiated by a link click. let linkForMostRecentNavigation = null; const PENDING_LINK_STATUS = { pending: true }; const IDLE_LINK_STATUS = { pending: false }; function setLinkForCurrentNavigation(link) { (0, _react.startTransition)(()=>{ linkForMostRecentNavigation?.setOptimisticLinkStatus(IDLE_LINK_STATUS); link?.setOptimisticLinkStatus(PENDING_LINK_STATUS); linkForMostRecentNavigation = link; }); } function unmountLinkForCurrentNavigation(link) { if (linkForMostRecentNavigation === link) { linkForMostRecentNavigation = null; } } function getLinkForCurrentNavigation() { return linkForMostRecentNavigation; } // Use a WeakMap to associate a Link instance with its DOM element. This is // used by the IntersectionObserver to track the link's visibility. const prefetchable = typeof WeakMap === 'function' ? new WeakMap() : new Map(); // A Set of the currently visible links. We re-prefetch visible links after a // cache invalidation, or when the current URL changes. It's a separate data // structure from the WeakMap above because only the visible links need to // be enumerated. const prefetchableAndVisible = new Set(); // A single IntersectionObserver instance shared by all components. const observer = typeof IntersectionObserver === 'function' ? new IntersectionObserver(handleIntersect, { rootMargin: '200px' }) : null; function observeVisibility(element, instance) { const existingInstance = prefetchable.get(element); if (existingInstance !== undefined) { // This shouldn't happen because each component should have its own // anchor tag instance, but it's defensive coding to avoid a memory leak in // case there's a logical error somewhere else. unmountPrefetchableInstance(element); } // Only track prefetchable links that have a valid prefetch URL prefetchable.set(element, instance); if (observer !== null) { observer.observe(element); } } function coercePrefetchableUrl(href) { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; else { return null; } } function mountLinkInstance(element, href, router, fetchStrategy, prefetchEnabled, setOptimisticLinkStatus) { if (prefetchEnabled) { const prefetchURL = coercePrefetchableUrl(href); if (prefetchURL !== null) { const instance = { router, fetchStrategy, isVisible: false, prefetchTask: null, prefetchHref: prefetchURL.href, setOptimisticLinkStatus }; // We only observe the link's visibility if it's prefetchable. For // example, this excludes links to external URLs. observeVisibility(element, instance); return instance; } } // If the link is not prefetchable, we still create an instance so we can // track its optimistic state (i.e. useLinkStatus). const instance = { router, fetchStrategy, isVisible: false, prefetchTask: null, prefetchHref: null, setOptimisticLinkStatus }; return instance; } function mountFormInstance(element, href, router, fetchStrategy) { const prefetchURL = coercePrefetchableUrl(href); if (prefetchURL === null) { // This href is not prefetchable, so we don't track it. // TODO: We currently observe/unobserve a form every time its href changes. // For Links, this isn't a big deal because the href doesn't usually change, // but for forms it's extremely common. We should optimize this. return; } const instance = { router, fetchStrategy, isVisible: false, prefetchTask: null, prefetchHref: prefetchURL.href, setOptimisticLinkStatus: null }; observeVisibility(element, instance); } function unmountPrefetchableInstance(element) { const instance = prefetchable.get(element); if (instance !== undefined) { prefetchable.delete(element); prefetchableAndVisible.delete(instance); const prefetchTask = instance.prefetchTask; if (prefetchTask !== null) { (0, _scheduler.cancelPrefetchTask)(prefetchTask); } } if (observer !== null) { observer.unobserve(element); } } function handleIntersect(entries) { for (const entry of entries){ // Some extremely old browsers or polyfills don't reliably support // isIntersecting so we check intersectionRatio instead. (Do we care? Not // really. But whatever this is fine.) const isVisible = entry.intersectionRatio > 0; onLinkVisibilityChanged(entry.target, isVisible); } } function onLinkVisibilityChanged(element, isVisible) { if ("TURBOPACK compile-time truthy", 1) { // Prefetching on viewport is disabled in development for performance // reasons, because it requires compiling the target page. // TODO: Investigate re-enabling this. return; } //TURBOPACK unreachable ; const instance = undefined; } function onNavigationIntent(element, unstable_upgradeToDynamicPrefetch) { const instance = prefetchable.get(element); if (instance === undefined) { return; } // Prefetch the link on hover/touchstart. if (instance !== undefined) { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; rescheduleLinkPrefetch(instance, _types.PrefetchPriority.Intent); } } function rescheduleLinkPrefetch(instance, priority) { // Ensures that app-router-instance is not compiled in the server bundle if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; } function pingVisibleLinks(nextUrl, tree) { // For each currently visible link, cancel the existing prefetch task (if it // exists) and schedule a new one. This is effectively the same as if all the // visible links left and then re-entered the viewport. // // This is called when the Next-Url or the base tree changes, since those // may affect the result of a prefetch task. It's also called after a // cache invalidation. for (const instance of prefetchableAndVisible){ const task = instance.prefetchTask; if (task !== null && !(0, _scheduler.isPrefetchTaskDirty)(task, nextUrl, tree)) { continue; } // Something changed. Cancel the existing prefetch task and schedule a // new one. if (task !== null) { (0, _scheduler.cancelPrefetchTask)(task); } const cacheKey = (0, _cachekey.createCacheKey)(instance.prefetchHref, nextUrl); instance.prefetchTask = (0, _scheduler.schedulePrefetchTask)(cacheKey, tree, instance.fetchStrategy, _types.PrefetchPriority.Default, null); } } 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; } }), "[project]/node_modules/next/dist/shared/lib/router/utils/path-has-prefix.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "pathHasPrefix", { enumerable: true, get: function() { return pathHasPrefix; } }); const _parsepath = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/parse-path.js [app-ssr] (ecmascript)"); function pathHasPrefix(path, prefix) { if (typeof path !== 'string') { return false; } const { pathname } = (0, _parsepath.parsePath)(path); return pathname === prefix || pathname.startsWith(prefix + '/'); } }), "[project]/node_modules/next/dist/client/has-base-path.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "hasBasePath", { enumerable: true, get: function() { return hasBasePath; } }); const _pathhasprefix = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/path-has-prefix.js [app-ssr] (ecmascript)"); const basePath = ("TURBOPACK compile-time value", "") || ''; function hasBasePath(path) { return (0, _pathhasprefix.pathHasPrefix)(path, basePath); } 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; } }), "[project]/node_modules/next/dist/shared/lib/router/utils/is-local-url.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "isLocalURL", { enumerable: true, get: function() { return isLocalURL; } }); const _utils = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/utils.js [app-ssr] (ecmascript)"); const _hasbasepath = __turbopack_context__.r("[project]/node_modules/next/dist/client/has-base-path.js [app-ssr] (ecmascript)"); function isLocalURL(url) { // prevent a hydration mismatch on href for url with anchor refs if (!(0, _utils.isAbsoluteUrl)(url)) return true; try { // absolute urls can be local if they are on the same origin const locationOrigin = (0, _utils.getLocationOrigin)(); const resolved = new URL(url, locationOrigin); return resolved.origin === locationOrigin && (0, _hasbasepath.hasBasePath)(resolved.pathname); } catch (_) { return false; } } }), "[project]/node_modules/next/dist/shared/lib/utils/error-once.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "errorOnce", { enumerable: true, get: function() { return errorOnce; } }); let errorOnce = (_)=>{}; if ("TURBOPACK compile-time truthy", 1) { const errors = new Set(); errorOnce = (msg)=>{ if (!errors.has(msg)) { console.error(msg); } errors.add(msg); }; } }), "[project]/node_modules/next/dist/client/app-dir/link.js [app-ssr] (ecmascript)", ((__turbopack_context__, module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { default: null, useLinkStatus: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { /** * A React component that extends the HTML `` element to provide * [prefetching](https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching) * and client-side navigation. This is the primary way to navigate between routes in Next.js. * * @remarks * - Prefetching is only enabled in production. * * @see https://nextjs.org/docs/app/api-reference/components/link */ default: function() { return LinkComponent; }, useLinkStatus: function() { return useLinkStatus; } }); const _interop_require_wildcard = __turbopack_context__.r("[project]/node_modules/@swc/helpers/cjs/_interop_require_wildcard.cjs [app-ssr] (ecmascript)"); const _jsxruntime = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js [app-ssr] (ecmascript)"); const _react = /*#__PURE__*/ _interop_require_wildcard._(__turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js [app-ssr] (ecmascript)")); const _formaturl = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/format-url.js [app-ssr] (ecmascript)"); const _approutercontextsharedruntime = __turbopack_context__.r("[project]/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/app-router-context.js [app-ssr] (ecmascript)"); const _usemergedref = __turbopack_context__.r("[project]/node_modules/next/dist/client/use-merged-ref.js [app-ssr] (ecmascript)"); const _utils = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/utils.js [app-ssr] (ecmascript)"); const _addbasepath = __turbopack_context__.r("[project]/node_modules/next/dist/client/add-base-path.js [app-ssr] (ecmascript)"); const _warnonce = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/utils/warn-once.js [app-ssr] (ecmascript)"); const _routerreducertypes = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/router-reducer/router-reducer-types.js [app-ssr] (ecmascript)"); const _links = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/links.js [app-ssr] (ecmascript)"); const _islocalurl = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/router/utils/is-local-url.js [app-ssr] (ecmascript)"); const _types = __turbopack_context__.r("[project]/node_modules/next/dist/client/components/segment-cache/types.js [app-ssr] (ecmascript)"); const _erroronce = __turbopack_context__.r("[project]/node_modules/next/dist/shared/lib/utils/error-once.js [app-ssr] (ecmascript)"); function isModifiedEvent(event) { const eventTarget = event.currentTarget; const target = eventTarget.getAttribute('target'); return target && target !== '_self' || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || // triggers resource download event.nativeEvent && event.nativeEvent.which === 2; } function linkClicked(e, href, linkInstanceRef, replace, scroll, onNavigate, transitionTypes) { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; } function formatStringOrUrl(urlObjOrString) { if (typeof urlObjOrString === 'string') { return urlObjOrString; } return (0, _formaturl.formatUrl)(urlObjOrString); } function LinkComponent(props) { const [linkStatus, setOptimisticLinkStatus] = (0, _react.useOptimistic)(_links.IDLE_LINK_STATUS); let children; const linkInstanceRef = (0, _react.useRef)(null); const { href: hrefProp, as: asProp, children: childrenProp, prefetch: prefetchProp = null, passHref, replace, shallow, scroll, onClick, onMouseEnter: onMouseEnterProp, onTouchStart: onTouchStartProp, legacyBehavior = false, onNavigate, transitionTypes, ref: forwardedRef, unstable_dynamicOnHover, ...restProps } = props; children = childrenProp; if (legacyBehavior && (typeof children === 'string' || typeof children === 'number')) { children = /*#__PURE__*/ (0, _jsxruntime.jsx)("a", { children: children }); } const router = _react.default.useContext(_approutercontextsharedruntime.AppRouterContext); const prefetchEnabled = prefetchProp !== false; const fetchStrategy = prefetchProp !== false ? getFetchStrategyFromPrefetchProp(prefetchProp) : _types.FetchStrategy.PPR; if ("TURBOPACK compile-time truthy", 1) { function createPropError(args) { return Object.defineProperty(new Error(`Failed prop type: The prop \`${args.key}\` expects a ${args.expected} in \`\`, but got \`${args.actual}\` instead.` + (("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : '')), "__NEXT_ERROR_CODE", { value: "E319", enumerable: false, configurable: true }); } // TypeScript trick for type-guarding: const requiredPropsGuard = { href: true }; const requiredProps = Object.keys(requiredPropsGuard); requiredProps.forEach((key)=>{ if (key === 'href') { if (props[key] == null || typeof props[key] !== 'string' && typeof props[key] !== 'object') { throw createPropError({ key, expected: '`string` or `object`', actual: props[key] === null ? 'null' : typeof props[key] }); } } else { // TypeScript trick for type-guarding: const _ = key; } }); // TypeScript trick for type-guarding: const optionalPropsGuard = { as: true, replace: true, scroll: true, shallow: true, passHref: true, prefetch: true, unstable_dynamicOnHover: true, onClick: true, onMouseEnter: true, onTouchStart: true, legacyBehavior: true, onNavigate: true, transitionTypes: true }; const optionalProps = Object.keys(optionalPropsGuard); optionalProps.forEach((key)=>{ const valType = typeof props[key]; if (key === 'as') { if (props[key] && valType !== 'string' && valType !== 'object') { throw createPropError({ key, expected: '`string` or `object`', actual: valType }); } } else if (key === 'onClick' || key === 'onMouseEnter' || key === 'onTouchStart' || key === 'onNavigate') { if (props[key] && valType !== 'function') { throw createPropError({ key, expected: '`function`', actual: valType }); } } else if (key === 'replace' || key === 'scroll' || key === 'shallow' || key === 'passHref' || key === 'legacyBehavior' || key === 'unstable_dynamicOnHover') { if (props[key] != null && valType !== 'boolean') { throw createPropError({ key, expected: '`boolean`', actual: valType }); } } else if (key === 'prefetch') { if (props[key] != null && valType !== 'boolean' && props[key] !== 'auto') { throw createPropError({ key, expected: '`boolean | "auto"`', actual: valType }); } } else if (key === 'transitionTypes') { if (props[key] != null && !Array.isArray(props[key])) { throw createPropError({ key, expected: '`string[]`', actual: valType }); } } else { // TypeScript trick for type-guarding: const _ = key; } }); } const resolvedHref = asProp || hrefProp; const formattedHref = formatStringOrUrl(resolvedHref); if ("TURBOPACK compile-time truthy", 1) { if (props.locale) { (0, _warnonce.warnOnce)('The `locale` prop is not supported in `next/link` while using the `app` router. Read more about app router internalization: https://nextjs.org/docs/app/building-your-application/routing/internationalization'); } if (!asProp) { let href; if (typeof resolvedHref === 'string') { href = resolvedHref; } else if (typeof resolvedHref === 'object' && typeof resolvedHref.pathname === 'string') { href = resolvedHref.pathname; } if (href) { const hasDynamicSegment = href.split('/').some((segment)=>segment.startsWith('[') && segment.endsWith(']')); if (hasDynamicSegment) { throw Object.defineProperty(new Error(`Dynamic href \`${href}\` found in while using the \`/app\` router, this is not supported. Read more: https://nextjs.org/docs/messages/app-dir-dynamic-href`), "__NEXT_ERROR_CODE", { value: "E267", enumerable: false, configurable: true }); } } } } // This will return the first child, if multiple are provided it will throw an error let child; if (legacyBehavior) { if (children?.$$typeof === Symbol.for('react.lazy')) { throw Object.defineProperty(new Error(`\`\` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link's \`\` tag.`), "__NEXT_ERROR_CODE", { value: "E863", enumerable: false, configurable: true }); } if ("TURBOPACK compile-time truthy", 1) { if (onClick) { console.warn(`"onClick" was passed to with \`href\` of \`${formattedHref}\` but "legacyBehavior" was set. The legacy behavior requires onClick be set on the child of next/link`); } if (onMouseEnterProp) { console.warn(`"onMouseEnter" was passed to with \`href\` of \`${formattedHref}\` but "legacyBehavior" was set. The legacy behavior requires onMouseEnter be set on the child of next/link`); } try { child = _react.default.Children.only(children); } catch (err) { if (!children) { throw Object.defineProperty(new Error(`No children were passed to with \`href\` of \`${formattedHref}\` but one child is required https://nextjs.org/docs/messages/link-no-children`), "__NEXT_ERROR_CODE", { value: "E320", enumerable: false, configurable: true }); } throw Object.defineProperty(new Error(`Multiple children were passed to with \`href\` of \`${formattedHref}\` but only one child is supported https://nextjs.org/docs/messages/link-multiple-children` + (("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : '')), "__NEXT_ERROR_CODE", { value: "E266", enumerable: false, configurable: true }); } } else //TURBOPACK unreachable ; } else { if ("TURBOPACK compile-time truthy", 1) { if (children?.type === 'a') { throw Object.defineProperty(new Error('Invalid with child. Please remove or use .\nLearn more: https://nextjs.org/docs/messages/invalid-new-link-with-extra-anchor'), "__NEXT_ERROR_CODE", { value: "E209", enumerable: false, configurable: true }); } } } const childRef = legacyBehavior ? child && typeof child === 'object' && child.ref : forwardedRef; // Use a callback ref to attach an IntersectionObserver to the anchor tag on // mount. In the future we will also use this to keep track of all the // currently mounted instances, e.g. so we can re-prefetch them after // a revalidation or refresh. const observeLinkVisibilityOnMount = _react.default.useCallback((element)=>{ if (router !== null) { linkInstanceRef.current = (0, _links.mountLinkInstance)(element, formattedHref, router, fetchStrategy, prefetchEnabled, setOptimisticLinkStatus); } return ()=>{ if (linkInstanceRef.current) { (0, _links.unmountLinkForCurrentNavigation)(linkInstanceRef.current); linkInstanceRef.current = null; } (0, _links.unmountPrefetchableInstance)(element); }; }, [ prefetchEnabled, formattedHref, router, fetchStrategy, setOptimisticLinkStatus ]); const mergedRef = (0, _usemergedref.useMergedRef)(observeLinkVisibilityOnMount, childRef); const childProps = { ref: mergedRef, onClick (e) { if ("TURBOPACK compile-time truthy", 1) { if (!e) { throw Object.defineProperty(new Error(`Component rendered inside next/link has to pass click event to "onClick" prop.`), "__NEXT_ERROR_CODE", { value: "E312", enumerable: false, configurable: true }); } } if (!legacyBehavior && typeof onClick === 'function') { onClick(e); } if (legacyBehavior && child.props && typeof child.props.onClick === 'function') { child.props.onClick(e); } if (!router) { return; } if (e.defaultPrevented) { return; } linkClicked(e, formattedHref, linkInstanceRef, replace, scroll, onNavigate, transitionTypes); }, onMouseEnter (e) { if (!legacyBehavior && typeof onMouseEnterProp === 'function') { onMouseEnterProp(e); } if (legacyBehavior && child.props && typeof child.props.onMouseEnter === 'function') { child.props.onMouseEnter(e); } if (!router) { return; } if ("TURBOPACK compile-time truthy", 1) { return; } //TURBOPACK unreachable ; const upgradeToDynamicPrefetch = undefined; }, onTouchStart: ("TURBOPACK compile-time falsy", 0) ? "TURBOPACK unreachable" : function onTouchStart(e) { if (!legacyBehavior && typeof onTouchStartProp === 'function') { onTouchStartProp(e); } if (legacyBehavior && child.props && typeof child.props.onTouchStart === 'function') { child.props.onTouchStart(e); } if (!router) { return; } if (!prefetchEnabled) { return; } const upgradeToDynamicPrefetch = unstable_dynamicOnHover === true; (0, _links.onNavigationIntent)(e.currentTarget, upgradeToDynamicPrefetch); } }; // If the url is absolute, we can bypass the logic to prepend the basePath. if ((0, _utils.isAbsoluteUrl)(formattedHref)) { childProps.href = formattedHref; } else if (!legacyBehavior || passHref || child.type === 'a' && !('href' in child.props)) { childProps.href = (0, _addbasepath.addBasePath)(formattedHref); } let link; if (legacyBehavior) { if ("TURBOPACK compile-time truthy", 1) { (0, _erroronce.errorOnce)('`legacyBehavior` is deprecated and will be removed in a future ' + 'release. A codemod is available to upgrade your components:\n\n' + 'npx @next/codemod@latest new-link .\n\n' + 'Learn more: https://nextjs.org/docs/app/building-your-application/upgrading/codemods#remove-a-tags-from-link-components'); } link = /*#__PURE__*/ _react.default.cloneElement(child, childProps); } else { link = /*#__PURE__*/ (0, _jsxruntime.jsx)("a", { ...restProps, ...childProps, children: children }); } return /*#__PURE__*/ (0, _jsxruntime.jsx)(LinkStatusContext.Provider, { value: linkStatus, children: link }); } const LinkStatusContext = /*#__PURE__*/ (0, _react.createContext)(_links.IDLE_LINK_STATUS); const useLinkStatus = ()=>{ return (0, _react.useContext)(LinkStatusContext); }; function getFetchStrategyFromPrefetchProp(prefetchProp) { if ("TURBOPACK compile-time falsy", 0) //TURBOPACK unreachable ; else { return prefetchProp === null || prefetchProp === 'auto' ? _types.FetchStrategy.PPR : // (although invalid values should've been filtered out by prop validation in dev) _types.FetchStrategy.Full; } } 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=node_modules_0j-8k18._.js.map