"use client"; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getServerActionDispatcher: null, urlToUrlWithoutFlightMarker: null, default: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getServerActionDispatcher: function() { return getServerActionDispatcher; }, urlToUrlWithoutFlightMarker: function() { return urlToUrlWithoutFlightMarker; }, default: function() { return AppRouter; } }); const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard"); const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react")); const _approutercontextsharedruntime = require("../../shared/lib/app-router-context.shared-runtime"); const _routerreducer = require("./router-reducer/router-reducer"); const _routerreducertypes = require("./router-reducer/router-reducer-types"); const _createhreffromurl = require("./router-reducer/create-href-from-url"); const _hooksclientcontextsharedruntime = require("../../shared/lib/hooks-client-context.shared-runtime"); const _usereducerwithdevtools = require("./use-reducer-with-devtools"); const _errorboundary = require("./error-boundary"); const _createinitialrouterstate = require("./router-reducer/create-initial-router-state"); const _isbot = require("../../shared/lib/router/utils/is-bot"); const _addbasepath = require("../add-base-path"); const _approuterannouncer = require("./app-router-announcer"); const _redirectboundary = require("./redirect-boundary"); const _findheadincache = require("./router-reducer/reducers/find-head-in-cache"); const _infinitepromise = require("./infinite-promise"); const _approuterheaders = require("./app-router-headers"); const _removebasepath = require("../remove-base-path"); const _hasbasepath = require("../has-base-path"); const isServer = typeof window === "undefined"; // Ensure the initialParallelRoutes are not combined because of double-rendering in the browser with Strict Mode. let initialParallelRoutes = isServer ? null : new Map(); let globalServerActionDispatcher = null; function getServerActionDispatcher() { return globalServerActionDispatcher; } let globalMutable = { refresh: ()=>{} }; function urlToUrlWithoutFlightMarker(url) { const urlWithoutFlightParameters = new URL(url, location.origin); urlWithoutFlightParameters.searchParams.delete(_approuterheaders.NEXT_RSC_UNION_QUERY); if (process.env.NODE_ENV === "production") { if (process.env.__NEXT_CONFIG_OUTPUT === "export" && urlWithoutFlightParameters.pathname.endsWith(".txt")) { const { pathname } = urlWithoutFlightParameters; const length = pathname.endsWith("/index.txt") ? 10 : 4; // Slice off `/index.txt` or `.txt` from the end of the pathname urlWithoutFlightParameters.pathname = pathname.slice(0, -length); } } return urlWithoutFlightParameters; } function isExternalURL(url) { return url.origin !== window.location.origin; } function HistoryUpdater(param) { let { tree, pushRef, canonicalUrl, sync } = param; (0, _react.useInsertionEffect)(()=>{ // Identifier is shortened intentionally. // __NA is used to identify if the history entry can be handled by the app-router. // __N is used to identify if the history entry can be handled by the old router. const historyState = { __NA: true, tree }; if (pushRef.pendingPush && (0, _createhreffromurl.createHrefFromUrl)(new URL(window.location.href)) !== canonicalUrl) { // This intentionally mutates React state, pushRef is overwritten to ensure additional push/replace calls do not trigger an additional history entry. pushRef.pendingPush = false; window.history.pushState(historyState, "", canonicalUrl); } else { window.history.replaceState(historyState, "", canonicalUrl); } sync(); }, [ tree, pushRef, canonicalUrl, sync ]); return null; } const createEmptyCacheNode = ()=>({ status: _approutercontextsharedruntime.CacheStates.LAZY_INITIALIZED, data: null, subTreeData: null, parallelRoutes: new Map() }); function useServerActionDispatcher(dispatch) { const serverActionDispatcher = (0, _react.useCallback)((actionPayload)=>{ (0, _react.startTransition)(()=>{ dispatch({ ...actionPayload, type: _routerreducertypes.ACTION_SERVER_ACTION, mutable: { globalMutable }, cache: createEmptyCacheNode() }); }); }, [ dispatch ]); globalServerActionDispatcher = serverActionDispatcher; } /** * Server response that only patches the cache and tree. */ function useChangeByServerResponse(dispatch) { return (0, _react.useCallback)((previousTree, flightData, overrideCanonicalUrl)=>{ (0, _react.startTransition)(()=>{ dispatch({ type: _routerreducertypes.ACTION_SERVER_PATCH, flightData, previousTree, overrideCanonicalUrl, cache: createEmptyCacheNode(), mutable: { globalMutable } }); }); }, [ dispatch ]); } function useNavigate(dispatch) { return (0, _react.useCallback)((href, navigateType, forceOptimisticNavigation, shouldScroll)=>{ const url = new URL((0, _addbasepath.addBasePath)(href), location.href); globalMutable.pendingNavigatePath = (0, _createhreffromurl.createHrefFromUrl)(url); return dispatch({ type: _routerreducertypes.ACTION_NAVIGATE, url, isExternalUrl: isExternalURL(url), locationSearch: location.search, forceOptimisticNavigation, shouldScroll: shouldScroll != null ? shouldScroll : true, navigateType, cache: createEmptyCacheNode(), mutable: { globalMutable } }); }, [ dispatch ]); } /** * The global router that wraps the application components. */ function Router(param) { let { buildId, initialHead, initialTree, initialCanonicalUrl, children, assetPrefix } = param; const initialState = (0, _react.useMemo)(()=>(0, _createinitialrouterstate.createInitialRouterState)({ buildId, children, initialCanonicalUrl, initialTree, initialParallelRoutes, isServer, location: !isServer ? window.location : null, initialHead }), [ buildId, children, initialCanonicalUrl, initialTree, initialHead ]); const [{ tree, cache, prefetchCache, pushRef, focusAndScrollRef, canonicalUrl, nextUrl }, dispatch, sync] = (0, _usereducerwithdevtools.useReducerWithReduxDevtools)(_routerreducer.reducer, initialState); (0, _react.useEffect)(()=>{ // Ensure initialParallelRoutes is cleaned up from memory once it's used. initialParallelRoutes = null; }, []); // Add memoized pathname/query for useSearchParams and usePathname. const { searchParams, pathname } = (0, _react.useMemo)(()=>{ const url = new URL(canonicalUrl, typeof window === "undefined" ? "http://n" : window.location.href); return { // This is turned into a readonly class in `useSearchParams` searchParams: url.searchParams, pathname: (0, _hasbasepath.hasBasePath)(url.pathname) ? (0, _removebasepath.removeBasePath)(url.pathname) : url.pathname }; }, [ canonicalUrl ]); const changeByServerResponse = useChangeByServerResponse(dispatch); const navigate = useNavigate(dispatch); useServerActionDispatcher(dispatch); /** * The app router that is exposed through `useRouter`. It's only concerned with dispatching actions to the reducer, does not hold state. */ const appRouter = (0, _react.useMemo)(()=>{ const routerInstance = { back: ()=>window.history.back(), forward: ()=>window.history.forward(), prefetch: (href, options)=>{ // Don't prefetch for bots as they don't navigate. // Don't prefetch during development (improves compilation performance) if ((0, _isbot.isBot)(window.navigator.userAgent) || process.env.NODE_ENV === "development") { return; } const url = new URL((0, _addbasepath.addBasePath)(href), location.href); // External urls can't be prefetched in the same way. if (isExternalURL(url)) { return; } (0, _react.startTransition)(()=>{ var _options_kind; dispatch({ type: _routerreducertypes.ACTION_PREFETCH, url, kind: (_options_kind = options == null ? void 0 : options.kind) != null ? _options_kind : _routerreducertypes.PrefetchKind.FULL }); }); }, replace: (href, options)=>{ if (options === void 0) options = {}; (0, _react.startTransition)(()=>{ var _options_scroll; navigate(href, "replace", Boolean(options.forceOptimisticNavigation), (_options_scroll = options.scroll) != null ? _options_scroll : true); }); }, push: (href, options)=>{ if (options === void 0) options = {}; (0, _react.startTransition)(()=>{ var _options_scroll; navigate(href, "push", Boolean(options.forceOptimisticNavigation), (_options_scroll = options.scroll) != null ? _options_scroll : true); }); }, refresh: ()=>{ (0, _react.startTransition)(()=>{ dispatch({ type: _routerreducertypes.ACTION_REFRESH, cache: createEmptyCacheNode(), mutable: { globalMutable }, origin: window.location.origin }); }); }, // @ts-ignore we don't want to expose this method at all fastRefresh: ()=>{ if (process.env.NODE_ENV !== "development") { throw new Error("fastRefresh can only be used in development mode. Please use refresh instead."); } else { (0, _react.startTransition)(()=>{ dispatch({ type: _routerreducertypes.ACTION_FAST_REFRESH, cache: createEmptyCacheNode(), mutable: { globalMutable }, origin: window.location.origin }); }); } } }; return routerInstance; }, [ dispatch, navigate ]); (0, _react.useEffect)(()=>{ // Exists for debugging purposes. Don't use in application code. if (window.next) { window.next.router = appRouter; } }, [ appRouter ]); (0, _react.useEffect)(()=>{ globalMutable.refresh = appRouter.refresh; }, [ appRouter.refresh ]); if (process.env.NODE_ENV !== "production") { // This hook is in a conditional but that is ok because `process.env.NODE_ENV` never changes // eslint-disable-next-line react-hooks/rules-of-hooks (0, _react.useEffect)(()=>{ // Add `window.nd` for debugging purposes. // This is not meant for use in applications as concurrent rendering will affect the cache/tree/router. // @ts-ignore this is for debugging window.nd = { router: appRouter, cache, prefetchCache, tree }; }, [ appRouter, cache, prefetchCache, tree ]); } (0, _react.useEffect)(()=>{ // If the app is restored from bfcache, it's possible that // pushRef.mpaNavigation is true, which would mean that any re-render of this component // would trigger the mpa navigation logic again from the lines below. // This will restore the router to the initial state in the event that the app is restored from bfcache. function handlePageShow(event) { var _window_history_state; if (!event.persisted || !((_window_history_state = window.history.state) == null ? void 0 : _window_history_state.tree)) return; dispatch({ type: _routerreducertypes.ACTION_RESTORE, url: new URL(window.location.href), tree: window.history.state.tree }); } window.addEventListener("pageshow", handlePageShow); return ()=>{ window.removeEventListener("pageshow", handlePageShow); }; }, [ dispatch ]); // When mpaNavigation flag is set do a hard navigation to the new url. // Infinitely suspend because we don't actually want to rerender any child // components with the new URL and any entangled state updates shouldn't // commit either (eg: useTransition isPending should stay true until the page // unloads). // // This is a side effect in render. Don't try this at home, kids. It's // probably safe because we know this is a singleton component and it's never // in . At least I hope so. (It will run twice in dev strict mode, // but that's... fine?) if (pushRef.mpaNavigation) { // if there's a re-render, we don't want to trigger another redirect if one is already in flight to the same URL if (globalMutable.pendingMpaPath !== canonicalUrl) { const location1 = window.location; if (pushRef.pendingPush) { location1.assign(canonicalUrl); } else { location1.replace(canonicalUrl); } globalMutable.pendingMpaPath = canonicalUrl; } // TODO-APP: Should we listen to navigateerror here to catch failed // navigations somehow? And should we call window.stop() if a SPA navigation // should interrupt an MPA one? (0, _react.use)((0, _infinitepromise.createInfinitePromise)()); } /** * Handle popstate event, this is used to handle back/forward in the browser. * By default dispatches ACTION_RESTORE, however if the history entry was not pushed/replaced by app-router it will reload the page. * That case can happen when the old router injected the history entry. */ const onPopState = (0, _react.useCallback)((param)=>{ let { state } = param; if (!state) { // TODO-APP: this case only happens when pushState/replaceState was called outside of Next.js. It should probably reload the page in this case. return; } // This case happens when the history entry was pushed by the `pages` router. if (!state.__NA) { window.location.reload(); return; } // @ts-ignore useTransition exists // TODO-APP: Ideally the back button should not use startTransition as it should apply the updates synchronously // Without startTransition works if the cache is there for this path (0, _react.startTransition)(()=>{ dispatch({ type: _routerreducertypes.ACTION_RESTORE, url: new URL(window.location.href), tree: state.tree }); }); }, [ dispatch ]); // Register popstate event to call onPopstate. (0, _react.useEffect)(()=>{ window.addEventListener("popstate", onPopState); return ()=>{ window.removeEventListener("popstate", onPopState); }; }, [ onPopState ]); const head = (0, _react.useMemo)(()=>{ return (0, _findheadincache.findHeadInCache)(cache, tree[1]); }, [ cache, tree ]); let content = /*#__PURE__*/ _react.default.createElement(_redirectboundary.RedirectBoundary, null, head, cache.subTreeData, /*#__PURE__*/ _react.default.createElement(_approuterannouncer.AppRouterAnnouncer, { tree: tree })); if (process.env.NODE_ENV !== "production") { if (typeof window !== "undefined") { const DevRootNotFoundBoundary = require("./dev-root-not-found-boundary").DevRootNotFoundBoundary; content = /*#__PURE__*/ _react.default.createElement(DevRootNotFoundBoundary, null, content); } const HotReloader = require("./react-dev-overlay/hot-reloader-client").default; content = /*#__PURE__*/ _react.default.createElement(HotReloader, { assetPrefix: assetPrefix }, content); } return /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/ _react.default.createElement(HistoryUpdater, { tree: tree, pushRef: pushRef, canonicalUrl: canonicalUrl, sync: sync }), /*#__PURE__*/ _react.default.createElement(_hooksclientcontextsharedruntime.PathnameContext.Provider, { value: pathname }, /*#__PURE__*/ _react.default.createElement(_hooksclientcontextsharedruntime.SearchParamsContext.Provider, { value: searchParams }, /*#__PURE__*/ _react.default.createElement(_approutercontextsharedruntime.GlobalLayoutRouterContext.Provider, { value: { buildId, changeByServerResponse, tree, focusAndScrollRef, nextUrl } }, /*#__PURE__*/ _react.default.createElement(_approutercontextsharedruntime.AppRouterContext.Provider, { value: appRouter }, /*#__PURE__*/ _react.default.createElement(_approutercontextsharedruntime.LayoutRouterContext.Provider, { value: { childNodes: cache.parallelRoutes, tree: tree, // Root node always has `url` // Provided in AppTreeContext to ensure it can be overwritten in layout-router url: canonicalUrl } }, content)))))); } function AppRouter(props) { const { globalErrorComponent, ...rest } = props; return /*#__PURE__*/ _react.default.createElement(_errorboundary.ErrorBoundary, { errorComponent: globalErrorComponent }, /*#__PURE__*/ _react.default.createElement(Router, rest)); } 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=app-router.js.map