Spaces:
Running
Running
ling-open-studio / node_modules /next /dist /client /components /segment-cache /navigation-testing-lock.js
| /** | |
| * 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). | |
| */ "use strict"; | |
| 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 = require("../app-router-headers"); | |
| const _useactionqueue = require("../use-action-queue"); | |
| 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 (process.env.__NEXT_EXPOSE_TESTING_API) { | |
| // 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 (process.env.__NEXT_EXPOSE_TESTING_API) { | |
| writeCookieValue([ | |
| 1, | |
| `c${Math.random()}`, | |
| { | |
| from: fromTree, | |
| to: toTree | |
| } | |
| ]); | |
| } | |
| } | |
| function updateCapturedSPAToTree(fromTree, toTree) { | |
| if (process.env.__NEXT_EXPOSE_TESTING_API) { | |
| writeCookieValue([ | |
| 1, | |
| `c${Math.random()}`, | |
| { | |
| from: fromTree, | |
| to: toTree | |
| } | |
| ]); | |
| } | |
| } | |
| function isNavigationLocked() { | |
| if (process.env.__NEXT_EXPOSE_TESTING_API) { | |
| return lockState !== null; | |
| } | |
| return false; | |
| } | |
| async function waitForNavigationLockIfActive() { | |
| if (process.env.__NEXT_EXPOSE_TESTING_API) { | |
| 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; | |
| } | |
| //# sourceMappingURL=navigation-testing-lock.js.map |