"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "renderToHTMLOrFlight", { enumerable: true, get: function() { return renderToHTMLOrFlight; } }); const _jsxruntime = require("react/jsx-runtime"); const _workasyncstorageexternal = require("../app-render/work-async-storage.external"); const _react = /*#__PURE__*/ _interop_require_wildcard(require("react")); const _renderresult = /*#__PURE__*/ _interop_require_default(require("../render-result")); const _streamops = require("./stream-ops"); const _internalutils = require("../internal-utils"); const _approuterheaders = require("../../client/components/app-router-headers"); const _metadatacontext = require("../../lib/metadata/metadata-context"); const _requeststore = require("../async-storage/request-store"); const _workstore = require("../async-storage/work-store"); const _httpaccessfallback = require("../../client/components/http-access-fallback/http-access-fallback"); const _redirect = require("../../client/components/redirect"); const _redirecterror = require("../../client/components/redirect-error"); const _implicittags = require("../lib/implicit-tags"); const _constants = require("../lib/trace/constants"); const _tracer = require("../lib/trace/tracer"); const _flightrenderresult = require("./flight-render-result"); const _createerrorhandler = require("./create-error-handler"); const _getshortdynamicparamtype = require("./get-short-dynamic-param-type"); const _getsegmentparam = require("../../shared/lib/router/utils/get-segment-param"); const _getscriptnoncefromheader = require("./get-script-nonce-from-header"); const _parseandvalidateflightrouterstate = require("./parse-and-validate-flight-router-state"); const _createflightrouterstatefromloadertree = require("./create-flight-router-state-from-loader-tree"); const _actionhandler = require("./action-handler"); const _bailouttocsr = require("../../shared/lib/lazy-dynamic/bailout-to-csr"); const _log = require("../../build/output/log"); const _requestcookies = require("../web/spec-extension/adapters/request-cookies"); const _serverinsertedhtml = require("./server-inserted-html"); const _requiredscripts = require("./required-scripts"); const _addpathprefix = require("../../shared/lib/router/utils/add-path-prefix"); const _makegetserverinsertedhtml = require("./make-get-server-inserted-html"); const _walktreewithflightrouterstate = require("./walk-tree-with-flight-router-state"); const _createcomponenttree = require("./create-component-tree"); const _getassetquerystring = require("./get-asset-query-string"); const _manifestssingleton = require("./manifests-singleton"); const _postponedstate = require("./postponed-state"); const _hooksservercontext = require("../../client/components/hooks-server-context"); const _useflightresponse = require("./use-flight-response"); const _staticgenerationbailout = require("../../client/components/static-generation-bailout"); const _formatservererror = require("../../lib/format-server-error"); const _errortelemetryutils = require("../../lib/error-telemetry-utils"); const _dynamicrendering = require("./dynamic-rendering"); const _clientcomponentrendererlogger = require("../client-component-renderer-logger"); const _helpers = require("../base-http/helpers"); const _parserelativeurl = require("../../shared/lib/router/utils/parse-relative-url"); const _approuter = /*#__PURE__*/ _interop_require_default(require("../../client/components/app-router")); const _serveractionrequestmeta = require("../lib/server-action-request-meta"); const _createinitialrouterstate = require("../../client/components/router-reducer/create-initial-router-state"); const _approuterinstance = require("../../client/components/app-router-instance"); const _utils = require("../instrumentation/utils"); const _segment = require("../../shared/lib/segment"); const _fallbackparams = require("../request/fallback-params"); const _apprenderprerenderutils = require("./app-render-prerender-utils"); const _prospectiverenderutils = require("./prospective-render-utils"); const _apprenderrenderutils = require("./app-render-render-utils"); const _scheduler = require("../../lib/scheduler"); const _workunitasyncstorageexternal = require("./work-unit-async-storage.external"); const _consoleasyncstorageexternal = require("./console-async-storage.external"); const _cachesignal = require("./cache-signal"); const _varyparams = require("./vary-params"); const _utils1 = require("../lib/trace/utils"); const _invarianterror = require("../../shared/lib/invariant-error"); const _staletime = require("./stale-time"); const _constants1 = require("../../lib/constants"); const _createcomponentstylesandscripts = require("./create-component-styles-and-scripts"); const _parseloadertree = require("../../shared/lib/router/utils/parse-loader-tree"); const _resumedatacache = require("../resume-data-cache/resume-data-cache"); const _iserror = /*#__PURE__*/ _interop_require_default(require("../../lib/is-error")); const _createserverinsertedmetadata = require("./metadata-insertion/create-server-inserted-metadata"); const _serverutils = require("../server-utils"); const _revalidationutils = require("../revalidation-utils"); const _trackmoduleloadingexternal = require("./module-loading/track-module-loading.external"); const _reactlargeshellerror = require("./react-large-shell-error"); const _segmentexplorerpath = require("./segment-explorer-path"); const _requestmeta = require("../request-meta"); const _getdynamicparam = require("../../shared/lib/router/utils/get-dynamic-param"); const _imageconfigcontextsharedruntime = require("../../shared/lib/image-config-context.shared-runtime"); const _imageconfig = require("../../shared/lib/image-config"); const _stagedrendering = require("./staged-rendering"); const _instantconfig = require("./instant-validation/instant-config"); const _warnonce = require("../../shared/lib/utils/warn-once"); const _debugchannelserver = require("./debug-channel-server"); const _streamutils = require("./instant-validation/stream-utils"); const _boundarytracking = require("./instant-validation/boundary-tracking"); const _cookies = require("../web/spec-extension/cookies"); const _instantvalidationerror = require("./instant-validation/instant-validation-error"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = { __proto__: null }; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function maybeAppendBuildIdToRSCPayload(ctx, payload) { if (!ctx.sharedContext.deploymentId) { // When using the build id, we need to initialize the id on initial page load, so a build id // header wouldn't be enough. payload.b = ctx.sharedContext.buildId; } return payload; } const flightDataPathHeadKey = 'h'; const getFlightViewportKey = (requestId)=>requestId + 'v'; const getFlightMetadataKey = (requestId)=>requestId + 'm'; const filterStackFrame = process.env.NODE_ENV !== 'production' ? require('../lib/source-maps').filterStackFrameDEV : undefined; function parseRequestHeaders(headers, options) { // runtime prefetch requests are *not* treated as prefetch requests // (TODO: this is confusing, we should refactor this to express this better) const isPrefetchRequest = headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '1'; const isRuntimePrefetchRequest = headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '2'; const isHmrRefresh = headers[_approuterheaders.NEXT_HMR_REFRESH_HEADER] !== undefined; const isRSCRequest = headers[_approuterheaders.RSC_HEADER] !== undefined; const shouldProvideFlightRouterState = isRSCRequest && (!isPrefetchRequest || !options.isRoutePPREnabled); const flightRouterState = shouldProvideFlightRouterState ? (0, _parseandvalidateflightrouterstate.parseAndValidateFlightRouterState)(headers[_approuterheaders.NEXT_ROUTER_STATE_TREE_HEADER]) : undefined; // Checks if this is a prefetch of the Route Tree by the Segment Cache const isRouteTreePrefetchRequest = headers[_approuterheaders.NEXT_ROUTER_SEGMENT_PREFETCH_HEADER] === '/_tree'; const csp = headers['content-security-policy'] || headers['content-security-policy-report-only']; const nonce = typeof csp === 'string' ? (0, _getscriptnoncefromheader.getScriptNonceFromHeader)(csp) : undefined; const previouslyRevalidatedTags = (0, _serverutils.getPreviouslyRevalidatedTags)(headers, options.previewModeId); let requestId; let htmlRequestId; if (process.env.__NEXT_DEV_SERVER) { // The request IDs are only used for the dev server to send debug // information to the matching client (identified by the HTML request ID // that was sent to the client with the HTML document) for the current // request (identified by the request ID, as defined by the client). requestId = typeof headers[_approuterheaders.NEXT_REQUEST_ID_HEADER] === 'string' ? headers[_approuterheaders.NEXT_REQUEST_ID_HEADER] : undefined; htmlRequestId = typeof headers[_approuterheaders.NEXT_HTML_REQUEST_ID_HEADER] === 'string' ? headers[_approuterheaders.NEXT_HTML_REQUEST_ID_HEADER] : undefined; } return { flightRouterState, isPrefetchRequest, isRuntimePrefetchRequest, isRouteTreePrefetchRequest, isHmrRefresh, isRSCRequest, nonce, previouslyRevalidatedTags, requestId, htmlRequestId }; } /** * Walks the loader tree to find the minimum `unstable_dynamicStaleTime` exported by * any page module. Returns null if no page exports the config. * * This only reads static exports from page modules — it does not render any * server components, so it's cheap to call. * * TODO: Move this to the prefetch hints file so we don't have to walk the * tree on every render. */ async function getDynamicStaleTime(tree) { const { page, parallelRoutes } = (0, _parseloadertree.parseLoaderTree)(tree); let result = null; // Only pages (not layouts) can export unstable_dynamicStaleTime. if (typeof page !== 'undefined') { const pageMod = await page[0](); if (pageMod && typeof pageMod.unstable_dynamicStaleTime === 'number') { const value = pageMod.unstable_dynamicStaleTime; result = result !== null ? Math.min(result, value) : value; } } const childPromises = []; for(const parallelRouteKey in parallelRoutes){ childPromises.push(getDynamicStaleTime(parallelRoutes[parallelRouteKey])); } const childResults = await Promise.all(childPromises); for (const childResult of childResults){ if (childResult !== null) { result = result !== null ? Math.min(result, childResult) : childResult; } } return result; } function createNotFoundLoaderTree(loaderTree) { const components = loaderTree[2]; const hasGlobalNotFound = !!components['global-not-found']; const notFoundTreeComponents = hasGlobalNotFound ? { layout: components['global-not-found'], page: [ ()=>null, 'next/dist/client/components/builtin/empty-stub' ] } : { page: components['not-found'] }; return [ '', { children: [ _segment.PAGE_SEGMENT_KEY, {}, notFoundTreeComponents, null ] }, // Always include global-error so that getGlobalErrorStyles can access it. // When global-not-found is present, use full components. // Otherwise, only include global-error module. hasGlobalNotFound ? components : { 'global-error': components['global-error'] }, null ]; } /** * Returns a function that parses the dynamic segment and return the associated value. */ function makeGetDynamicParamFromSegment(interpolatedParams, fallbackRouteParams, optimisticRouting) { return function getDynamicParamFromSegment(loaderTree) { const [segment, , , staticSiblings] = loaderTree; const segmentParam = (0, _getsegmentparam.getSegmentParam)(segment); if (!segmentParam) { return null; } const segmentKey = segmentParam.paramName; const dynamicParamType = _getshortdynamicparamtype.dynamicParamTypes[segmentParam.paramType]; // Static siblings are only included when optimistic routing is enabled const siblings = optimisticRouting ? staticSiblings : null; return (0, _getdynamicparam.getDynamicParam)(interpolatedParams, segmentKey, dynamicParamType, fallbackRouteParams, siblings); }; } function NonIndex({ createElement, pagePath, statusCode, isPossibleServerAction }) { const is404Page = pagePath === '/404'; const isInvalidStatusCode = typeof statusCode === 'number' && statusCode > 400; // Only render noindex for page request, skip for server actions // TODO: is this correct if `isPossibleServerAction` is a false positive? if (!isPossibleServerAction && (is404Page || isInvalidStatusCode)) { return createElement('meta', { name: 'robots', content: 'noindex' }); } return null; } /** * This is used by server actions & client-side navigations to generate RSC data from a client-side request. * This function is only called on "dynamic" requests (ie, there wasn't already a static response). * It uses request headers (namely `next-router-state-tree`) to determine where to start rendering. */ async function generateDynamicRSCPayload(ctx, options) { // Flight data that is going to be passed to the browser. // Currently a single item array but in the future multiple patches might be combined in a single request. // We initialize `flightData` to an empty string because the client router knows how to tolerate // it (treating it as an MPA navigation). The only time this function wouldn't generate flight data // is for server actions, if the server action handler instructs this function to skip it. When the server // action reducer sees a falsy value, it'll simply resolve the action with no data. let flightData = ''; const { componentMod: { routeModule: { userland: { loaderTree } }, createElement, createMetadataComponents, Fragment }, query, requestId, flightRouterState, workStore, url } = ctx; const serveStreamingMetadata = !!ctx.renderOpts.serveStreamingMetadata; if (!(options == null ? void 0 : options.skipPageRendering)) { var _ctx_renderOpts_prefetchHints; const preloadCallbacks = []; // If we're performing instant validation, we need to render the whole tree, // without skipping shared layouts. const needsFullTree = process.env.__NEXT_DEV_SERVER && ctx.renderOpts.cacheComponents && !(options == null ? void 0 : options.actionResult) && // Only for navigations await (0, _instantconfig.anySegmentNeedsInstantValidationInDev)(loaderTree); const metadataIsRuntimePrefetchable = await (0, _instantconfig.anySegmentHasRuntimePrefetchEnabled)(loaderTree); const { Viewport, Metadata, MetadataOutlet } = createMetadataComponents({ tree: loaderTree, parsedQuery: query, pathname: url.pathname, metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts), interpolatedParams: ctx.interpolatedParams, serveStreamingMetadata, isRuntimePrefetchable: metadataIsRuntimePrefetchable }); const rscHead = createElement(Fragment, { key: flightDataPathHeadKey }, createElement(NonIndex, { createElement, pagePath: ctx.pagePath, statusCode: ctx.res.statusCode, isPossibleServerAction: ctx.isPossibleServerAction }), createElement(Viewport, { key: getFlightViewportKey(requestId) }), createElement(Metadata, { key: getFlightMetadataKey(requestId) })); flightData = (needsFullTree ? await (0, _walktreewithflightrouterstate.createFullTreeFlightDataForNavigation)({ ctx, loaderTree, rscHead, injectedCSS: new Set(), injectedJS: new Set(), injectedFontPreloadTags: new Set(), preloadCallbacks, MetadataOutlet }) : await (0, _walktreewithflightrouterstate.walkTreeWithFlightRouterState)({ ctx, loaderTreeToFilter: loaderTree, parentParams: {}, flightRouterState, rscHead, injectedCSS: new Set(), injectedJS: new Set(), injectedFontPreloadTags: new Set(), rootLayoutIncluded: false, preloadCallbacks, MetadataOutlet, hintTree: ((_ctx_renderOpts_prefetchHints = ctx.renderOpts.prefetchHints) == null ? void 0 : _ctx_renderOpts_prefetchHints[ctx.pagePath]) ?? null })).map((path)=>path.slice(1)) // remove the '' (root) segment ; } // In dev, the Vary header may not reliably reflect whether a route can // be intercepted, because interception routes are compiled on demand. // Default to true so the client doesn't cache a stale Fallback entry. const varyHeader = ctx.res.getHeader('vary'); const couldBeIntercepted = !!process.env.__NEXT_DEV_SERVER || typeof varyHeader === 'string' && varyHeader.includes(_approuterheaders.NEXT_URL); // If we have an action result, then this is a server action response. // We can rely on this because `ActionResult` will always be a promise, even if // the result is falsey. if (options == null ? void 0 : options.actionResult) { return maybeAppendBuildIdToRSCPayload(ctx, { a: options.actionResult, f: flightData, q: getRenderedSearch(query), i: !!couldBeIntercepted }); } // Otherwise, it's a regular RSC response. const baseResponse = maybeAppendBuildIdToRSCPayload(ctx, { f: flightData, q: getRenderedSearch(query), i: !!couldBeIntercepted, S: workStore.isStaticGeneration, h: (0, _varyparams.getMetadataVaryParamsThenable)() }); if ((options == null ? void 0 : options.staleTimeIterable) !== undefined) { baseResponse.s = options.staleTimeIterable; } if ((options == null ? void 0 : options.staticStageByteLengthPromise) !== undefined) { baseResponse.l = options.staticStageByteLengthPromise; } if ((options == null ? void 0 : options.runtimePrefetchStream) !== undefined) { baseResponse.p = options.runtimePrefetchStream; } // Include the per-page dynamic stale time from unstable_dynamicStaleTime, but only // for dynamic renders (not prerenders/static generation). The client treats // its presence as authoritative. // TODO: Move this to the prefetch hints file so we don't have to walk the // tree on every render. if (!workStore.isStaticGeneration) { const dynamicStaleTime = await getDynamicStaleTime(ctx.componentMod.routeModule.userland.loaderTree); if (dynamicStaleTime !== null) { baseResponse.d = dynamicStaleTime; } } return baseResponse; } function createErrorContext(ctx, renderSource) { return { routerKind: 'App Router', routePath: ctx.pagePath, // TODO: is this correct if `isPossibleServerAction` is a false positive? routeType: ctx.isPossibleServerAction ? 'action' : 'render', renderSource, revalidateReason: (0, _utils.getRevalidateReason)(ctx.workStore) }; } /** * Produces a RenderResult containing the Flight data for the given request. See * `generateDynamicRSCPayload` for information on the contents of the render result. */ async function generateDynamicFlightRenderResult(req, ctx, requestStore, options) { const { htmlRequestId, renderOpts, requestId, workStore } = ctx; const { onInstrumentationRequestError, setReactDebugChannel, isBuildTimePrerendering = false } = renderOpts; function onFlightDataRenderError(err, silenceLog) { return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'react-server-components-payload'), silenceLog); } const onError = (0, _createerrorhandler.createReactServerErrorHandler)(process.env.NODE_ENV === 'development', isBuildTimePrerendering, workStore.reactServerErrorsByDigest, onFlightDataRenderError); const debugChannel = setReactDebugChannel && (0, _debugchannelserver.createDebugChannel)(); if (debugChannel) { setReactDebugChannel(debugChannel.clientSide, htmlRequestId, requestId); } const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); // For app dir, use the bundled version of Flight server renderer (renderToReadableStream) // which contains the subset React. const rscPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, generateDynamicRSCPayload, ctx, options); const flightStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ctx.componentMod, rscPayload, clientModules, { onError, temporaryReferences: options == null ? void 0 : options.temporaryReferences, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide }); return new _flightrenderresult.FlightRenderResult(flightStream, { fetchMetrics: workStore.fetchMetrics }, options == null ? void 0 : options.waitUntil); } /** * Production-only staged dynamic flight render for cache components. Uses * staged rendering to separate static (RDC-backed) from runtime/dynamic * content. */ async function generateStagedDynamicFlightRenderResult(req, ctx, requestStore) { const { componentMod, workStore, renderOpts } = ctx; const { renderToReadableStream, routeModule } = componentMod; const { loaderTree } = routeModule.userland; const { onInstrumentationRequestError, experimental } = renderOpts; function onFlightDataRenderError(err, silenceLog) { return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'react-server-components-payload'), silenceLog); } const onError = (0, _createerrorhandler.createReactServerErrorHandler)(false, false, workStore.reactServerErrorsByDigest, onFlightDataRenderError); const selectStaleTime = (0, _staletime.createSelectStaleTime)(experimental); const staleTimeIterable = new _staletime.StaleTimeIterable(); // TODO(cached-navs): this assumes that we checked during build that there's no sync IO. // but it can happen e.g. after a revalidation or conditionally for a param that wasn't prerendered. // we should change this to track sync IO, log an error and advance to dynamic. const shouldTrackSyncIO = false; const stageController = new _stagedrendering.StagedRenderingController(null, null, shouldTrackSyncIO); // Initialize stale time tracking on the request store. requestStore.stale = _constants1.INFINITE_CACHE; requestStore.stagedRendering = stageController; requestStore.asyncApiPromises = createAsyncApiPromises(stageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); (0, _staletime.trackStaleTime)(requestStore, staleTimeIterable, selectStaleTime); // Deferred promise for the static stage byte length. Flight serializes the // resolved value into the stream so the client knows where the static // prefix ends. let resolveStaticStageByteLength; const staticStageByteLengthPromise = new Promise((resolve)=>{ resolveStaticStageByteLength = resolve; }); // Check if this route has opted into runtime prefetching via // unstable_instant. If so, we piggyback on the dynamic render to fill caches // and then spawn a final runtime prerender whose result stream is embedded in // the RSC payload. This is gated on the explicit opt-in because it adds extra // server processing, increases the response payload size, and the runtime // prefetch output should have been validated first. const hasRuntimePrefetch = await (0, _instantconfig.anySegmentHasRuntimePrefetchEnabled)(loaderTree); let runtimePrefetchStream; if (hasRuntimePrefetch) { // Create a mutable cache that gets filled during the dynamic render. const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); requestStore.prerenderResumeDataCache = prerenderResumeDataCache; const cacheSignal = new _cachesignal.CacheSignal(); (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); requestStore.cacheSignal = cacheSignal; // Create a deferred stream for the runtime prefetch result. Its readable // side goes into the RSC payload (Flight serializes it lazily). The // writable side receives the runtime prerender result once the dynamic // render has filled all caches. const runtimePrefetchTransform = new TransformStream(); runtimePrefetchStream = runtimePrefetchTransform.readable; // Wait for the dynamic render to fill caches, then run the final runtime // prerender (fire-and-forget — does not block the response). void cacheSignal.cacheReady().then(()=>spawnRuntimePrefetchWithFilledCaches(runtimePrefetchTransform.writable, ctx, prerenderResumeDataCache, requestStore, onError)); } const rscPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, generateDynamicRSCPayload, ctx, { staleTimeIterable, staticStageByteLengthPromise, runtimePrefetchStream }); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const flightReadableStream = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Static); const stream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, renderToReadableStream, rscPayload, clientModules, { onError, filterStackFrame }); const [dynamicStream, staticStream] = stream.tee(); countStaticStageBytes(staticStream, stageController).then(resolveStaticStageByteLength); return dynamicStream; }, ()=>{ // This is a separate task that doesn't advance a stage. It forces // draining the microtask queue so that the stale time iterable is closed // before we advance to the dynamic stage. void (0, _staletime.finishStaleTimeTracking)(staleTimeIterable); }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); return new _flightrenderresult.FlightRenderResult(flightReadableStream, { fetchMetrics: workStore.fetchMetrics }); } /** * Runs a final runtime prerender using the provided (already filled) cache and * pipes its output into the provided writable stream. The caller is responsible * for waiting until caches are warm before calling this function. */ async function spawnRuntimePrefetchWithFilledCaches(writable, ctx, prerenderResumeDataCache, requestStore, onError) { try { const { componentMod, getDynamicParamFromSegment } = ctx; const { loaderTree } = componentMod.routeModule.userland; const rootParams = (0, _createcomponenttree.getRootParams)(loaderTree, getDynamicParamFromSegment); const staleTimeIterable = new _staletime.StaleTimeIterable(); const { result } = await finalRuntimeServerPrerender(ctx, generateDynamicRSCPayload.bind(null, ctx, { staleTimeIterable }), prerenderResumeDataCache, null, rootParams, requestStore.headers, requestStore.cookies, requestStore.draftMode, onError, staleTimeIterable); await result.prelude.pipeTo(writable); } catch { // Runtime prerender failed. Close the stream gracefully — the navigation // still works, we just won't get cached runtime data. try { await writable.close(); } catch { // Writable may already be closed/errored. } } } async function stagedRenderToReadableStreamWithoutCachesInDev(ctx, requestStore, getPayload, options) { // We're rendering while bypassing caches, // so we have no hope of showing a useful runtime stage. // But we still want things like `params` to show up in devtools correctly, // which relies on mechanisms we've set up for staged rendering, // so we do a 2-task version (Static -> Dynamic) instead. // We aren't filling caches so we don't need to abort this render, it'll // stream in a single pass const stageController = new _stagedrendering.StagedRenderingController(null, null, false // do not track sync IO (we don't have reliable stages) ); const environmentName = ()=>{ const currentStage = stageController.currentStage; switch(currentStage){ case _stagedrendering.RenderStage.Before: case _stagedrendering.RenderStage.EarlyStatic: case _stagedrendering.RenderStage.Static: return 'Prerender'; case _stagedrendering.RenderStage.EarlyRuntime: case _stagedrendering.RenderStage.Runtime: case _stagedrendering.RenderStage.Dynamic: case _stagedrendering.RenderStage.Abandoned: return 'Server'; default: currentStage; throw Object.defineProperty(new _invarianterror.InvariantError(`Invalid render stage: ${currentStage}`), "__NEXT_ERROR_CODE", { value: "E881", enumerable: false, configurable: true }); } }; requestStore.stagedRendering = stageController; requestStore.asyncApiPromises = createAsyncApiPromises(stageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const rscPayload = await getPayload(requestStore); return await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Static); return _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ctx.componentMod, rscPayload, clientModules, { ...options, environmentName }); }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); } /** * Fork of `generateDynamicFlightRenderResult` that renders using `renderWithRestartOnCacheMissInDev` * to ensure correct separation of environments Prerender/Server (for use in Cache Components) */ async function generateDynamicFlightRenderResultWithStagesInDev(req, ctx, initialRequestStore, createRequestStore, fallbackParams) { const { htmlRequestId, renderOpts, requestId, workStore, componentMod: { createElement, routeModule: { userland: { loaderTree } } }, url } = ctx; const { onInstrumentationRequestError, setReactDebugChannel, setCacheStatus, isBuildTimePrerendering = false } = renderOpts; function onFlightDataRenderError(err, silenceLog) { return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'react-server-components-payload'), silenceLog); } const onError = (0, _createerrorhandler.createReactServerErrorHandler)(process.env.NODE_ENV === 'development', isBuildTimePrerendering, workStore.reactServerErrorsByDigest, onFlightDataRenderError); // We validate RSC requests for HMR refreshes and client navigations when // instant configs exist, since we render all the layouts necessary to perform // the validation in those cases. const shouldValidate = !isBypassingCachesInDev(initialRequestStore) && (initialRequestStore.isHmrRefresh === true || await (0, _instantconfig.anySegmentNeedsInstantValidationInDev)(loaderTree)); const getPayload = async (requestStore)=>{ const payload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, generateDynamicRSCPayload, ctx, undefined); if (isBypassingCachesInDev(requestStore)) { // Mark the RSC payload to indicate that caches were bypassed in dev. // This lets the client know not to cache anything based on this render. payload._bypassCachesInDev = createElement(WarnForBypassCachesInDev, { route: workStore.route }); } else if (shouldValidate) { // If this payload will be used for validation, it needs to contain the // canonical URL. Without it we'd get an error. payload.c = prepareInitialCanonicalUrl(url); } return payload; }; let debugChannel; let stream; if (// We only do this flow if we can safely recreate the store from scratch // (which is not the case for renders after an action) createRequestStore && // We only do this flow if we're not bypassing caches in dev using // "disable cache" in devtools or a hard refresh (cache-control: "no-store") !isBypassingCachesInDev(initialRequestStore)) { // Before we kick off the render, we set the cache status back to it's initial state // in case a previous render bypassed the cache. if (setCacheStatus) { setCacheStatus('ready', htmlRequestId); } const { stream: serverStream, accumulatedChunksPromise, syncInterruptReason, startTime, staticStageEndTime, runtimeStageEndTime, debugChannel: returnedDebugChannel, requestStore: finalRequestStore } = await renderWithRestartOnCacheMissInDev(ctx, initialRequestStore, createRequestStore, getPayload, onError); if (shouldValidate) { let validationDebugChannelClient = undefined; if (returnedDebugChannel) { const [t1, t2] = returnedDebugChannel.clientSide.readable.tee(); returnedDebugChannel.clientSide.readable = t1; validationDebugChannelClient = nodeStreamFromReadableStream(t2); } _consoleasyncstorageexternal.consoleAsyncStorage.run({ dim: true }, spawnStaticShellValidationInDev, accumulatedChunksPromise, syncInterruptReason, startTime, staticStageEndTime, runtimeStageEndTime, ctx, finalRequestStore, fallbackParams, validationDebugChannelClient); } else { logValidationSkipped(ctx); } debugChannel = returnedDebugChannel; stream = serverStream; } else { // We're either bypassing caches or we can't restart the render. // Do a dynamic render, but with (basic) environment labels. // Set cache status to bypass when specifically bypassing caches in dev if (setCacheStatus) { setCacheStatus('bypass', htmlRequestId); } debugChannel = setReactDebugChannel && (0, _debugchannelserver.createDebugChannel)(); stream = await stagedRenderToReadableStreamWithoutCachesInDev(ctx, initialRequestStore, getPayload, { onError: onError, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide }); } if (debugChannel && setReactDebugChannel) { setReactDebugChannel(debugChannel.clientSide, htmlRequestId, requestId); } return new _flightrenderresult.FlightRenderResult(stream, { fetchMetrics: workStore.fetchMetrics }); } async function generateRuntimePrefetchResult(req, ctx, requestStore) { const { workStore, renderOpts } = ctx; const { isBuildTimePrerendering = false, onInstrumentationRequestError } = renderOpts; function onFlightDataRenderError(err, silenceLog) { return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, // TODO(runtime-ppr): should we use a different value? createErrorContext(ctx, 'react-server-components-payload'), silenceLog); } const onError = (0, _createerrorhandler.createReactServerErrorHandler)(false, isBuildTimePrerendering, workStore.reactServerErrorsByDigest, onFlightDataRenderError); const metadata = {}; const staleTimeIterable = new _staletime.StaleTimeIterable(); const { componentMod: { routeModule: { userland: { loaderTree } } }, getDynamicParamFromSegment } = ctx; const rootParams = (0, _createcomponenttree.getRootParams)(loaderTree, getDynamicParamFromSegment); // We need to share caches between the prospective prerender and the final prerender, // but we're not going to persist this anywhere. const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); // We're not resuming an existing render. const renderResumeDataCache = null; await prospectiveRuntimeServerPrerender(ctx, generateDynamicRSCPayload.bind(null, ctx), prerenderResumeDataCache, renderResumeDataCache, rootParams, requestStore.headers, requestStore.cookies, requestStore.draftMode); const response = await finalRuntimeServerPrerender(ctx, generateDynamicRSCPayload.bind(null, ctx, { staleTimeIterable }), prerenderResumeDataCache, renderResumeDataCache, rootParams, requestStore.headers, requestStore.cookies, requestStore.draftMode, onError, staleTimeIterable); applyMetadataFromPrerenderResult(response, metadata, workStore); metadata.fetchMetrics = ctx.workStore.fetchMetrics; return new _flightrenderresult.FlightRenderResult(response.result.prelude, metadata); } async function prospectiveRuntimeServerPrerender(ctx, getPayload, prerenderResumeDataCache, renderResumeDataCache, rootParams, headers, cookies, draftMode) { const { implicitTags, renderOpts, workStore } = ctx; const { ComponentMod } = renderOpts; // Prerender controller represents the lifetime of the prerender. // It will be aborted when a Task is complete or a synchronously aborting // API is called. Notably during cache-filling renders this does not actually // terminate the render itself which will continue until all caches are filled const initialServerPrerenderController = new AbortController(); // This controller represents the lifetime of the React render call. Notably // during the cache-filling render it is different from the prerender controller // because we don't want to end the react render until all caches are filled. const initialServerRenderController = new AbortController(); // The cacheSignal helps us track whether caches are still filling or we are ready // to cut the render off. const cacheSignal = new _cachesignal.CacheSignal(); const initialServerPrerenderStore = { type: 'prerender-runtime', phase: 'render', rootParams, implicitTags, renderSignal: initialServerRenderController.signal, controller: initialServerPrerenderController, // During the initial prerender we need to track all cache reads to ensure // we render long enough to fill every cache it is possible to visit during // the final prerender. cacheSignal, // We only need to track dynamic accesses during the final prerender. dynamicTracking: null, // Runtime prefetches are never cached server-side, only client-side, // so we set `expire` and `revalidate` to their minimum values just in case. revalidate: 1, expire: 0, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], renderResumeDataCache, prerenderResumeDataCache, hmrRefreshHash: undefined, // We don't track vary params during initial prerender, only the final one varyParamsAccumulator: null, // No stage sequencing needed for prospective renders. stagedRendering: null, // These are not present in regular prerenders, but allowed in a runtime prerender. headers, cookies, draftMode }; const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); // We're not going to use the result of this render because the only time it could be used // is if it completes in a microtask and that's likely very rare for any non-trivial app const initialServerPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialServerPrerenderStore, getPayload); const prerenderOptions = { filterStackFrame, onError: (err)=>{ const digest = (0, _createerrorhandler.getDigestForWellKnownError)(err); if (digest) { return digest; } if (initialServerPrerenderController.signal.aborted) { // The render aborted before this error was handled which indicates // the error is caused by unfinished components within the render return; } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } }, // We don't want to stop rendering until the cacheSignal is complete so we pass // a different signal to this render call than is used by dynamic APIs to signify // transitioning out of the prerender environment signal: initialServerRenderController.signal }; const pendingInitialServerResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialServerPrerenderStore, (0, _streamops.getServerPrerender)(ComponentMod), initialServerPayload, clientModules, prerenderOptions); // Wait for all caches to be finished filling and for async imports to resolve (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); await cacheSignal.cacheReady(); initialServerRenderController.abort(); initialServerPrerenderController.abort(); // We don't need to continue the prerender process if we already // detected invalid dynamic usage in the initial prerender phase. if (workStore.invalidDynamicUsageError) { throw workStore.invalidDynamicUsageError; } try { return await (0, _apprenderprerenderutils.createReactServerPrerenderResult)(pendingInitialServerResult); } catch (err) { if (initialServerRenderController.signal.aborted || initialServerPrerenderController.signal.aborted) { // These are expected errors that might error the prerender. we ignore them. } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { // We don't normally log these errors because we are going to retry anyway but // it can be useful for debugging Next.js itself to get visibility here when needed (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } return null; } } /** * Prepends a single ASCII byte to the stream indicating whether the response * is partial (contains dynamic holes): '~' (0x7e) for partial, '#' (0x23) * for complete. */ function prependIsPartialByte(stream, isPartial) { const byte = new Uint8Array([ isPartial ? 0x7e : 0x23 ]); return stream.pipeThrough(new TransformStream({ start (controller) { controller.enqueue(byte); } })); } async function finalRuntimeServerPrerender(ctx, getPayload, prerenderResumeDataCache, renderResumeDataCache, rootParams, headers, cookies, draftMode, onError, staleTimeIterable) { const { implicitTags, renderOpts } = ctx; const { ComponentMod, experimental, isDebugDynamicAccesses } = renderOpts; const selectStaleTime = (0, _staletime.createSelectStaleTime)(experimental); let serverIsDynamic = false; const finalServerController = new AbortController(); const serverDynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(isDebugDynamicAccesses); const finalStageController = new _stagedrendering.StagedRenderingController(finalServerController.signal, null, true // track sync IO ); const varyParamsAccumulator = (0, _varyparams.createResponseVaryParamsAccumulator)(); const finalServerPrerenderStore = { type: 'prerender-runtime', phase: 'render', rootParams, implicitTags, renderSignal: finalServerController.signal, controller: finalServerController, // All caches we could read must already be filled so no tracking is necessary cacheSignal: null, dynamicTracking: serverDynamicTracking, // Runtime prefetches are never cached server-side, only client-side, // so we set `expire` and `revalidate` to their minimum values just in case. revalidate: 1, expire: 0, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, varyParamsAccumulator, // Used to separate the stages in the 5-task pipeline. stagedRendering: finalStageController, // These are not present in regular prerenders, but allowed in a runtime prerender. headers, cookies, draftMode }; (0, _staletime.trackStaleTime)(finalServerPrerenderStore, staleTimeIterable, selectStaleTime); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const finalRSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalServerPrerenderStore, getPayload); let prerenderIsPending = true; const result = await (0, _apprenderrenderutils.runInSequentialTasks)(async ()=>{ // EarlyStatic stage: render begins. // Runtime-prefetchable segments render immediately. // Non-prefetchable segments are gated until the Static stage. finalStageController.advanceStage(_stagedrendering.RenderStage.EarlyStatic); const prerenderResult = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalServerPrerenderStore, (0, _streamops.getServerPrerender)(ComponentMod), finalRSCPayload, clientModules, { filterStackFrame, onError, signal: finalServerController.signal }); prerenderIsPending = false; return prerenderResult; }, ()=>{ // Advance to Static stage: resolve promise holding back // non-prefetchable segments so they can begin rendering. finalStageController.advanceStage(_stagedrendering.RenderStage.Static); }, ()=>{ // Advance to EarlyRuntime stage: resolve cookies/headers for // runtime-prefetchable segments. Sync IO is checked here. finalStageController.advanceStage(_stagedrendering.RenderStage.EarlyRuntime); }, ()=>{ // Advance to Runtime stage: resolve cookies/headers for // non-prefetchable segments. Sync IO is allowed here. finalStageController.advanceStage(_stagedrendering.RenderStage.Runtime); }, ()=>{ Promise.all([ (0, _staletime.finishStaleTimeTracking)(staleTimeIterable), (0, _varyparams.finishAccumulatingVaryParams)(varyParamsAccumulator) ]).then(()=>{ // Abort. This runs as a microtask after Flight has flushed the // staleTime and varyParams closing chunks, but before the next // macrotask resolves the overall result. if (finalServerController.signal.aborted) { // If the server controller is already aborted we must have called // something that required aborting the prerender synchronously such // as with new Date() serverIsDynamic = true; return; } if (prerenderIsPending) { // If prerenderIsPending then we have blocked for longer than a Task // and we assume there is something unfinished. serverIsDynamic = true; } finalServerController.abort(); }); }); result.prelude = prependIsPartialByte(result.prelude, serverIsDynamic); return { result, // TODO(runtime-ppr): do we need to produce a digest map here? // digestErrorsMap: ..., dynamicAccess: serverDynamicTracking, isPartial: serverIsDynamic, collectedRevalidate: finalServerPrerenderStore.revalidate, collectedExpire: finalServerPrerenderStore.expire, collectedStale: staleTimeIterable.currentValue, collectedTags: finalServerPrerenderStore.tags }; } /** * Crawlers will inadvertently think the canonicalUrl in the RSC payload should be crawled * when our intention is to just seed the router state with the current URL. * This function splits up the pathname so that we can later join it on * when we're ready to consume the path. */ function prepareInitialCanonicalUrl(url) { return (url.pathname + url.search).split('/'); } function getRenderedSearch(query) { // Inlined implementation of querystring.encode, which is not available in // the Edge runtime. const pairs = []; for(const key in query){ const value = query[key]; if (value == null) continue; if (Array.isArray(value)) { for (const v of value){ pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(v))}`); } } else { pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`); } } // The result should match the format of a web URL's `search` property, since // this is the format that's stored in the App Router state. // TODO: We're a bit inconsistent about this. The x-nextjs-rewritten-query // header omits the leading question mark. Should refactor to always do // that instead. if (pairs.length === 0) { // If the search string is empty, return an empty string. return ''; } // Prepend '?' to the search params string. return '?' + pairs.join('&'); } // This is the data necessary to render when no SSR errors are encountered async function getRSCPayload(tree, ctx, options) { var _ctx_renderOpts_prefetchHints; const { is404, staleTimeIterable, staticStageByteLengthPromise, runtimePrefetchStream } = options; const injectedCSS = new Set(); const injectedJS = new Set(); const injectedFontPreloadTags = new Set(); let missingSlots; // We only track missing parallel slots in development if (process.env.__NEXT_DEV_SERVER) { missingSlots = new Set(); } const { getDynamicParamFromSegment, query, appUsingSizeAdjustment, componentMod: { createMetadataComponents, createElement, Fragment }, url, workStore } = ctx; const hints = ((_ctx_renderOpts_prefetchHints = ctx.renderOpts.prefetchHints) == null ? void 0 : _ctx_renderOpts_prefetchHints[ctx.pagePath]) ?? null; const initialTree = await (0, _createflightrouterstatefromloadertree.createFlightRouterStateFromLoaderTree)(tree, hints, getDynamicParamFromSegment, query); const serveStreamingMetadata = !!ctx.renderOpts.serveStreamingMetadata; const hasGlobalNotFound = !!tree[2]['global-not-found']; const metadataIsRuntimePrefetchable = await (0, _instantconfig.anySegmentHasRuntimePrefetchEnabled)(tree); const { Viewport, Metadata, MetadataOutlet } = createMetadataComponents({ tree, // When it's using global-not-found, metadata errorType is undefined, which will retrieve the // metadata from the page. // When it's using not-found, metadata errorType is 'not-found', which will retrieve the // metadata from the not-found.js boundary. // TODO: remove this condition and keep it undefined when global-not-found is stabilized. errorType: is404 && !hasGlobalNotFound ? 'not-found' : undefined, parsedQuery: query, pathname: url.pathname, metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts), interpolatedParams: ctx.interpolatedParams, serveStreamingMetadata, isRuntimePrefetchable: metadataIsRuntimePrefetchable }); const preloadCallbacks = []; const seedData = await (0, _createcomponenttree.createComponentTree)({ ctx, loaderTree: tree, parentParams: {}, parentOptionalCatchAllParamName: null, parentRuntimePrefetchable: false, injectedCSS, injectedJS, injectedFontPreloadTags, rootLayoutIncluded: false, missingSlots, preloadCallbacks, authInterrupts: ctx.renderOpts.experimental.authInterrupts, MetadataOutlet }); // When the `vary` response header is present with `Next-URL`, that means there's a chance // it could respond differently if there's an interception route. We provide this information // to `AppRouter` so that it can properly seed the prefetch cache with a prefix, if needed. // In dev, the Vary header may not reliably reflect whether a route can // be intercepted, because interception routes are compiled on demand. // Default to true so the client doesn't cache a stale Fallback entry. const varyHeader = ctx.res.getHeader('vary'); const couldBeIntercepted = !!process.env.__NEXT_DEV_SERVER || typeof varyHeader === 'string' && varyHeader.includes(_approuterheaders.NEXT_URL); const initialHead = createElement(Fragment, { key: flightDataPathHeadKey }, createElement(NonIndex, { createElement, pagePath: ctx.pagePath, statusCode: ctx.res.statusCode, isPossibleServerAction: ctx.isPossibleServerAction }), createElement(Viewport, null), createElement(Metadata, null), appUsingSizeAdjustment ? createElement('meta', { name: 'next-size-adjust', content: '' }) : null); const { GlobalError, styles: globalErrorStyles } = await getGlobalErrorStyles(tree, ctx); // Assume the head we're rendering contains only partial data if PPR is // enabled and this is a statically generated response. This is used by the // client Segment Cache after a prefetch to determine if it can skip the // second request to fill in the dynamic data. // // See similar comment in create-component-tree.tsx for more context. const isPossiblyPartialHead = workStore.isStaticGeneration && ctx.renderOpts.experimental.isRoutePPREnabled === true; return maybeAppendBuildIdToRSCPayload(ctx, { // See the comment above the `Preloads` component (below) for why this is part of the payload P: createElement(Preloads, { preloadCallbacks: preloadCallbacks }), c: prepareInitialCanonicalUrl(url), q: getRenderedSearch(query), i: !!couldBeIntercepted, f: [ [ initialTree, seedData, initialHead, isPossiblyPartialHead ] ], m: missingSlots, G: [ GlobalError, globalErrorStyles ], // Tells the client whether this route supports per-segment prefetching. // With Cache Components, all routes support it. Without it, only fully // static pages do, because their per-segment prefetch responses are // generated during static generation (build or ISR). S: workStore.isStaticGeneration || ctx.renderOpts.cacheComponents, h: (0, _varyparams.getMetadataVaryParamsThenable)(), s: staleTimeIterable, l: staticStageByteLengthPromise, p: runtimePrefetchStream, // Include the per-page dynamic stale time from unstable_dynamicStaleTime, but // only for dynamic renders. The client treats its presence as // authoritative. // TODO: Move this to the prefetch hints file so we don't have to walk // the tree on every render. d: !workStore.isStaticGeneration ? await getDynamicStaleTime(tree) ?? undefined : undefined }); } /** * Preload calls (such as `ReactDOM.preloadStyle` and `ReactDOM.preloadFont`) need to be called during rendering * in order to create the appropriate preload tags in the DOM, otherwise they're a no-op. Since we invoke * renderToReadableStream with a function that returns component props rather than a component itself, we use * this component to "render " the preload calls. */ function Preloads({ preloadCallbacks }) { preloadCallbacks.forEach((preloadFn)=>preloadFn()); return null; } // This is the data necessary to render when an error state is triggered async function getErrorRSCPayload(tree, ctx, ssrError, errorType) { var _ctx_renderOpts_prefetchHints; const { getDynamicParamFromSegment, query, componentMod: { createMetadataComponents, createElement, Fragment }, url, workStore } = ctx; const serveStreamingMetadata = !!ctx.renderOpts.serveStreamingMetadata; const metadataIsRuntimePrefetchable = await (0, _instantconfig.anySegmentHasRuntimePrefetchEnabled)(tree); const { Viewport, Metadata } = createMetadataComponents({ tree, parsedQuery: query, pathname: url.pathname, metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts), errorType, interpolatedParams: ctx.interpolatedParams, serveStreamingMetadata: serveStreamingMetadata, isRuntimePrefetchable: metadataIsRuntimePrefetchable }); const initialHead = createElement(Fragment, { key: flightDataPathHeadKey }, createElement(NonIndex, { createElement, pagePath: ctx.pagePath, statusCode: ctx.res.statusCode, isPossibleServerAction: ctx.isPossibleServerAction }), createElement(Viewport, null), process.env.__NEXT_DEV_SERVER && createElement('meta', { name: 'next-error', content: 'not-found' }), createElement(Metadata, null)); const errorHints = ((_ctx_renderOpts_prefetchHints = ctx.renderOpts.prefetchHints) == null ? void 0 : _ctx_renderOpts_prefetchHints[ctx.pagePath]) ?? null; const initialTree = await (0, _createflightrouterstatefromloadertree.createFlightRouterStateFromLoaderTree)(tree, errorHints, getDynamicParamFromSegment, query); let err = undefined; if (ssrError) { err = (0, _iserror.default)(ssrError) ? ssrError : Object.defineProperty(new Error(ssrError + ''), "__NEXT_ERROR_CODE", { value: "E394", enumerable: false, configurable: true }); } // For metadata notFound error there's no global not found boundary on top // so we create a not found page with AppRouter const seedData = [ createElement('html', { id: '__next_error__' }, createElement('head', null), createElement('body', null, process.env.__NEXT_DEV_SERVER && err ? createElement('template', { 'data-next-error-message': err.message, 'data-next-error-digest': 'digest' in err ? err.digest : '', 'data-next-error-stack': err.stack }) : null)), {}, null, false, null ]; const { GlobalError, styles: globalErrorStyles } = await getGlobalErrorStyles(tree, ctx); const isPossiblyPartialHead = workStore.isStaticGeneration && ctx.renderOpts.experimental.isRoutePPREnabled === true; return maybeAppendBuildIdToRSCPayload(ctx, { c: prepareInitialCanonicalUrl(url), q: getRenderedSearch(query), m: undefined, i: false, f: [ [ initialTree, seedData, initialHead, isPossiblyPartialHead ] ], G: [ GlobalError, globalErrorStyles ], // Tells the client whether this route supports per-segment prefetching. // With Cache Components, all routes support it. Without it, only fully // static pages do, because their per-segment prefetch responses are // generated during static generation (build or ISR). S: workStore.isStaticGeneration || ctx.renderOpts.cacheComponents, h: (0, _varyparams.getMetadataVaryParamsThenable)() }); } // This component must run in an SSR context. It will render the RSC root component function App({ reactServerStream, reactDebugStream, debugEndTime, preinitScripts, ServerInsertedHTMLProvider, nonce, images }) { preinitScripts(); const response = _react.use((0, _useflightresponse.getFlightStream)(reactServerStream, reactDebugStream, debugEndTime, nonce)); const initialState = (0, _createinitialrouterstate.createInitialRouterState)({ // This is not used during hydration, so we don't have to pass a // real timestamp. navigatedAt: -1, initialRSCPayload: response, // location is not initialized in the SSR render // it's set to window.location during hydration location: null }); const actionQueue = (0, _approuterinstance.createMutableActionQueue)(initialState, null); const { HeadManagerContext } = require('../../shared/lib/head-manager-context.shared-runtime'); return /*#__PURE__*/ (0, _jsxruntime.jsx)(HeadManagerContext.Provider, { value: { appDir: true, nonce }, children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_imageconfigcontextsharedruntime.ImageConfigContext.Provider, { value: images ?? _imageconfig.imageConfigDefault, children: /*#__PURE__*/ (0, _jsxruntime.jsx)(ServerInsertedHTMLProvider, { children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_approuter.default, { actionQueue: actionQueue, globalErrorState: response.G }) }) }) }); /* eslint-enable @next/internal/no-ambiguous-jsx -- React Client */ } // @TODO our error stream should be probably just use the same root component. But it was previously // different I don't want to figure out if that is meaningful at this time so just keeping the behavior // consistent for now. function ErrorApp({ reactServerStream, preinitScripts, ServerInsertedHTMLProvider, nonce, images }) { /* eslint-disable @next/internal/no-ambiguous-jsx -- React Client */ preinitScripts(); const response = _react.use((0, _useflightresponse.getFlightStream)(reactServerStream, undefined, undefined, nonce)); const initialState = (0, _createinitialrouterstate.createInitialRouterState)({ // This is not used during hydration, so we don't have to pass a // real timestamp. navigatedAt: -1, initialRSCPayload: response, // location is not initialized in the SSR render // it's set to window.location during hydration location: null }); const actionQueue = (0, _approuterinstance.createMutableActionQueue)(initialState, null); return /*#__PURE__*/ (0, _jsxruntime.jsx)(_imageconfigcontextsharedruntime.ImageConfigContext.Provider, { value: images ?? _imageconfig.imageConfigDefault, children: /*#__PURE__*/ (0, _jsxruntime.jsx)(ServerInsertedHTMLProvider, { children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_approuter.default, { actionQueue: actionQueue, globalErrorState: response.G }) }) }); /* eslint-enable @next/internal/no-ambiguous-jsx -- React Client */ } async function renderToHTMLOrFlightImpl(req, res, url, pagePath, query, renderOpts, workStore, parsedRequestHeaders, postponedState, serverComponentsHmrCache, sharedContext, interpolatedParams, fallbackRouteParams) { const isNotFoundPath = pagePath === '/404'; if (isNotFoundPath) { res.statusCode = 404; } // A unique request timestamp used by development to ensure that it's // consistent and won't change during this request. This is important to // avoid that resources can be deduped by React Float if the same resource is // rendered or preloaded multiple times: ``. const requestTimestamp = Date.now(); const { ComponentMod, nextFontManifest, serverActions, assetPrefix = '', enableTainting, cacheComponents, setIsrStatus } = renderOpts; const { cachedNavigations } = renderOpts.experimental; // We need to expose the bundled `require` API globally for // react-server-dom-webpack. This is a hack until we find a better way. if (ComponentMod.__next_app__) { const instrumented = (0, _clientcomponentrendererlogger.wrapClientComponentLoader)(ComponentMod); // When we are prerendering if there is a cacheSignal for tracking // cache reads we track calls to `loadChunk` and `require`. This allows us // to treat chunk/module loading with similar semantics as cache reads to avoid // module loading from causing a prerender to abort too early. const shouldTrackModuleLoading = ()=>{ if (!cacheComponents) { return false; } if (process.env.__NEXT_DEV_SERVER) { return true; } const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore(); if (!workUnitStore) { return false; } switch(workUnitStore.type){ case 'prerender': case 'prerender-client': case 'validation-client': case 'prerender-runtime': case 'cache': case 'private-cache': return true; case 'prerender-ppr': case 'prerender-legacy': case 'request': case 'unstable-cache': case 'generate-static-params': return false; default: workUnitStore; } }; const __next_require__ = (...args)=>{ const exportsOrPromise = instrumented.require(...args); if (shouldTrackModuleLoading()) { // requiring an async module returns a promise. (0, _trackmoduleloadingexternal.trackPendingImport)(exportsOrPromise); } return exportsOrPromise; }; // @ts-expect-error globalThis.__next_require__ = __next_require__; const __next_chunk_load__ = (...args)=>{ const loadingChunk = instrumented.loadChunk(...args); if (shouldTrackModuleLoading()) { (0, _trackmoduleloadingexternal.trackPendingChunkLoad)(loadingChunk); } return loadingChunk; }; // @ts-expect-error globalThis.__next_chunk_load__ = __next_chunk_load__; } if (process.env.__NEXT_DEV_SERVER && setIsrStatus && !cacheComponents) { // Reset the ISR status at start of request. const { pathname } = new URL(req.url || '/', 'http://n'); setIsrStatus(pathname, // Only pages using the Node runtime can use ISR, Edge is always dynamic. process.env.NEXT_RUNTIME === 'edge' ? false : undefined); } if (// The type check here ensures that `req` is correctly typed, and the // environment variable check provides dead code elimination. process.env.NEXT_RUNTIME !== 'edge' && (0, _helpers.isNodeNextRequest)(req)) { res.onClose(()=>{ // We stop tracking fetch metrics when the response closes, since we // report them at that time. workStore.shouldTrackFetchMetrics = false; }); req.originalRequest.on('end', ()=>{ if ('performance' in globalThis) { const metrics = (0, _clientcomponentrendererlogger.getClientComponentLoaderMetrics)({ reset: true }); if (metrics) { (0, _tracer.getTracer)().startSpan(_constants.NextNodeServerSpan.clientComponentLoading, { startTime: metrics.clientComponentLoadStart, attributes: { 'next.clientComponentLoadCount': metrics.clientComponentLoadCount, 'next.span_type': _constants.NextNodeServerSpan.clientComponentLoading } }).end(metrics.clientComponentLoadStart + metrics.clientComponentLoadTimes); } } }); } const metadata = { statusCode: isNotFoundPath ? 404 : undefined }; const appUsingSizeAdjustment = !!(nextFontManifest == null ? void 0 : nextFontManifest.appUsingSizeAdjust); ComponentMod.patchFetch(); // Pull out the hooks/references from the component. const { routeModule: { userland: { loaderTree } }, taintObjectReference } = ComponentMod; if (enableTainting) { taintObjectReference('Do not pass process.env to Client Components since it will leak sensitive data', process.env); } workStore.fetchMetrics = []; metadata.fetchMetrics = workStore.fetchMetrics; // don't modify original query object query = { ...query }; (0, _internalutils.stripInternalQueries)(query); const { isStaticGeneration } = workStore; let requestId; let htmlRequestId; const { flightRouterState, isPrefetchRequest, isRuntimePrefetchRequest, isRSCRequest, isHmrRefresh, nonce } = parsedRequestHeaders; if (parsedRequestHeaders.requestId) { // If the client has provided a request ID (in development mode), we use it. requestId = parsedRequestHeaders.requestId; } else { // Otherwise we generate a new request ID. if (isStaticGeneration) { requestId = Buffer.from(await crypto.subtle.digest('SHA-1', Buffer.from(req.url))).toString('hex'); } else if (process.env.NEXT_RUNTIME === 'edge') { requestId = crypto.randomUUID(); } else { requestId = require('next/dist/compiled/nanoid').nanoid(); } } // If the client has provided an HTML request ID, we use it to associate the // request with the HTML document from which it originated, which is used to // send debug information to the associated WebSocket client. Otherwise, this // is the request for the HTML document, so we use the request ID also as the // HTML request ID. htmlRequestId = parsedRequestHeaders.htmlRequestId || requestId; const getDynamicParamFromSegment = makeGetDynamicParamFromSegment(interpolatedParams, fallbackRouteParams, renderOpts.experimental.optimisticRouting); const isPossibleActionRequest = (0, _serveractionrequestmeta.getIsPossibleServerAction)(req); // For implicit tags, we use the resolved pathname which has dynamic params // interpolated, is decoded, and has trailing slash removed. const resolvedPathname = (0, _requestmeta.getRequestMeta)(req, 'resolvedPathname'); if (!resolvedPathname) { throw Object.defineProperty(new _invarianterror.InvariantError('resolvedPathname must be set in request metadata'), "__NEXT_ERROR_CODE", { value: "E981", enumerable: false, configurable: true }); } const implicitTags = await (0, _implicittags.getImplicitTags)(workStore.page, resolvedPathname, fallbackRouteParams); const ctx = { componentMod: ComponentMod, url, renderOpts, workStore, parsedRequestHeaders, getDynamicParamFromSegment, interpolatedParams, query, isPrefetch: isPrefetchRequest, isPossibleServerAction: isPossibleActionRequest, requestTimestamp, appUsingSizeAdjustment, flightRouterState, requestId, htmlRequestId, pagePath, assetPrefix, isNotFoundPath, nonce, res, sharedContext, implicitTags }; (0, _tracer.getTracer)().setRootSpanAttribute('next.route', pagePath); if (isStaticGeneration) { // We're either building or revalidating. In either case we need to // prerender our page rather than render it. const prerenderToStreamWithTracing = (0, _tracer.getTracer)().wrap(_constants.AppRenderSpan.getBodyResult, { spanName: `prerender route (app) ${pagePath}`, attributes: { 'next.route': pagePath } }, prerenderToStream); const response = await prerenderToStreamWithTracing(req, res, ctx, metadata, loaderTree, fallbackRouteParams); // If we're debugging partial prerendering, print all the dynamic API accesses // that occurred during the render. // @TODO move into renderToStream function if (response.dynamicAccess && (0, _dynamicrendering.accessedDynamicData)(response.dynamicAccess) && renderOpts.isDebugDynamicAccesses) { (0, _log.warn)('The following dynamic usage was detected:'); for (const access of (0, _dynamicrendering.formatDynamicAPIAccesses)(response.dynamicAccess)){ (0, _log.warn)(access); } } // If we encountered any unexpected errors during build we fail the // prerendering phase and the build. if (workStore.invalidDynamicUsageError) { (0, _dynamicrendering.logDisallowedDynamicError)(workStore, workStore.invalidDynamicUsageError); throw new _staticgenerationbailout.StaticGenBailoutError(); } if (response.digestErrorsMap.size) { const buildFailingError = response.digestErrorsMap.values().next().value; if (buildFailingError) throw buildFailingError; } // Pick first userland SSR error, which is also not a RSC error. if (response.ssrErrors.length) { const buildFailingError = response.ssrErrors.find((err)=>(0, _createerrorhandler.isUserLandError)(err)); if (buildFailingError) throw buildFailingError; } const options = { metadata, contentType: _constants1.HTML_CONTENT_TYPE_HEADER }; // If we have pending revalidates, wait until they are all resolved. const maybeRevalidatesPromise = (0, _revalidationutils.executeRevalidates)(workStore); if (maybeRevalidatesPromise !== false) { const revalidatesPromise = maybeRevalidatesPromise.finally(()=>{ if (process.env.NEXT_PRIVATE_DEBUG_CACHE) { console.log('pending revalidates promise finished for:', url.href); } }); if (renderOpts.waitUntil) { renderOpts.waitUntil(revalidatesPromise); } else { options.waitUntil = revalidatesPromise; } } applyMetadataFromPrerenderResult(response, metadata, workStore); if (response.renderResumeDataCache) { metadata.renderResumeDataCache = response.renderResumeDataCache; } const streamString = await (0, _streamops.streamToString)(response.stream); const result = new _renderresult.default(streamString, options); // Run build-time instant validation if the page has instant configs // TODO(instant-validation-build): This is not a great place to wire this in. if (workStore.cacheComponentsEnabled && workStore.isBuildTimePrerendering && renderOpts.runInstantValidation && await (0, _instantconfig.anySegmentNeedsInstantValidationInBuild)(loaderTree)) { // Throws StaticGenBailoutError if validation failed. await validateInstantConfigsInBuild(ctx, response.renderResumeDataCache ?? null); } return result; } else { // We're rendering dynamically const renderResumeDataCache = renderOpts.renderResumeDataCache ?? (postponedState == null ? void 0 : postponedState.renderResumeDataCache) ?? null; const rootParams = (0, _createcomponenttree.getRootParams)(loaderTree, ctx.getDynamicParamFromSegment); const fallbackParams = (0, _requestmeta.getRequestMeta)(req, 'fallbackParams') || null; const createRequestStore = _requeststore.createRequestStoreForRender.bind(null, req, res, url, rootParams, implicitTags, renderOpts.onUpdateCookies, renderOpts.previewProps, isHmrRefresh, serverComponentsHmrCache, renderResumeDataCache, fallbackParams); const requestStore = createRequestStore(); if (process.env.__NEXT_DEV_SERVER && setIsrStatus && !cacheComponents && // Only pages using the Node runtime can use ISR, so we only need to // update the status for those. // The type check here ensures that `req` is correctly typed, and the // environment variable check provides dead code elimination. process.env.NEXT_RUNTIME !== 'edge' && (0, _helpers.isNodeNextRequest)(req)) { req.originalRequest.on('end', ()=>{ const { pathname } = new URL(req.url || '/', 'http://n'); const isStatic = !requestStore.usedDynamic && !workStore.forceDynamic; setIsrStatus(pathname, isStatic); }); } if (isRSCRequest) { if (isRuntimePrefetchRequest) { return generateRuntimePrefetchResult(req, ctx, requestStore); } else { if (process.env.__NEXT_DEV_SERVER && process.env.NEXT_RUNTIME !== 'edge' && cacheComponents) { return generateDynamicFlightRenderResultWithStagesInDev(req, ctx, requestStore, createRequestStore, fallbackParams); } else if (cacheComponents && cachedNavigations) { return generateStagedDynamicFlightRenderResult(req, ctx, requestStore); } else { return generateDynamicFlightRenderResult(req, ctx, requestStore); } } } let didExecuteServerAction = false; let formState = null; if (isPossibleActionRequest) { // For action requests, we handle them differently with a special render result. const actionRequestResult = await (0, _actionhandler.handleAction)({ req, res, ComponentMod, generateFlight: generateDynamicFlightRenderResult, workStore, requestStore, serverActions, ctx, metadata }); if (actionRequestResult) { if (actionRequestResult.type === 'not-found') { const notFoundLoaderTree = createNotFoundLoaderTree(loaderTree); res.statusCode = 404; metadata.statusCode = 404; const stream = await renderToStream(requestStore, req, res, ctx, notFoundLoaderTree, formState, postponedState, metadata, undefined, fallbackParams); return new _renderresult.default(stream, { metadata, contentType: _constants1.HTML_CONTENT_TYPE_HEADER }); } else if (actionRequestResult.type === 'done') { if (actionRequestResult.result) { actionRequestResult.result.assignMetadata(metadata); return actionRequestResult.result; } else if (actionRequestResult.formState) { formState = actionRequestResult.formState; } } } didExecuteServerAction = true; } const options = { metadata, contentType: _constants1.HTML_CONTENT_TYPE_HEADER }; const stream = await renderToStream(// NOTE: in Cache Components (dev), if the render is restarted, it will use a different requestStore // than the one that we're passing in here. requestStore, req, res, ctx, loaderTree, formState, postponedState, metadata, // If we're rendering HTML after an action, we don't want restartable-render behavior // because the result should be dynamic, like it is in prod. // Also, the request store might have been mutated by the action (e.g. enabling draftMode) // and we currently we don't copy changes over when creating a new store, // so the restarted render wouldn't be correct. didExecuteServerAction ? undefined : createRequestStore, fallbackParams); // Invalid dynamic usages should only error the request in development. // In production, it's better to produce a result. // (the dynamic error will still be thrown inside the component tree, but it's catchable by error boundaries) if (workStore.invalidDynamicUsageError && process.env.__NEXT_DEV_SERVER) { throw workStore.invalidDynamicUsageError; } // If we have pending revalidates, wait until they are all resolved. const maybeRevalidatesPromise = (0, _revalidationutils.executeRevalidates)(workStore); if (maybeRevalidatesPromise !== false) { const revalidatesPromise = maybeRevalidatesPromise.finally(()=>{ if (process.env.NEXT_PRIVATE_DEBUG_CACHE) { console.log('pending revalidates promise finished for:', url.href); } }); if (renderOpts.waitUntil) { renderOpts.waitUntil(revalidatesPromise); } else { options.waitUntil = revalidatesPromise; } } // Create the new render result for the response. return new _renderresult.default(stream, options); } } const renderToHTMLOrFlight = (req, res, pagePath, query, fallbackRouteParams, renderOpts, serverComponentsHmrCache, sharedContext)=>{ var _renderOpts_previewProps; if (!req.url) { throw Object.defineProperty(new Error('Invalid URL'), "__NEXT_ERROR_CODE", { value: "E182", enumerable: false, configurable: true }); } const url = (0, _parserelativeurl.parseRelativeUrl)(req.url, undefined, false); // We read these values from the request object as, in certain cases, // base-server will strip them to opt into different rendering behavior. const parsedRequestHeaders = parseRequestHeaders(req.headers, { isRoutePPREnabled: renderOpts.experimental.isRoutePPREnabled === true, previewModeId: (_renderOpts_previewProps = renderOpts.previewProps) == null ? void 0 : _renderOpts_previewProps.previewModeId }); const { isPrefetchRequest, previouslyRevalidatedTags, nonce } = parsedRequestHeaders; let interpolatedParams; let postponedState = null; // If provided, the postpone state should be parsed so it can be provided to // React. if (typeof renderOpts.postponed === 'string') { if (fallbackRouteParams) { throw Object.defineProperty(new _invarianterror.InvariantError('postponed state should not be provided when fallback params are provided'), "__NEXT_ERROR_CODE", { value: "E592", enumerable: false, configurable: true }); } interpolatedParams = (0, _getdynamicparam.interpolateParallelRouteParams)(renderOpts.ComponentMod.routeModule.userland.loaderTree, renderOpts.params ?? {}, pagePath, fallbackRouteParams); postponedState = (0, _postponedstate.parsePostponedState)(renderOpts.postponed, interpolatedParams, renderOpts.experimental.maxPostponedStateSizeBytes); } else { interpolatedParams = (0, _getdynamicparam.interpolateParallelRouteParams)(renderOpts.ComponentMod.routeModule.userland.loaderTree, renderOpts.params ?? {}, pagePath, fallbackRouteParams); } if ((postponedState == null ? void 0 : postponedState.renderResumeDataCache) && renderOpts.renderResumeDataCache) { throw Object.defineProperty(new _invarianterror.InvariantError('postponed state and dev warmup immutable resume data cache should not be provided together'), "__NEXT_ERROR_CODE", { value: "E589", enumerable: false, configurable: true }); } const workStore = (0, _workstore.createWorkStore)({ page: renderOpts.routeModule.definition.page, renderOpts, // @TODO move to workUnitStore of type Request isPrefetchRequest, buildId: sharedContext.buildId, previouslyRevalidatedTags, nonce }); return _workasyncstorageexternal.workAsyncStorage.run(workStore, // The function to run renderToHTMLOrFlightImpl, // all of it's args req, res, url, pagePath, query, renderOpts, workStore, parsedRequestHeaders, postponedState, serverComponentsHmrCache, sharedContext, interpolatedParams, fallbackRouteParams); }; function applyMetadataFromPrerenderResult(response, metadata, workStore) { if (response.collectedTags) { metadata.fetchTags = response.collectedTags.join(','); } // Let the client router know how long to keep the cached entry around. const staleHeader = String(response.collectedStale); metadata.headers ??= {}; metadata.headers[_approuterheaders.NEXT_ROUTER_STALE_TIME_HEADER] = staleHeader; // If force static is specifically set to false, we should not revalidate // the page. if (workStore.forceStatic === false || response.collectedRevalidate === 0) { metadata.cacheControl = { revalidate: 0, expire: undefined }; } else { // Copy the cache control value onto the render result metadata. metadata.cacheControl = { revalidate: response.collectedRevalidate >= _constants1.INFINITE_CACHE ? false : response.collectedRevalidate, expire: response.collectedExpire >= _constants1.INFINITE_CACHE ? undefined : response.collectedExpire }; } // provide bailout info for debugging if (metadata.cacheControl.revalidate === 0) { metadata.staticBailoutInfo = { description: workStore.dynamicUsageDescription, stack: workStore.dynamicUsageStack }; } } async function renderToStream(requestStore, req, res, ctx, tree, formState, postponedState, metadata, createRequestStore, fallbackParams) { /* eslint-disable @next/internal/no-ambiguous-jsx -- React Client */ const { assetPrefix, htmlRequestId, nonce, pagePath, renderOpts, requestId, workStore } = ctx; const { basePath, buildManifest, ComponentMod: { createElement }, crossOrigin, experimental, isBuildTimePrerendering = false, onInstrumentationRequestError, page, reactMaxHeadersLength, setReactDebugChannel, shouldWaitOnAllReady, subresourceIntegrityManifest, supportsDynamicResponse, cacheComponents } = renderOpts; const { cachedNavigations } = renderOpts.experimental; const { ServerInsertedHTMLProvider, renderServerInsertedHTML } = (0, _serverinsertedhtml.createServerInsertedHTML)(); const getServerInsertedMetadata = (0, _createserverinsertedmetadata.createServerInsertedMetadata)(nonce); const tracingMetadata = (0, _utils1.getTracedMetadata)((0, _tracer.getTracer)().getTracePropagationData(), experimental.clientTraceMetadata); const polyfills = buildManifest.polyfillFiles.filter((polyfill)=>polyfill.endsWith('.js') && !polyfill.endsWith('.module.js')).map((polyfill)=>({ src: `${assetPrefix}/_next/${polyfill}${(0, _getassetquerystring.getAssetQueryString)(ctx, false)}`, integrity: subresourceIntegrityManifest == null ? void 0 : subresourceIntegrityManifest[polyfill], crossOrigin, noModule: true, nonce })); const [preinitScripts, bootstrapScript] = (0, _requiredscripts.getRequiredScripts)(buildManifest, // Why is assetPrefix optional on renderOpts? // @TODO make it default empty string on renderOpts and get rid of it from ctx assetPrefix, crossOrigin, subresourceIntegrityManifest, (0, _getassetquerystring.getAssetQueryString)(ctx, true), nonce, page); // In development mode, set the request ID as a global variable, before the // bootstrap script is executed, which depends on it during hydration. // For MPA navigations (page reload, direct URL entry), the request ID // header is not present, so we generate a random one. const bootstrapScriptContent = process.env.__NEXT_DEV_SERVER ? `self.__next_r=${JSON.stringify(requestId ?? crypto.randomUUID())}` : undefined; // Create the "render route (app)" span manually so we can keep it open during streaming. // This is necessary because errors inside Suspense boundaries are reported asynchronously // during stream consumption, after a typical wrapped function would have ended the span. // Note: We pass the full span name as the first argument since startSpan uses it directly. const renderSpan = (0, _tracer.getTracer)().startSpan(`render route (app) ${pagePath}`, { attributes: { 'next.span_name': `render route (app) ${pagePath}`, 'next.span_type': _constants.AppRenderSpan.getBodyResult, 'next.route': pagePath } }); // Helper to end the span with error status (used when throwing from catch blocks) const endSpanWithError = (err)=>{ if (!renderSpan.isRecording()) return; if (err instanceof Error) { renderSpan.recordException(err); renderSpan.setAttribute('error.type', err.name); } renderSpan.setStatus({ code: _tracer.SpanStatusCode.ERROR, message: err instanceof Error ? err.message : undefined }); renderSpan.end(); }; // Run the rest of the function within the span's context so child spans // (like "build component tree", "generateMetadata") are properly parented. return (0, _tracer.getTracer)().withSpan(renderSpan, async ()=>{ const { reactServerErrorsByDigest } = workStore; function onHTMLRenderRSCError(err, silenceLog) { return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'react-server-components'), silenceLog); } const serverComponentsErrorHandler = (0, _createerrorhandler.createReactServerErrorHandler)(process.env.NODE_ENV === 'development', isBuildTimePrerendering, reactServerErrorsByDigest, onHTMLRenderRSCError, renderSpan); function onHTMLRenderSSRError(err) { // We don't need to silence logs here. onHTMLRenderSSRError won't be called // at all if the error was logged before in the RSC error handler. const silenceLog = false; return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'server-rendering'), silenceLog); } const allCapturedErrors = []; const htmlRendererErrorHandler = (0, _createerrorhandler.createHTMLErrorHandler)(process.env.NODE_ENV === 'development', isBuildTimePrerendering, reactServerErrorsByDigest, allCapturedErrors, onHTMLRenderSSRError, renderSpan); let reactServerResult = null; let reactDebugStream; const setHeader = res.setHeader.bind(res); const appendHeader = res.appendHeader.bind(res); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); try { if (process.env.__NEXT_DEV_SERVER && // Edge routes never prerender so we don't have a Prerender environment for anything in edge runtime process.env.NEXT_RUNTIME !== 'edge' && // We only have a Prerender environment for projects opted into cacheComponents cacheComponents) { let debugChannel; // eslint-disable-next-line @typescript-eslint/no-shadow const getPayload = async (requestStore)=>{ const payload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404 }); if (isBypassingCachesInDev(requestStore)) { // Mark the RSC payload to indicate that caches were bypassed in dev. // This lets the client know not to cache anything based on this render. if (renderOpts.setCacheStatus) { // we know this is available when cacheComponents is enabled, but typeguard to be safe renderOpts.setCacheStatus('bypass', htmlRequestId); } payload._bypassCachesInDev = createElement(WarnForBypassCachesInDev, { route: workStore.route }); } return payload; }; if (// We only do this flow if we can safely recreate the store from scratch // (which is not the case for renders after an action) createRequestStore && // We only do this flow if we're not bypassing caches in dev using // "disable cache" in devtools or a hard refresh (cache-control: "no-store") !isBypassingCachesInDev(requestStore)) { const { stream: serverStream, accumulatedChunksPromise, syncInterruptReason, startTime, staticStageEndTime, runtimeStageEndTime, debugChannel: returnedDebugChannel, requestStore: finalRequestStore } = await renderWithRestartOnCacheMissInDev(ctx, requestStore, createRequestStore, getPayload, serverComponentsErrorHandler); let validationDebugChannelClient = undefined; if (returnedDebugChannel) { const [t1, t2] = returnedDebugChannel.clientSide.readable.tee(); returnedDebugChannel.clientSide.readable = t1; validationDebugChannelClient = nodeStreamFromReadableStream(t2); } _consoleasyncstorageexternal.consoleAsyncStorage.run({ dim: true }, spawnStaticShellValidationInDev, accumulatedChunksPromise, syncInterruptReason, startTime, staticStageEndTime, runtimeStageEndTime, ctx, finalRequestStore, fallbackParams, validationDebugChannelClient); reactServerResult = new _apprenderprerenderutils.ReactServerResult(serverStream); requestStore = finalRequestStore; debugChannel = returnedDebugChannel; } else { logValidationSkipped(ctx); // We're either bypassing caches or we can't restart the render. // Do a dynamic render, but with (basic) environment labels. debugChannel = setReactDebugChannel && (0, _debugchannelserver.createDebugChannel)(); const serverStream = await stagedRenderToReadableStreamWithoutCachesInDev(ctx, requestStore, getPayload, { onError: serverComponentsErrorHandler, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide }); reactServerResult = new _apprenderprerenderutils.ReactServerResult(serverStream); } if (debugChannel && setReactDebugChannel) { const [readableSsr, readableBrowser] = debugChannel.clientSide.readable.tee(); reactDebugStream = readableSsr; setReactDebugChannel({ readable: readableBrowser }, htmlRequestId, requestId); } } else if (cacheComponents && cachedNavigations) { // Production Cache Components + Cached Navigations: use staged // rendering so the RSC payload includes the static stage byte length // (`l` field), enabling the client to cache the static subset during // hydration. const { renderToReadableStream } = ctx.componentMod; const selectStaleTime = (0, _staletime.createSelectStaleTime)(experimental); const staleTimeIterable = new _staletime.StaleTimeIterable(); // TODO(cached-navs): this assumes that we checked during build that there's no sync IO. // but it can happen e.g. after a revalidation or conditionally for a param that wasn't prerendered. // we should change this to track sync IO, log an error and advance to dynamic. const shouldTrackSyncIO = false; const stageController = new _stagedrendering.StagedRenderingController(null, null, shouldTrackSyncIO); requestStore.stale = _constants1.INFINITE_CACHE; requestStore.stagedRendering = stageController; (0, _staletime.trackStaleTime)(requestStore, staleTimeIterable, selectStaleTime); let resolveStaticStageByteLength; const staticStageByteLengthPromise = new Promise((resolve)=>{ resolveStaticStageByteLength = resolve; }); // If the route has runtime prefetching enabled, spawn a runtime // prerender after the resume render fills caches. The result is // embedded in the initial RSC payload so the client can cache // runtime-prefetchable content during hydration. const hasRuntimePrefetch = await (0, _instantconfig.anySegmentHasRuntimePrefetchEnabled)(tree); let runtimePrefetchStream; if (hasRuntimePrefetch) { const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); requestStore.prerenderResumeDataCache = prerenderResumeDataCache; const cacheSignal = new _cachesignal.CacheSignal(); (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); requestStore.cacheSignal = cacheSignal; const runtimePrefetchTransform = new TransformStream(); runtimePrefetchStream = runtimePrefetchTransform.readable; void cacheSignal.cacheReady().then(()=>spawnRuntimePrefetchWithFilledCaches(runtimePrefetchTransform.writable, ctx, prerenderResumeDataCache, requestStore, serverComponentsErrorHandler)); } const RSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404, staleTimeIterable, staticStageByteLengthPromise, runtimePrefetchStream }); const flightStream = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Static); const stream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, renderToReadableStream, RSCPayload, clientModules, { onError: serverComponentsErrorHandler, filterStackFrame }); const [dynamicStream, staticStream] = stream.tee(); countStaticStageBytes(staticStream, stageController).then(resolveStaticStageByteLength); return dynamicStream; }, ()=>{ // This is a separate task that doesn't advance a stage. It forces // draining the microtask queue so that the stale time iterable is // closed before we advance to the dynamic stage. void (0, _staletime.finishStaleTimeTracking)(staleTimeIterable); }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); reactServerResult = new _apprenderprerenderutils.ReactServerResult(flightStream); } else { // This is a dynamic render. We don't do dynamic tracking because we're not prerendering const RSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404 }); const debugChannel = setReactDebugChannel && (0, _debugchannelserver.createDebugChannel)(); if (debugChannel) { const [readableSsr, readableBrowser] = debugChannel.clientSide.readable.tee(); reactDebugStream = readableSsr; setReactDebugChannel({ readable: readableBrowser }, htmlRequestId, requestId); } reactServerResult = new _apprenderprerenderutils.ReactServerResult(_workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ctx.componentMod, RSCPayload, clientModules, { filterStackFrame, onError: serverComponentsErrorHandler, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide })); } // React doesn't start rendering synchronously but we want the RSC render to have a chance to start // before we begin SSR rendering because we want to capture any available preload headers so we tick // one task before continuing await (0, _scheduler.waitAtLeastOneReactRenderTask)(); // If provided, the postpone state should be parsed as JSON so it can be // provided to React. if (typeof renderOpts.postponed === 'string') { if ((postponedState == null ? void 0 : postponedState.type) === _postponedstate.DynamicState.DATA) { // We have a complete HTML Document in the prerender but we need to // still include the new server component render because it was not included // in the static prelude. const inlinedDataStream = (0, _streamops.createInlinedDataStream)(reactServerResult.tee(), nonce, formState); // End the span since there's no async rendering in this path if (renderSpan.isRecording()) renderSpan.end(); return (0, _streamops.chainStreams)(inlinedDataStream, (0, _streamops.createDocumentClosingStream)()); } else if (postponedState) { // We assume we have dynamic HTML requiring a resume render to complete const { postponed, preludeState } = (0, _postponedstate.getPostponedFromState)(postponedState); const resumeAppElement = /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: reactServerResult.tee(), reactDebugStream: reactDebugStream, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }); const getServerInsertedHTML = (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: allCapturedErrors, basePath, tracingMetadata: tracingMetadata }); const { stream: htmlStream, allReady } = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.resumeToFizzStream, resumeAppElement, postponed, { onError: htmlRendererErrorHandler, nonce }); // End the render span only after React completed rendering (including anything inside Suspense boundaries) allReady.finally(()=>{ if (renderSpan.isRecording()) renderSpan.end(); }); return await (0, _streamops.continueDynamicHTMLResume)(htmlStream, { delayDataUntilFirstHtmlChunk: preludeState === _postponedstate.DynamicHTMLPreludeState.Empty, inlinedDataStream: (0, _streamops.createInlinedDataStream)(reactServerResult.consume(), nonce, formState), getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }); } } // This is a regular dynamic render const getServerInsertedHTML = (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: allCapturedErrors, basePath, tracingMetadata: tracingMetadata }); const generateStaticHTML = supportsDynamicResponse !== true || !!shouldWaitOnAllReady; const appElement = /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: reactServerResult.tee(), reactDebugStream: reactDebugStream, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }); const fizzOptions = { onError: htmlRendererErrorHandler, nonce, onHeaders: (headers)=>{ headers.forEach((value, key)=>{ appendHeader(key, value); }); }, maxHeadersLength: reactMaxHeadersLength, bootstrapScriptContent, bootstrapScripts: [ bootstrapScript ], formState }; const { stream: htmlStream, allReady } = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFizzStream, appElement, fizzOptions); // End the render span only after React completed rendering (including anything inside Suspense boundaries) allReady.finally(()=>{ if (renderSpan.isRecording()) renderSpan.end(); }); return await (0, _streamops.continueFizzStream)(htmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(reactServerResult.consume(), nonce, formState), isStaticGeneration: generateStaticHTML, allReady, deploymentId: ctx.sharedContext.deploymentId, getServerInsertedHTML, getServerInsertedMetadata, validateRootLayout: !!process.env.__NEXT_DEV_SERVER }); } catch (err) { if ((0, _staticgenerationbailout.isStaticGenBailoutError)(err) || typeof err === 'object' && err !== null && 'message' in err && typeof err.message === 'string' && err.message.includes('https://nextjs.org/docs/advanced-features/static-html-export')) { // Ensure that "next dev" prints the red error overlay endSpanWithError(err); throw err; } // If a bailout made it to this point, it means it wasn't wrapped inside // a suspense boundary. const shouldBailoutToCSR = (0, _bailouttocsr.isBailoutToCSRError)(err); if (shouldBailoutToCSR) { const stack = (0, _formatservererror.getStackWithoutErrorMessage)(err); (0, _log.error)(`${err.reason} should be wrapped in a suspense boundary at page "${pagePath}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n${stack}`); endSpanWithError(err); throw err; } let errorType; if ((0, _httpaccessfallback.isHTTPAccessFallbackError)(err)) { res.statusCode = (0, _httpaccessfallback.getAccessFallbackHTTPStatus)(err); metadata.statusCode = res.statusCode; errorType = (0, _httpaccessfallback.getAccessFallbackErrorTypeByStatus)(res.statusCode); } else if ((0, _redirecterror.isRedirectError)(err)) { errorType = 'redirect'; res.statusCode = (0, _redirect.getRedirectStatusCodeFromError)(err); metadata.statusCode = res.statusCode; const redirectUrl = (0, _addpathprefix.addPathPrefix)((0, _redirect.getURLFromRedirectError)(err), basePath); // If there were mutable cookies set, we need to set them on the // response. const headers = new Headers(); if ((0, _requestcookies.appendMutableCookies)(headers, requestStore.mutableCookies)) { setHeader('set-cookie', Array.from(headers.values())); } setHeader('location', redirectUrl); } else if (!shouldBailoutToCSR) { res.statusCode = 500; metadata.statusCode = res.statusCode; } const [errorPreinitScripts, errorBootstrapScript] = (0, _requiredscripts.getRequiredScripts)(buildManifest, assetPrefix, crossOrigin, subresourceIntegrityManifest, (0, _getassetquerystring.getAssetQueryString)(ctx, false), nonce, '/_not-found/page'); let errorRSCPayload; let errorServerStream; try { errorRSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, getErrorRSCPayload, tree, ctx, reactServerErrorsByDigest.has(err.digest) ? null : err, errorType); errorServerStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ctx.componentMod, errorRSCPayload, clientModules, { filterStackFrame, onError: serverComponentsErrorHandler }); if (reactServerResult === null) { // We errored when we did not have an RSC stream to read from. This is not just a render // error, we need to throw early endSpanWithError(err); throw err; } } catch (setupErr) { endSpanWithError(setupErr); throw setupErr; } try { const generateStaticHTML = supportsDynamicResponse !== true || !!shouldWaitOnAllReady; const { stream: errorHtmlStream, allReady: errorAllReady } = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFizzStream, /*#__PURE__*/ (0, _jsxruntime.jsx)(ErrorApp, { reactServerStream: errorServerStream, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, preinitScripts: errorPreinitScripts, nonce: nonce, images: ctx.renderOpts.images }), { nonce, bootstrapScriptContent, bootstrapScripts: [ errorBootstrapScript ], formState }); // End the render span only after React completed rendering (including anything inside Suspense boundaries) errorAllReady.finally(()=>{ if (renderSpan.isRecording()) renderSpan.end(); }); return await (0, _streamops.continueFizzStream)(errorHtmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(// This is intentionally using the readable datastream from the // main render rather than the flight data from the error page // render reactServerResult.consume(), nonce, formState), isStaticGeneration: generateStaticHTML, deploymentId: ctx.sharedContext.deploymentId, getServerInsertedHTML: (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: [], basePath, tracingMetadata: tracingMetadata }), getServerInsertedMetadata, validateRootLayout: !!process.env.__NEXT_DEV_SERVER }); } catch (finalErr) { if (process.env.__NEXT_DEV_SERVER && (0, _httpaccessfallback.isHTTPAccessFallbackError)(finalErr)) { const { bailOnRootNotFound } = require('../../client/components/dev-root-http-access-fallback-boundary'); bailOnRootNotFound(); } endSpanWithError(finalErr); throw finalErr; } } }); /* eslint-enable @next/internal/no-ambiguous-jsx */ } async function renderWithRestartOnCacheMissInDev(ctx, initialRequestStore, createRequestStore, getPayload, onError) { const { htmlRequestId, renderOpts } = ctx; const { ComponentMod, setCacheStatus, setReactDebugChannel } = renderOpts; let startTime = -Infinity; // If the render is restarted, we'll recreate a fresh request store let requestStore = initialRequestStore; const environmentName = ()=>{ const currentStage = requestStore.stagedRendering.currentStage; switch(currentStage){ case _stagedrendering.RenderStage.Before: case _stagedrendering.RenderStage.EarlyStatic: case _stagedrendering.RenderStage.Static: return 'Prerender'; case _stagedrendering.RenderStage.EarlyRuntime: return 'Prefetch'; case _stagedrendering.RenderStage.Runtime: return 'Prefetchable'; case _stagedrendering.RenderStage.Dynamic: case _stagedrendering.RenderStage.Abandoned: return 'Server'; default: currentStage; throw Object.defineProperty(new _invarianterror.InvariantError(`Invalid render stage: ${currentStage}`), "__NEXT_ERROR_CODE", { value: "E881", enumerable: false, configurable: true }); } }; //=============================================== // Initial render //=============================================== // Try to render the page and see if there's any cache misses. // If there are, wait for caches to finish and restart the render. // This render might end up being used as a prospective render (if there's cache misses), // so we need to set it up for filling caches. const cacheSignal = new _cachesignal.CacheSignal(); // If we encounter async modules that delay rendering, we'll also need to restart. // TODO(restart-on-cache-miss): technically, we only need to wait for pending *server* modules here, // but `trackPendingModules` doesn't distinguish between client and server. (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); const initialReactController = new AbortController(); const initialDataController = new AbortController() // Controls hanging promises we create ; const initialAbandonController = new AbortController() // Controls whether this render is abandoned ; const initialStageController = new _stagedrendering.StagedRenderingController(initialDataController.signal, initialAbandonController, true // track sync IO ); requestStore.prerenderResumeDataCache = prerenderResumeDataCache; // `getRenderResumeDataCache` will fall back to using `prerenderResumeDataCache` as `renderResumeDataCache`, // so not having a resume data cache won't break any expectations in case we don't need to restart. requestStore.renderResumeDataCache = null; requestStore.stagedRendering = initialStageController; requestStore.asyncApiPromises = createAsyncApiPromises(initialStageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); requestStore.cacheSignal = cacheSignal; let debugChannel = setReactDebugChannel && (0, _debugchannelserver.createDebugChannel)(); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); // Note: The stage controller starts out in the `Before` stage, // where sync IO does not cause aborts, so it's okay if it happens before render. const initialRscPayload = await getPayload(requestStore); const initialStreamResult = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ initialStageController.advanceStage(_stagedrendering.RenderStage.EarlyStatic); startTime = performance.now() + performance.timeOrigin; const streamPair = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ComponentMod, initialRscPayload, clientModules, { onError, environmentName, startTime, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide, signal: initialReactController.signal }).tee(); // If we abort the render, we want to reject the stage-dependent promises as well. // Note that we want to install this listener after the render is started // so that it runs after react is finished running its abort code. initialReactController.signal.addEventListener('abort', ()=>{ const { reason } = initialReactController.signal; initialDataController.abort(reason); }, { once: true }); const stream = streamPair[0]; const accumulatedChunksPromise = accumulateStreamChunks(streamPair[1], initialStageController, initialDataController.signal); initialDataController.signal.addEventListener('abort', ()=>{ accumulatedChunksPromise.catch(()=>{}); stream.cancel(); }, { once: true }); return { stream, accumulatedChunksPromise }; }, ()=>{ if (initialAbandonController.signal.aborted === true) { return; } else if (cacheSignal.hasPendingReads()) { initialAbandonController.abort(); } else { initialStageController.advanceStage(_stagedrendering.RenderStage.Static); } }, ()=>{ if (initialAbandonController.signal.aborted === true) { return; } else if (cacheSignal.hasPendingReads()) { initialAbandonController.abort(); } else { initialStageController.advanceStage(_stagedrendering.RenderStage.EarlyRuntime); } }, ()=>{ if (initialAbandonController.signal.aborted === true) { return; } else if (cacheSignal.hasPendingReads()) { initialAbandonController.abort(); } else { initialStageController.advanceStage(_stagedrendering.RenderStage.Runtime); } }, ()=>{ if (initialAbandonController.signal.aborted === true) { return; } else if (cacheSignal.hasPendingReads()) { initialAbandonController.abort(); } else { initialStageController.advanceStage(_stagedrendering.RenderStage.Dynamic); } }); if (initialStageController.currentStage !== _stagedrendering.RenderStage.Abandoned) { // No cache misses. We can use the result as-is. return { stream: initialStreamResult.stream, accumulatedChunksPromise: initialStreamResult.accumulatedChunksPromise, syncInterruptReason: initialStageController.getSyncInterruptReason(), startTime, staticStageEndTime: initialStageController.getStaticStageEndTime(), runtimeStageEndTime: initialStageController.getRuntimeStageEndTime(), debugChannel, requestStore }; } if (process.env.__NEXT_DEV_SERVER && setCacheStatus) { setCacheStatus('filling', htmlRequestId); } // Cache miss. We will use the initial render to fill caches, and discard its result. // Then, we can render again with warm caches. // TODO(restart-on-cache-miss): // This might end up waiting for more caches than strictly necessary, // because we can't abort the render yet, and we'll let runtime/dynamic APIs resolve. // Ideally we'd only wait for caches that are needed in the static stage. // This will be optimized in the future by not allowing runtime/dynamic APIs to resolve. await cacheSignal.cacheReady(); initialReactController.abort(); //=============================================== // Final render (restarted) //=============================================== // The initial render acted as a prospective render to warm the caches. requestStore = createRequestStore(); // We are going to render this pass all the way through because we've already // filled any caches so we won't be aborting this time. const abortSignal = null; const finalStageController = new _stagedrendering.StagedRenderingController(abortSignal, null, true // track sync IO ); // We've filled the caches, so now we can render as usual, // without any cache-filling mechanics. requestStore.prerenderResumeDataCache = null; requestStore.renderResumeDataCache = (0, _resumedatacache.createRenderResumeDataCache)(prerenderResumeDataCache); requestStore.stagedRendering = finalStageController; requestStore.cacheSignal = null; requestStore.asyncApiPromises = createAsyncApiPromises(finalStageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); // The initial render already wrote to its debug channel. // We're not using it, so we need to create a new one. debugChannel = setReactDebugChannel && (0, _debugchannelserver.createDebugChannel)(); // Note: The stage controller starts out in the `Before` stage, // where sync IO does not cause aborts, so it's okay if it happens before render. const finalRscPayload = await getPayload(requestStore); const finalStreamResult = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ finalStageController.advanceStage(_stagedrendering.RenderStage.EarlyStatic); startTime = performance.now() + performance.timeOrigin; const streamPair = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ComponentMod, finalRscPayload, clientModules, { onError, environmentName, startTime, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide }).tee(); return { stream: streamPair[0], accumulatedChunksPromise: accumulateStreamChunks(streamPair[1], finalStageController, null) }; }, ()=>{ // Static stage finalStageController.advanceStage(_stagedrendering.RenderStage.Static); }, ()=>{ // EarlyRuntime stage finalStageController.advanceStage(_stagedrendering.RenderStage.EarlyRuntime); }, ()=>{ // Runtime stage finalStageController.advanceStage(_stagedrendering.RenderStage.Runtime); }, ()=>{ // Dynamic stage finalStageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); if (process.env.__NEXT_DEV_SERVER && setCacheStatus) { setCacheStatus('filled', htmlRequestId); } return { stream: finalStreamResult.stream, accumulatedChunksPromise: finalStreamResult.accumulatedChunksPromise, syncInterruptReason: finalStageController.getSyncInterruptReason(), startTime, staticStageEndTime: finalStageController.getStaticStageEndTime(), runtimeStageEndTime: finalStageController.getRuntimeStageEndTime(), debugChannel, requestStore }; } async function accumulateStreamChunks(stream, stageController, signal) { const staticChunks = []; const runtimeChunks = []; const dynamicChunks = []; const reader = stream.getReader(); let cancelled = false; function cancel() { if (!cancelled) { cancelled = true; reader.cancel(); } } if (signal) { signal.addEventListener('abort', cancel, { once: true }); } try { while(!cancelled){ const { done, value } = await reader.read(); if (done) { cancel(); break; } switch(stageController.currentStage){ case _stagedrendering.RenderStage.Before: throw Object.defineProperty(new _invarianterror.InvariantError('Unexpected stream chunk while in Before stage'), "__NEXT_ERROR_CODE", { value: "E942", enumerable: false, configurable: true }); case _stagedrendering.RenderStage.EarlyStatic: case _stagedrendering.RenderStage.Static: staticChunks.push(value); // fall through case _stagedrendering.RenderStage.EarlyRuntime: case _stagedrendering.RenderStage.Runtime: runtimeChunks.push(value); // fall through case _stagedrendering.RenderStage.Dynamic: dynamicChunks.push(value); break; case _stagedrendering.RenderStage.Abandoned: break; default: stageController.currentStage; break; } } } catch (err) { // When we cancel the reader we may reject the read. // Only swallow errors caused by our intentional cancel(); // re-throw unexpected errors to avoid silently returning partial data. if (!cancelled) { throw err; } } return { staticChunks, runtimeChunks, dynamicChunks }; } async function countStaticStageBytes(stream, stageController) { let byteLength = 0; const reader = stream.getReader(); stageController.onStage(_stagedrendering.RenderStage.EarlyRuntime, ()=>{ reader.cancel(); }); while(true){ const { done, value } = await reader.read(); if (done) { break; } if (stageController.currentStage <= _stagedrendering.RenderStage.Static) { byteLength += value.byteLength; } else { reader.cancel(); break; } } return byteLength; } function createAsyncApiPromises(stagedRendering, cookies, mutableCookies, headers) { return { // Runtime APIs (for prefetch segments) cookies: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.Runtime, 'cookies', cookies), earlyCookies: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.EarlyRuntime, 'cookies', cookies), mutableCookies: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.Runtime, 'cookies', mutableCookies), earlyMutableCookies: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.EarlyRuntime, 'cookies', mutableCookies), headers: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.Runtime, 'headers', headers), earlyHeaders: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.EarlyRuntime, 'headers', headers), // These are not used directly, but we chain other `params`/`searchParams` promises off of them. sharedParamsParent: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.Runtime, undefined, ''), earlySharedParamsParent: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.EarlyRuntime, undefined, ''), sharedSearchParamsParent: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.Runtime, undefined, ''), earlySharedSearchParamsParent: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.EarlyRuntime, undefined, ''), connection: stagedRendering.delayUntilStage(_stagedrendering.RenderStage.Dynamic, 'connection', undefined) }; } /** * Logs the given messages, and sends the error instances to the browser as an * RSC stream, where they can be deserialized and logged (or otherwise presented * in the devtools), while leveraging React's capabilities to not only * source-map the stack frames (via findSourceMapURL), but also create virtual * server modules that allow users to inspect the server source code in the * browser. */ async function logMessagesAndSendErrorsToBrowser(messages, ctx) { const { htmlRequestId, renderOpts } = ctx; const { sendErrorsToBrowser } = renderOpts; const errors = []; for (const message of messages){ // Log the error to the CLI. Prevent the logs from being dimmed, which we // apply for other logs during the spawned validation. _consoleasyncstorageexternal.consoleAsyncStorage.exit(()=>{ console.error(message); }); // Error instances are also sent to the browser. We're currently using a // non-Error message only in debug build mode as a message that is only // meant for the CLI. FIXME: This is a bit spooky action at a distance. We // should maybe have a more explicit way of determining which messages // should be sent to the browser. Regardless, only real errors with a proper // stack make sense to be "replayed" in the browser. if (message instanceof Error) { errors.push(message); } } if (errors.length > 0) { if (!sendErrorsToBrowser) { throw Object.defineProperty(new _invarianterror.InvariantError('Expected `sendErrorsToBrowser` to be defined in renderOpts.'), "__NEXT_ERROR_CODE", { value: "E947", enumerable: false, configurable: true }); } // Build a Map of error → error code for errors that have one. // React doesn't revive __NEXT_ERROR_CODE during RSC deserialization, so we // send it as a side-channel Map. RSC preserves object identity, so the // deserialized Map keys will reference the same Error objects. const errorCodes = new Map(); for (const err of errors){ const code = (0, _errortelemetryutils.extractNextErrorCode)(err); if (code !== undefined) { errorCodes.set(err, code); } } const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const errorsFlightStream = (0, _streamops.renderToFlightStream)(ctx.componentMod, { errors, errorCodes }, clientModules, { filterStackFrame }); sendErrorsToBrowser(errorsFlightStream, htmlRequestId); } } function logValidationSkipped(ctx) { if (process.env.__NEXT_TEST_MODE && process.env.NEXT_TEST_LOG_VALIDATION) { const requestId = ctx.requestId; const url = ctx.url.href; console.log('' + JSON.stringify({ type: 'validation_start', requestId, url }) + ''); console.log('' + JSON.stringify({ type: 'validation_end', requestId, url }) + ''); } } async function spawnStaticShellValidationInDev(...args) { if (process.env.__NEXT_TEST_MODE && process.env.NEXT_TEST_LOG_VALIDATION) { const ctx = args[5]; const requestId = ctx.requestId; const url = ctx.url.href; console.log('' + JSON.stringify({ type: 'validation_start', requestId, url }) + ''); try { return await spawnStaticShellValidationInDevImpl(...args); } finally{ console.log('' + JSON.stringify({ type: 'validation_end', requestId, url }) + ''); } } else { return await spawnStaticShellValidationInDevImpl(...args); } } /** * This function is a fork of prerenderToStream cacheComponents branch. * While it doesn't return a stream we want it to have identical * prerender semantics to prerenderToStream and should update it * in conjunction with any changes to that function. */ async function spawnStaticShellValidationInDevImpl(accumulatedChunksPromise, syncInterruptReason, startTime, staticStageEndTime, runtimeStageEndTime, ctx, requestStore, fallbackRouteParams, debugChannelClient) { const debug = process.env.NEXT_PRIVATE_DEBUG_VALIDATION === '1' ? console.log : undefined; const { componentMod: ComponentMod, getDynamicParamFromSegment, renderOpts, workStore } = ctx; const loaderTree = ComponentMod.routeModule.userland.loaderTree; const allowEmptyStaticShell = (renderOpts.allowEmptyStaticShell ?? false) || await (0, _instantconfig.isPageAllowedToBlock)(loaderTree); const rootParams = (0, _createcomponenttree.getRootParams)(loaderTree, getDynamicParamFromSegment); const hmrRefreshHash = (0, _workunitasyncstorageexternal.getHmrRefreshHash)(requestStore); // We don't need to continue the prerender process if we already // detected invalid dynamic usage in the initial prerender phase. const { invalidDynamicUsageError } = workStore; if (invalidDynamicUsageError) { return logMessagesAndSendErrorsToBrowser([ invalidDynamicUsageError ], ctx); } if (syncInterruptReason) { return logMessagesAndSendErrorsToBrowser([ syncInterruptReason ], ctx); } let debugChunks = null; if (debugChannelClient) { debugChunks = []; debugChannelClient.on('data', (c)=>{ debugChunks.push(c); }); } const accumulatedChunks = await accumulatedChunksPromise; const { staticChunks, runtimeChunks, dynamicChunks } = accumulatedChunks; const needsInstantValidation = await (0, _instantconfig.anySegmentNeedsInstantValidationInDev)(loaderTree); // `samples` from instant config are only used during build const validationSamples = null; const validationSampleTracking = null; // First we warmup SSR with the runtime chunks. This ensures that when we do // the full prerender pass with dynamic tracking module loading won't // interrupt the prerender and can properly observe the entire content await warmupClientModulesForStagedValidation(// if we're going to be validating prefetches, we'll be rendering some segments in the dynamic stage. // otherwise, for static shell validation, we only need to warm up to the runtime stage. // we also need to use a different store type, because instant validation allows more APIs to resolve. needsInstantValidation ? 'validation-client' : 'prerender-client', needsInstantValidation ? dynamicChunks : runtimeChunks, dynamicChunks, rootParams, fallbackRouteParams, allowEmptyStaticShell, ctx, validationSamples, validationSampleTracking); debug == null ? void 0 : debug(`Starting static shell validation...`); const runtimeResult = await validateStagedShell(runtimeChunks, dynamicChunks, debugChunks, runtimeStageEndTime, rootParams, fallbackRouteParams, allowEmptyStaticShell, ctx, hmrRefreshHash, _dynamicrendering.trackDynamicHoleInRuntimeShell); if (runtimeResult.length > 0) { debug == null ? void 0 : debug(`❌ Failed - ${runtimeResult.length} errors from runtime stage`); // We have something to report from the runtime validation // We can skip the rest return logMessagesAndSendErrorsToBrowser(runtimeResult, ctx); } const staticResult = await validateStagedShell(staticChunks, dynamicChunks, debugChunks, staticStageEndTime, rootParams, fallbackRouteParams, allowEmptyStaticShell, ctx, hmrRefreshHash, _dynamicrendering.trackDynamicHoleInStaticShell); if (staticResult.length > 0) { debug == null ? void 0 : debug(`❌ Failed - ${staticResult.length} errors from static stage`); // We have something to report from the static validation // We can skip the rest return logMessagesAndSendErrorsToBrowser(staticResult, ctx); } debug == null ? void 0 : debug(`✅ Passed`); if (needsInstantValidation) { const instantConfigsResult = await validateInstantConfigs(accumulatedChunks, debugChunks, startTime, rootParams, fallbackRouteParams, ctx, hmrRefreshHash, validationSamples); if (instantConfigsResult.length > 0) { return logMessagesAndSendErrorsToBrowser(instantConfigsResult, ctx); } } } async function warmupClientModulesForStagedValidation(storeType, partialServerChunks, allServerChunks, rootParams, fallbackRouteParams, allowEmptyStaticShell, ctx, validationSamples, validationSampleTracking) { const { implicitTags, nonce, workStore } = ctx; // Warmup SSR const initialClientPrerenderController = new AbortController(); const initialClientReactController = new AbortController(); const initialClientRenderController = new AbortController(); const preinitScripts = ()=>{}; const { ServerInsertedHTMLProvider } = (0, _serverinsertedhtml.createServerInsertedHTML)(); let initialClientPrerenderStore; if (storeType === 'prerender-client') { const store = { type: 'prerender-client', phase: 'render', rootParams, fallbackRouteParams, implicitTags, renderSignal: initialClientRenderController.signal, controller: initialClientPrerenderController, // For HTML Generation the only cache tracked activity // is module loading, which has it's own cache signal cacheSignal: null, dynamicTracking: null, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], // TODO should this be removed from client stores? prerenderResumeDataCache: null, renderResumeDataCache: null, hmrRefreshHash: undefined, // Client prerenders don't track server param access varyParamsAccumulator: null }; initialClientPrerenderStore = store; } else { const store = { type: 'validation-client', phase: 'render', rootParams, implicitTags, renderSignal: initialClientRenderController.signal, controller: initialClientPrerenderController, // For HTML Generation the only cache tracked activity // is module loading, which has it's own cache signal cacheSignal: null, dynamicTracking: null, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], // TODO should this be removed from client stores? prerenderResumeDataCache: null, renderResumeDataCache: null, hmrRefreshHash: undefined, // Client prerenders don't track server param access varyParamsAccumulator: null, // We're not rendering any validation boundaries yet. boundaryState: null, validationSamples, validationSampleTracking, fallbackRouteParams }; initialClientPrerenderStore = store; } // TODO: maybe conditionally switch between runtime chunks and all chunks? // but warming too much should always be fine, just not always necessary const serverStream = (0, _streamutils.createNodeStreamWithLateRelease)(partialServerChunks, allServerChunks, initialClientReactController.signal); const pendingInitialClientResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialClientPrerenderStore, _streamops.getClientPrerender, // eslint-disable-next-line @next/internal/no-ambiguous-jsx -- React Client /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: serverStream, reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { signal: initialClientReactController.signal, onError: (err)=>{ const digest = (0, _createerrorhandler.getDigestForWellKnownError)(err); if (digest) { return digest; } if ((0, _reactlargeshellerror.isReactLargeShellError)(err)) { // TODO: Aggregate console.error(err); return undefined; } if (initialClientReactController.signal.aborted) { // These are expected errors that might error the prerender. we ignore them. } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { // We don't normally log these errors because we are going to retry anyway but // it can be useful for debugging Next.js itself to get visibility here when needed (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } } }); // The listener to abort our own render controller must be added after React // has added its listener, to ensure that pending I/O is not // aborted/rejected too early. initialClientReactController.signal.addEventListener('abort', ()=>{ initialClientRenderController.abort(); }, { once: true }); pendingInitialClientResult.catch((err)=>{ if (initialClientReactController.signal.aborted || (0, _dynamicrendering.isPrerenderInterruptedError)(err)) { // These are expected errors that might error the prerender. we ignore them. } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { // We don't normally log these errors because we are going to retry anyway but // it can be useful for debugging Next.js itself to get visibility here when needed (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } }); // This is mostly needed for dynamic `import()`s in client components. // Promises passed to client were already awaited above (assuming that they came from cached functions) const cacheSignal = new _cachesignal.CacheSignal(); (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); await cacheSignal.cacheReady(); initialClientReactController.abort(); } async function validateStagedShell(stageChunks, allServerChunks, debugChunks, debugEndTime, rootParams, fallbackRouteParams, allowEmptyStaticShell, ctx, hmrRefreshHash, trackDynamicHole) { const { implicitTags, nonce, workStore } = ctx; const clientDynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(false //isDebugDynamicAccesses ); const clientReactController = new AbortController(); const clientRenderController = new AbortController(); const preinitScripts = ()=>{}; const { ServerInsertedHTMLProvider } = (0, _serverinsertedhtml.createServerInsertedHTML)(); const finalClientPrerenderStore = { type: 'prerender-client', phase: 'render', rootParams, fallbackRouteParams, implicitTags, renderSignal: clientRenderController.signal, controller: clientReactController, // No APIs require a cacheSignal through the workUnitStore during the HTML prerender cacheSignal: null, dynamicTracking: clientDynamicTracking, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], // TODO should this be removed from client stores? prerenderResumeDataCache: null, renderResumeDataCache: null, hmrRefreshHash, // Client prerenders don't track server param access varyParamsAccumulator: null }; const dynamicValidation = (0, _dynamicrendering.createDynamicValidationState)(); const serverStream = (0, _streamutils.createNodeStreamWithLateRelease)(stageChunks, allServerChunks, clientReactController.signal); const debugChannelClient = debugChunks ? (0, _streamutils.createNodeStreamWithLateRelease)(debugChunks, debugChunks, clientReactController.signal) : undefined; try { let { prelude: unprocessedPrelude } = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ const pendingFinalClientResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalClientPrerenderStore, _streamops.getClientPrerender, // eslint-disable-next-line @next/internal/no-ambiguous-jsx -- React Client /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: serverStream, reactDebugStream: debugChannelClient, debugEndTime: debugEndTime, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { signal: clientReactController.signal, onError: (err, errorInfo)=>{ if ((0, _dynamicrendering.isPrerenderInterruptedError)(err) || clientReactController.signal.aborted) { const componentStack = errorInfo.componentStack; if (typeof componentStack === 'string') { trackDynamicHole(workStore, componentStack, dynamicValidation, clientDynamicTracking); } return; } if ((0, _reactlargeshellerror.isReactLargeShellError)(err)) { // TODO: Aggregate console.error(err); return undefined; } return (0, _createerrorhandler.getDigestForWellKnownError)(err); } }); // The listener to abort our own render controller must be added after // React has added its listener, to ensure that pending I/O is not // aborted/rejected too early. clientReactController.signal.addEventListener('abort', ()=>{ clientRenderController.abort(); }, { once: true }); return pendingFinalClientResult; }, ()=>{ clientReactController.abort(); }); const { preludeIsEmpty } = await (0, _streamops.processPrelude)(unprocessedPrelude); return (0, _dynamicrendering.getStaticShellDisallowedDynamicReasons)(workStore, preludeIsEmpty ? _dynamicrendering.PreludeState.Empty : _dynamicrendering.PreludeState.Full, dynamicValidation, // TODO(instant-validation): if allowEmptyStaticShell is true (likely due to blocking configs), // we should probably just skip this altogether allowEmptyStaticShell); } catch (thrownValue) { // Even if the root errors we still want to report any cache components errors // that were discovered before the root errored. let errors = (0, _dynamicrendering.getStaticShellDisallowedDynamicReasons)(workStore, _dynamicrendering.PreludeState.Errored, dynamicValidation, // TODO(instant-validation): if allowEmptyStaticShell is true (likely due to blocking configs), // we should probably just skip this altogether allowEmptyStaticShell); if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { errors.unshift('During dynamic validation the root of the page errored. The next logged error is the thrown value. It may be a duplicate of errors reported during the normal development mode render.', thrownValue); } return errors; } } /** * Validates instant configs by iterating URL depths from deepest to * shallowest. At each depth, builds a combined payload where segments * above the boundary use Dynamic stage (already mounted) and segments * below use Static/Runtime stage (being prefetched). If the new subtree * contains any `unstable_instant` configs, the payload is rendered to * detect dynamic holes without Suspense. */ async function validateInstantConfigs(accumulatedChunks, debugChunks, startTime, rootParams, fallbackRouteParams, ctx, hmrRefreshHash, validationSamples) { const debug = process.env.NEXT_PRIVATE_DEBUG_VALIDATION === '1' ? console.log : undefined; const { createCombinedPayloadAtDepth, createCombinedPayloadStream, collectStagedSegmentData, discoverValidationDepths } = ctx.componentMod.InstantValidation(); const { createValidationSampleTracking } = require('./instant-validation/instant-samples'); debug == null ? void 0 : debug('\nStarting depth-based instant validation...'); const loaderTree = ctx.componentMod.routeModule.userland.loaderTree; // Only affects a debug environment name label, not functional behavior. const hasRuntimePrefetch = true; const clientReferenceManifest = (0, _manifestssingleton.getClientReferenceManifest)(); const { cache, payload: initialRscPayload, stageEndTimes } = await collectStagedSegmentData({ [_stagedrendering.RenderStage.Static]: accumulatedChunks.staticChunks, [_stagedrendering.RenderStage.Runtime]: accumulatedChunks.runtimeChunks, [_stagedrendering.RenderStage.Dynamic]: accumulatedChunks.dynamicChunks }, debugChunks, startTime, hasRuntimePrefetch, clientReferenceManifest); const { implicitTags, nonce, workStore } = ctx; const isDebugChannelEnabled = !!ctx.renderOpts.setReactDebugChannel; /** * Build and validate a combined payload at the given URL depth. * * Returns null if no instant config exists at this depth. * Returns an empty array if validation passed. * Returns a non-empty array of errors if validation failed. * * When the initial validation uses static segments and finds errors, * automatically retries with runtime stages to discriminate between * runtime and dynamic errors, returning the more specific result. */ async function validateAtDepth(depth, groupDepthForValidation) { return validateAtDepthImpl(depth, groupDepthForValidation, null); } async function validateAtDepthImpl(depth, groupDepthForValidation, previousBoundaryState) { const extraChunksController = new AbortController(); const boundaryState = (0, _boundarytracking.createValidationBoundaryTracking)(); let useRuntimeStageForPartialSegments = false; if (previousBoundaryState) { // We're doing a followup render to better discriminate error types useRuntimeStageForPartialSegments = true; for (const id of previousBoundaryState.expectedIds){ boundaryState.expectedIds.add(id); } } const payloadResult = await createCombinedPayloadAtDepth(initialRscPayload, cache, loaderTree, ctx.getDynamicParamFromSegment, ctx.query, depth, groupDepthForValidation, extraChunksController.signal, boundaryState, clientReferenceManifest, stageEndTimes, useRuntimeStageForPartialSegments); if (payloadResult === null) { return null; } const reactController = new AbortController(); const renderController = new AbortController(); const preinitScripts = ()=>{}; const { ServerInsertedHTMLProvider } = (0, _serverinsertedhtml.createServerInsertedHTML)(); const { stream: serverStream, debugStream } = await createCombinedPayloadStream(payloadResult.payload, extraChunksController, reactController.signal, clientReferenceManifest, startTime, isDebugChannelEnabled); const instantValidationState = (0, _dynamicrendering.createInstantValidationState)(payloadResult.createInstantStack); const validationSampleTracking = validationSamples !== null ? createValidationSampleTracking() : null; const clientDynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(false); const prerenderStore = { type: 'validation-client', phase: 'render', rootParams, implicitTags, renderSignal: renderController.signal, controller: reactController, cacheSignal: null, dynamicTracking: clientDynamicTracking, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache: null, renderResumeDataCache: null, hmrRefreshHash, varyParamsAccumulator: null, boundaryState, fallbackRouteParams, validationSamples, validationSampleTracking }; let errors; try { const { prelude: unprocessedPrelude } = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ const pendingResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderStore, _streamops.getClientPrerender, // eslint-disable-next-line @next/internal/no-ambiguous-jsx -- React Client /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: serverStream, reactDebugStream: debugStream ?? undefined, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { signal: reactController.signal, onError: (err, errorInfo)=>{ if ((0, _dynamicrendering.isPrerenderInterruptedError)(err) || reactController.signal.aborted) { const componentStack = errorInfo.componentStack; if (typeof componentStack === 'string') { (0, _dynamicrendering.trackDynamicHoleInNavigation)(workStore, componentStack, instantValidationState, clientDynamicTracking, payloadResult.hasAmbiguousErrors ? _dynamicrendering.DynamicHoleKind.Runtime : _dynamicrendering.DynamicHoleKind.Dynamic, boundaryState); } return; } else if (!reactController.signal.aborted) { const componentStack = errorInfo.componentStack; if (typeof componentStack === 'string') { let errorForDisplay = err; if (process.env.NODE_ENV === 'production') { // In production (i.e. build validation), Flight omits everything except the digest // when serializing errors, which makes them very unfriendly for debugging. // Map the deserialized errors back to their original error object to make it more useful. if (err && typeof err === 'object' && 'digest' in err && typeof err.digest === 'string') { const serverError = workStore.reactServerErrorsByDigest.get(err.digest); if (serverError !== undefined) { errorForDisplay = serverError; } } } (0, _dynamicrendering.trackThrownErrorInNavigation)(workStore, instantValidationState, errorForDisplay, componentStack); } } if ((0, _reactlargeshellerror.isReactLargeShellError)(err)) { console.error(err); return undefined; } return (0, _createerrorhandler.getDigestForWellKnownError)(err); } }); reactController.signal.addEventListener('abort', ()=>{ renderController.abort(); }, { once: true }); return pendingResult; }, ()=>{ reactController.abort(); }); const { preludeIsEmpty } = await (0, _streamops.processPrelude)(unprocessedPrelude); errors = (0, _dynamicrendering.getNavigationDisallowedDynamicReasons)(workStore, preludeIsEmpty ? _dynamicrendering.PreludeState.Empty : _dynamicrendering.PreludeState.Full, instantValidationState, validationSampleTracking, boundaryState); } catch (thrownValue) { errors = (0, _dynamicrendering.getNavigationDisallowedDynamicReasons)(workStore, _dynamicrendering.PreludeState.Errored, instantValidationState, validationSampleTracking, boundaryState); } // This prerender did not produce any errors if (errors.length === 0) { return []; } if (previousBoundaryState === null && payloadResult.hasAmbiguousErrors) { // This is the first validation attempt. we prepared a payload where dynamic holes might be runtime data dependencies // or dynamic data dependencies. We do a followup validation using a payload with only Runtime segments to discriminate const dynamicOnlyErrors = await validateAtDepthImpl(depth, groupDepthForValidation, boundaryState); if (dynamicOnlyErrors !== null && dynamicOnlyErrors.length > 0) { // The dynamic errors only validation found errors to report so we favor those return dynamicOnlyErrors; } } // If we didn't return some other errors at this point the only thing to return is this validation's errors return errors; } // Discover validation depth bounds from the LoaderTree. The array // length is the max URL depth; each entry is the max group depth // (route group segments) between that URL depth and the next. const groupDepthsByUrlDepth = discoverValidationDepths(loaderTree); const maxDepth = groupDepthsByUrlDepth.length; for(let depth = maxDepth - 1; depth >= 0; depth--){ const maxGroupDepth = groupDepthsByUrlDepth[depth]; for(let currentGroupDepth = maxGroupDepth; currentGroupDepth >= 0; currentGroupDepth--){ debug == null ? void 0 : debug(`Trying depth ${depth}` + (currentGroupDepth > 0 ? ` + groupDepth ${currentGroupDepth}...` : '...')); const errors = await validateAtDepth(depth, currentGroupDepth); if (errors === null) { debug == null ? void 0 : debug(` No config at depth ${depth}+${currentGroupDepth}, skipping.`); continue; } if (errors.length > 0) { debug == null ? void 0 : debug(` Depth ${depth}+${currentGroupDepth}: ❌ Failed (${errors.length} errors)`); return errors; } debug == null ? void 0 : debug(` Depth ${depth}+${currentGroupDepth}: ✅ Passed`); } } debug == null ? void 0 : debug(`✅ All depths passed`); return []; } /** * Two-pass render for build-time instant validation. * The flow is similar to `renderWithRestartOnCacheMissInDev`: pass 1 warms caches, * pass 2 renders with warm caches. If pass 1 has no cache misses, * its result is returned directly. * * Differences from `renderWithRestartOnCacheMissInDev`: * - both renders are abortable: if we know that we can't use a stream, we can just * throw it away, we don't have to render a complete result. * - We don't need to tee the stream, we only care about accumulating chunks. */ async function renderWithRestartOnCacheMissInValidation(ctx, initialRequestStore, createRequestStore, getPayload, createOnError, prefilledDataCache) { const { componentMod: ComponentMod } = ctx; const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); let startTime = -Infinity; let requestStore = initialRequestStore; //=============================================== // Initial render (prospective — may warm caches) //=============================================== const cacheSignal = new _cachesignal.CacheSignal(); (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); // The prerender we rean before the validation probably already filled some caches, // so we want to save work and re-use them. const prerenderResumeDataCache = prefilledDataCache ? (0, _resumedatacache.createPrerenderResumeDataCache)(prefilledDataCache) : (0, _resumedatacache.createPrerenderResumeDataCache)(); const initialReactController = new AbortController(); const initialDataController = new AbortController(); const initialAbandonController = new AbortController(); const initialStageController = new _stagedrendering.StagedRenderingController(initialDataController.signal, initialAbandonController, true // track sync IO ); requestStore.prerenderResumeDataCache = prerenderResumeDataCache; requestStore.renderResumeDataCache = null; requestStore.stagedRendering = initialStageController; requestStore.cacheSignal = cacheSignal; requestStore.asyncApiPromises = createAsyncApiPromises(initialStageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); // We don't set `requestStore.controller and requestStore.renderSignal here. // Right now, we only abort for sync IO, and in the first render, that's just a restart // (after waiting for caches) requestStore.controller = undefined; requestStore.renderSignal = undefined; const initialRscPayload = await getPayload(requestStore); const advanceStageIfNoCacheMiss = (stage)=>{ if (initialAbandonController.signal.aborted === true) { return; } else if (cacheSignal.hasPendingReads()) { initialAbandonController.abort(); } else { initialStageController.advanceStage(stage); } }; const initialResult = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ initialStageController.advanceStage(_stagedrendering.RenderStage.EarlyStatic); startTime = performance.now() + performance.timeOrigin; const stream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ComponentMod, initialRscPayload, clientModules, { onError: createOnError(initialReactController.signal, false), startTime, filterStackFrame, signal: initialReactController.signal }); initialReactController.signal.addEventListener('abort', ()=>{ const { reason } = initialReactController.signal; initialDataController.abort(reason); }, { once: true }); const accumulatedChunksPromise = accumulateStreamChunks(stream, initialStageController, initialDataController.signal); accumulatedChunksPromise.catch(()=>{}); return { accumulatedChunksPromise }; }, ()=>{ advanceStageIfNoCacheMiss(_stagedrendering.RenderStage.Static); }, ()=>{ advanceStageIfNoCacheMiss(_stagedrendering.RenderStage.EarlyRuntime); }, ()=>{ advanceStageIfNoCacheMiss(_stagedrendering.RenderStage.Runtime); }, ()=>{ advanceStageIfNoCacheMiss(_stagedrendering.RenderStage.Dynamic); }); if (initialStageController.currentStage !== _stagedrendering.RenderStage.Abandoned) { // No cache misses. Use the result as-is. return { accumulatedChunksPromise: initialResult.accumulatedChunksPromise, startTime, stageController: initialStageController, requestStore }; } // Cache miss. Wait for caches to fill, then re-render with warm caches. await cacheSignal.cacheReady(); initialReactController.abort(); //=============================================== // Final render (restarted, with warm caches) //=============================================== requestStore = createRequestStore(); // Unlike dev, where we're re-using the render that'll be visible in the browser, // we *can* abort the validation render. const finalReactController = new AbortController(); const finalDataController = new AbortController(); const finalStageController = new _stagedrendering.StagedRenderingController(finalDataController.signal, null, true // track sync IO ); requestStore.prerenderResumeDataCache = null; requestStore.renderResumeDataCache = (0, _resumedatacache.createRenderResumeDataCache)(prerenderResumeDataCache); requestStore.stagedRendering = finalStageController; requestStore.cacheSignal = null; requestStore.asyncApiPromises = createAsyncApiPromises(finalStageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); // Right now, we only abort for sync IO. // If sync IO occurs in a place where it's not allowed, then we have to fail validation, // and we can abort the render immediately, without waiting for anything else.. requestStore.controller = finalReactController; requestStore.renderSignal = finalDataController.signal; const finalRscPayload = await getPayload(requestStore); const finalResult = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ finalStageController.advanceStage(_stagedrendering.RenderStage.EarlyStatic); startTime = performance.now() + performance.timeOrigin; const stream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToFlightStream, ComponentMod, finalRscPayload, clientModules, { onError: createOnError(finalReactController.signal, true), startTime, filterStackFrame, signal: finalReactController.signal }); finalReactController.signal.addEventListener('abort', ()=>{ finalDataController.abort(finalReactController.signal.reason); }, { once: true }); const accumulatedChunksPromise = accumulateStreamChunks(stream, finalStageController, null); accumulatedChunksPromise.catch(()=>{}); return { accumulatedChunksPromise }; }, ()=>{ finalStageController.advanceStage(_stagedrendering.RenderStage.Static); }, ()=>{ finalStageController.advanceStage(_stagedrendering.RenderStage.EarlyRuntime); }, ()=>{ finalStageController.advanceStage(_stagedrendering.RenderStage.Runtime); }, ()=>{ finalStageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); return { accumulatedChunksPromise: finalResult.accumulatedChunksPromise, startTime, stageController: finalStageController, requestStore }; } async function validateInstantConfigsInBuild(ctx, prefilledDataCache) { const run = async ()=>{ let success; try { // The validation renders are separate renders, and use a separate WorkStore. // However, we defensively exit the existing workStore to avoid relying on something from there // before we shadow it. success = await _workasyncstorageexternal.workAsyncStorage.exit(async ()=>validateInstantConfigsInBuildImpl(ctx, prefilledDataCache)); } catch (err) { console.error(Object.defineProperty(new _invarianterror.InvariantError('An unexpected error occcured during instant validation', { cause: err }), "__NEXT_ERROR_CODE", { value: "E1097", enumerable: false, configurable: true })); success = false; } if (!success) { console.error('Stopping prerender due to instant validation errors.'); throw new _staticgenerationbailout.StaticGenBailoutError(); } }; if (process.env.__NEXT_TEST_MODE && process.env.NEXT_TEST_LOG_VALIDATION) { // In tests, we use these markers to extract the relevant portion of the CLI logs. // We want consistent ordering of these messages and other console.error calls, // so we use console.error here as well. Using console.log leads to non-deterministic // log order, likely stdout/stderr can interleave in non-deterministic ways. const requestId = Date.now(); const route = ctx.workStore.route; console.error('' + JSON.stringify({ type: 'validation_start', requestId, url: route }) + ''); try { return await run(); } finally{ console.error('' + JSON.stringify({ type: 'validation_end', requestId, url: route }) + ''); } } else { return await run(); } } /** * Runs instant validation at build time using the `samples` from `unstable_instant`. * * For each sample, this creates a staged RSC render with a synthetic `RequestStore` * populated from sample data, then feeds the accumulated chunks to * `validateInstantConfigs` which handles the actual validation. */ async function validateInstantConfigsInBuildImpl(ctx, prefilledDataCache) { const debug = process.env.NEXT_PRIVATE_DEBUG_VALIDATION === '1' ? console.log : undefined; const { workStore: outerWorkStore } = ctx; const route = outerWorkStore.route; const loaderTree = ctx.componentMod.routeModule.userland.loaderTree; let samples = await (0, _instantconfig.resolveInstantConfigSamplesForPage)(loaderTree); if (!samples || samples.length === 0) { // No samples defined; use a single empty sample to still run validation samples = [ {} ]; } debug == null ? void 0 : debug('Resolved samples:', samples); const allPossibleFallbackRouteParams = (0, _fallbackparams.getFallbackRouteParams)(route, ctx.componentMod.routeModule); for(let sampleIndex = 0; sampleIndex < samples.length; sampleIndex++){ const sample = samples[sampleIndex]; debug == null ? void 0 : debug(`Validating sample (${sampleIndex + 1}/${samples.length}):`, sample); let errors; try { errors = await _consoleasyncstorageexternal.consoleAsyncStorage.run({ dim: true }, ()=>validateInstantConfigInBuildWithSample(ctx, sample, allPossibleFallbackRouteParams, prefilledDataCache)); } catch (err) { if ((0, _instantvalidationerror.isInstantValidationError)(err)) { errors = [ err ]; } else { throw err; } } if (errors.length > 0) { debug == null ? void 0 : debug(`❌ Sample failed validation (${errors.length} errors)`); const sampleDesc = samples.length > 1 ? ` (sample ${sampleIndex + 1} of ${samples.length})` : ''; for (const err of errors){ console.error(err); } console.error(`Build-time instant validation failed for route "${route}"${sampleDesc}.`); return false; } else { debug == null ? void 0 : debug('✅ Sample validated successfully'); } } return true; } async function validateInstantConfigInBuildWithSample(outerCtx, sample, allPossibleFallbackRouteParams, prefilledDataCache) { // The flow for build mirrors what we do when validating in dev. // We have to perform a full dynamic render to get the RSC chunks for each stage. // In order to do that, we have to set up a mock AppRenderContext, workStore, and requestStore // based on the `sample` we're using. const { workStore: outerWorkStore } = outerCtx; const loaderTree = outerCtx.componentMod.routeModule.userland.loaderTree; const route = outerWorkStore.route; const { createCookiesFromSample, createHeadersFromSample, createDraftModeForValidation, createRelativeURLFromSamples, createValidationSampleTracking } = require('./instant-validation/instant-samples'); // TODO(instant-validation-build): it feels like this should happen higher up // and go through existing URL parsing/generation logic? const sampleUrl = createRelativeURLFromSamples(route, sample.params, sample.searchParams); const sampleParams = sample.params ?? {}; let fallbackRouteParams = null; if (allPossibleFallbackRouteParams) { const fallbackRouteParamsMut = new Map(); for (const [paramKey, value] of allPossibleFallbackRouteParams){ if (!(paramKey in sampleParams)) { fallbackRouteParamsMut.set(paramKey, value); } } fallbackRouteParams = fallbackRouteParamsMut; } const getDynamicParamFromSegment = makeGetDynamicParamFromSegment(sampleParams, fallbackRouteParams, false); const sampleRootParams = (0, _createcomponenttree.getRootParams)(loaderTree, getDynamicParamFromSegment); let sampleUrlWithoutQuery; let sampleQuery; ({ query: sampleQuery, ...sampleUrlWithoutQuery } = sampleUrl); const { AfterContext } = require('../after/after-context'); // NOTE: Matching the field order in `createWorkStore` to avoid deopting. const workStore = { isStaticGeneration: false, page: outerWorkStore.page, route: outerWorkStore.route, incrementalCache: outerWorkStore.incrementalCache, cacheLifeProfiles: outerWorkStore.cacheLifeProfiles, isBuildTimePrerendering: false, fetchCache: outerWorkStore.fetchCache, isOnDemandRevalidate: false, isDraftMode: false, isPrefetchRequest: false, buildId: outerWorkStore.buildId, reactLoadableManifest: outerWorkStore.reactLoadableManifest, assetPrefix: outerWorkStore.assetPrefix, nonce: outerWorkStore.nonce, // Never run `after()` for this validation render. by definition, `after` can't affect the rendered output. afterContext: new AfterContext({ waitUntil (promise) { promise.catch(()=>{}); }, onClose () {}, onTaskError () {} }), cacheComponentsEnabled: outerWorkStore.cacheComponentsEnabled, previouslyRevalidatedTags: [], refreshTagsByCacheKind: new Map(), runInCleanSnapshot: outerWorkStore.runInCleanSnapshot, shouldTrackFetchMetrics: false, reactServerErrorsByDigest: new Map() }; return _workasyncstorageexternal.workAsyncStorage.run(workStore, async ()=>{ // NOTE: match field order in renderToHTMLOrFlightImpl to avoid deopts const validationCtx = { componentMod: outerCtx.componentMod, url: sampleUrlWithoutQuery, renderOpts: outerCtx.renderOpts, workStore, parsedRequestHeaders: outerCtx.parsedRequestHeaders, getDynamicParamFromSegment, interpolatedParams: sampleParams, query: sampleQuery, isPrefetch: false, isPossibleServerAction: false, requestTimestamp: outerCtx.requestTimestamp, appUsingSizeAdjustment: outerCtx.appUsingSizeAdjustment, flightRouterState: undefined, requestId: outerCtx.requestId, htmlRequestId: outerCtx.htmlRequestId, pagePath: outerCtx.pagePath, assetPrefix: outerCtx.assetPrefix, isNotFoundPath: outerCtx.isNotFoundPath, nonce: outerCtx.nonce, res: outerCtx.res, sharedContext: outerCtx.sharedContext, implicitTags: outerCtx.implicitTags }; const validationSamples = { params: sample.params, searchParams: sample.searchParams }; const createRequestStore = ()=>{ // Create exhaustive request data from sample const sampleCookies = createCookiesFromSample(sample.cookies, route); // We don't have to bother initializing these, pages can't access them anyway, // we just need them because RequestStore requires them. const unusedMutableCookies = new _cookies.ResponseCookies(new Headers()); // Create headers. const sampleHeaders = createHeadersFromSample(sample.headers, sample.cookies, route); const draftMode = createDraftModeForValidation(); return { type: 'request', phase: 'render', implicitTags: outerCtx.implicitTags, url: { pathname: sampleUrl.pathname, search: sampleUrl.search }, headers: sampleHeaders, cookies: sampleCookies, mutableCookies: unusedMutableCookies, userspaceMutableCookies: unusedMutableCookies, draftMode, rootParams: sampleRootParams, validationSamples, validationSampleTracking: createValidationSampleTracking(), // These will be set when rendering renderResumeDataCache: null, prerenderResumeDataCache: null, stagedRendering: null, asyncApiPromises: undefined }; }; // Track server errors. If one of them surfaces during the client render // in the deserialized form (with no message/stack) we'll use this to map it // back to the original. const onServerError = (0, _createerrorhandler.createReactServerErrorHandler)(true, true, workStore.reactServerErrorsByDigest, ()=>{} // Don't report anything here. If needed, it will be reported in the client render. ); const { accumulatedChunksPromise, startTime, stageController, requestStore: finalServerStore } = await renderWithRestartOnCacheMissInValidation(validationCtx, createRequestStore(), createRequestStore, (requestStore)=>_workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, getRSCPayload, loaderTree, validationCtx, { is404: false }), (signal)=>function onError(err) { const digest = (0, _createerrorhandler.getDigestForWellKnownError)(err); if (digest) { return digest; } if (signal.aborted) { return; } return onServerError(err); }, prefilledDataCache); const accumulatedChunks = await accumulatedChunksPromise; const debugChunks = null // TODO(instant-validation-build): support debugChannel ; // Missing sample errors take priority over everything else, // because they prevent us from rendering everything we need to validate. const serverValidationSampleTracking = finalServerStore.validationSampleTracking; if (serverValidationSampleTracking.missingSampleErrors.length > 0) { return serverValidationSampleTracking.missingSampleErrors; } // We also error for sync IO. This runs after the prerender, // so if we get sync IO errors here, they're likely from the runtime stage -- // the prerender probably discovered sync IO in the static stage if (stageController.currentStage === _stagedrendering.RenderStage.Abandoned && stageController.syncInterruptReason) { return [ stageController.syncInterruptReason ]; } const allowEmptyStaticShell = (validationCtx.renderOpts.allowEmptyStaticShell ?? false) || await (0, _instantconfig.isPageAllowedToBlock)(loaderTree); // Now we the chunks of a fully rendered page, just like in dev. // We can use them to validate all the navigations required by `instant` configs. // Note that we're not performing static shell validation here -- that happens // implicitly as part of the static prerender. // The static prerender has warmed some client modules already, // but we'll be reaching Runtime/Dynamic stages and thus rendering more content, // so we need to warm again. // TODO(instant-validation-build): This might warm too much, possibly hitting errors on code that didn't expect // to run at build time. For example, we generally don't need to render leaf segments (e.g. __PAGE__) in // the Dynamic stage, they're Runtime at best. const warmupValidationSamplesTracking = createValidationSampleTracking(); await warmupClientModulesForStagedValidation('validation-client', accumulatedChunks.dynamicChunks, accumulatedChunks.dynamicChunks, sampleRootParams, fallbackRouteParams, allowEmptyStaticShell, validationCtx, validationSamples, warmupValidationSamplesTracking); if (warmupValidationSamplesTracking.missingSampleErrors.length > 0) { return warmupValidationSamplesTracking.missingSampleErrors; } return await validateInstantConfigs(accumulatedChunks, debugChunks, startTime, sampleRootParams, fallbackRouteParams, validationCtx, undefined, validationSamples); }); } /** * Determines whether we should generate static flight data. */ function shouldGenerateStaticFlightData(workStore) { const { isStaticGeneration } = workStore; if (!isStaticGeneration) return false; return true; } async function prerenderToStream(req, res, ctx, metadata, tree, fallbackRouteParams) { // When prerendering formState is always null. We still include it // because some shared APIs expect a formState value and this is slightly // more explicit than making it an optional function argument const formState = null; const { assetPrefix, getDynamicParamFromSegment, implicitTags, nonce, pagePath, renderOpts, workStore } = ctx; const { basePath, buildManifest, ComponentMod, crossOrigin, experimental, isDebugDynamicAccesses, isBuildTimePrerendering = false, onInstrumentationRequestError, page, reactMaxHeadersLength, subresourceIntegrityManifest, cacheComponents } = renderOpts; const { cachedNavigations } = renderOpts.experimental; const allowEmptyStaticShell = (renderOpts.allowEmptyStaticShell ?? false) || await (0, _instantconfig.isPageAllowedToBlock)(tree); const rootParams = (0, _createcomponenttree.getRootParams)(tree, getDynamicParamFromSegment); const { ServerInsertedHTMLProvider, renderServerInsertedHTML } = (0, _serverinsertedhtml.createServerInsertedHTML)(); const getServerInsertedMetadata = (0, _createserverinsertedmetadata.createServerInsertedMetadata)(nonce); const tracingMetadata = (0, _utils1.getTracedMetadata)((0, _tracer.getTracer)().getTracePropagationData(), experimental.clientTraceMetadata); const polyfills = buildManifest.polyfillFiles.filter((polyfill)=>polyfill.endsWith('.js') && !polyfill.endsWith('.module.js')).map((polyfill)=>({ src: `${assetPrefix}/_next/${polyfill}${(0, _getassetquerystring.getAssetQueryString)(ctx, false)}`, integrity: subresourceIntegrityManifest == null ? void 0 : subresourceIntegrityManifest[polyfill], crossOrigin, noModule: true, nonce })); const [preinitScripts, bootstrapScript] = (0, _requiredscripts.getRequiredScripts)(buildManifest, // Why is assetPrefix optional on renderOpts? // @TODO make it default empty string on renderOpts and get rid of it from ctx assetPrefix, crossOrigin, subresourceIntegrityManifest, (0, _getassetquerystring.getAssetQueryString)(ctx, true), nonce, page); const { reactServerErrorsByDigest } = workStore; // We don't report errors during prerendering through our instrumentation hooks const reportErrors = !experimental.isRoutePPREnabled; function onHTMLRenderRSCError(err, silenceLog) { if (reportErrors) { return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'react-server-components'), silenceLog); } } const serverComponentsErrorHandler = (0, _createerrorhandler.createReactServerErrorHandler)(process.env.NODE_ENV === 'development', isBuildTimePrerendering, reactServerErrorsByDigest, onHTMLRenderRSCError); function onHTMLRenderSSRError(err) { if (reportErrors) { // We don't need to silence logs here. onHTMLRenderSSRError won't be // called at all if the error was logged before in the RSC error handler. const silenceLog = false; return onInstrumentationRequestError == null ? void 0 : onInstrumentationRequestError(err, req, createErrorContext(ctx, 'server-rendering'), silenceLog); } } const allCapturedErrors = []; const htmlRendererErrorHandler = (0, _createerrorhandler.createHTMLErrorHandler)(process.env.NODE_ENV === 'development', isBuildTimePrerendering, reactServerErrorsByDigest, allCapturedErrors, onHTMLRenderSSRError); let reactServerPrerenderResult = null; const setMetadataHeader = (name)=>{ metadata.headers ??= {}; metadata.headers[name] = res.getHeader(name); }; const setHeader = (name, value)=>{ res.setHeader(name, value); setMetadataHeader(name); return res; }; const appendHeader = (name, value)=>{ if (Array.isArray(value)) { value.forEach((item)=>{ res.appendHeader(name, item); }); } else { res.appendHeader(name, value); } setMetadataHeader(name); }; const selectStaleTime = (0, _staletime.createSelectStaleTime)(experimental); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); let prerenderStore = null; try { if (cacheComponents) { /** * cacheComponents with PPR * * The general approach is to render the RSC stream first allowing any cache reads to resolve. * Once we have settled all cache reads we restart the render and abort after a single Task. * * Unlike with the non PPR case we can't synchronously abort the render when a dynamic API is used * during the initial render because we need to ensure all caches can be filled as part of the initial Task * and a synchronous abort might prevent us from filling all caches. * * Once the render is complete we allow the SSR render to finish and use a combination of the postponed state * and the reactServerIsDynamic value to determine how to treat the resulting render */ // The prerender controller represents the lifetime of the prerender. It // will be aborted when a task is complete or a synchronously aborting API // is called. Notably, during prospective prerenders, this does not // actually terminate the prerender itself, which will continue until all // caches are filled. const initialServerPrerenderController = new AbortController(); // This controller is used to abort the React prerender. const initialServerReactController = new AbortController(); // This controller represents the lifetime of the React prerender. Its // signal can be used for any I/O operation to abort the I/O and/or to // reject, when prerendering aborts. This includes our own hanging // promises for accessing request data, and for fetch calls. It might be // replaced in the future by React.cacheSignal(). It's aborted after the // React controller, so that no pending I/O can register abort listeners // that are called before React's abort listener is called. This ensures // that pending I/O is not rejected too early when aborting the prerender. // Notably, during the prospective prerender, it is different from the // prerender controller because we don't want to end the React prerender // until all caches are filled. const initialServerRenderController = new AbortController(); // The cacheSignal helps us track whether caches are still filling or we are ready // to cut the render off. const cacheSignal = new _cachesignal.CacheSignal(); // Always start with a fresh prerender RDC so warmup can fill misses, // even when we have a prefilled render RDC to seed from. const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); let renderResumeDataCache = renderOpts.renderResumeDataCache ?? null; const initialServerPayloadPrerenderStore = { type: 'prerender', phase: 'render', rootParams, fallbackRouteParams, implicitTags, // While this render signal isn't going to be used to abort a React render while getting the RSC payload // various request data APIs bind to this controller to reject after completion. renderSignal: initialServerRenderController.signal, // When we generate the RSC payload we might abort this controller due to sync IO // but we don't actually care about sync IO in this phase so we use a throw away controller // that isn't connected to anything controller: new AbortController(), // During the initial prerender we need to track all cache reads to ensure // we render long enough to fill every cache it is possible to visit during // the final prerender. cacheSignal, dynamicTracking: null, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, // We don't track vary params during initial prerender, only the final one varyParamsAccumulator: null }; // We're not going to use the result of this render because the only time it could be used // is if it completes in a microtask and that's likely very rare for any non-trivial app const initialServerPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialServerPayloadPrerenderStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404 }); const initialServerPrerenderStore = prerenderStore = { type: 'prerender', phase: 'render', rootParams, fallbackRouteParams, implicitTags, renderSignal: initialServerRenderController.signal, controller: initialServerPrerenderController, // During the initial prerender we need to track all cache reads to ensure // we render long enough to fill every cache it is possible to visit during // the final prerender. cacheSignal, dynamicTracking: null, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, // We don't track vary params during initial prerender, only the final one varyParamsAccumulator: null }; const initialPrerenderOptions = { filterStackFrame, onError: (err)=>{ const digest = (0, _createerrorhandler.getDigestForWellKnownError)(err); if (digest) { return digest; } if ((0, _reactlargeshellerror.isReactLargeShellError)(err)) { // TODO: Aggregate console.error(err); return undefined; } if (initialServerPrerenderController.signal.aborted) { // The render aborted before this error was handled which indicates // the error is caused by unfinished components within the render return; } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } }, // We don't want to stop rendering until the cacheSignal is complete so we pass // a different signal to this render call than is used by dynamic APIs to signify // transitioning out of the prerender environment signal: initialServerReactController.signal }; const pendingInitialServerResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialServerPrerenderStore, (0, _streamops.getServerPrerender)(ComponentMod), initialServerPayload, clientModules, initialPrerenderOptions); // The listener to abort our own render controller must be added after // React has added its listener, to ensure that pending I/O is not // aborted/rejected too early. initialServerReactController.signal.addEventListener('abort', ()=>{ initialServerRenderController.abort(); initialServerPrerenderController.abort(); }, { once: true }); // Wait for all caches to be finished filling and for async imports to resolve (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); await cacheSignal.cacheReady(); initialServerReactController.abort(); // We don't need to continue the prerender process if we already // detected invalid dynamic usage in the initial prerender phase. if (workStore.invalidDynamicUsageError) { (0, _dynamicrendering.logDisallowedDynamicError)(workStore, workStore.invalidDynamicUsageError); throw new _staticgenerationbailout.StaticGenBailoutError(); } let initialServerResult; try { initialServerResult = await (0, _apprenderprerenderutils.createReactServerPrerenderResult)(pendingInitialServerResult); } catch (err) { if (initialServerReactController.signal.aborted || initialServerPrerenderController.signal.aborted) { // These are expected errors that might error the prerender. we ignore them. } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { // We don't normally log these errors because we are going to retry anyway but // it can be useful for debugging Next.js itself to get visibility here when needed (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } } if (initialServerResult) { const initialClientPrerenderController = new AbortController(); const initialClientReactController = new AbortController(); const initialClientRenderController = new AbortController(); const initialClientPrerenderStore = { type: 'prerender-client', phase: 'render', rootParams, fallbackRouteParams, implicitTags, renderSignal: initialClientRenderController.signal, controller: initialClientPrerenderController, // For HTML Generation the only cache tracked activity // is module loading, which has it's own cache signal cacheSignal: null, dynamicTracking: null, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, // Client prerenders don't track server param access varyParamsAccumulator: null }; const pendingInitialClientResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(initialClientPrerenderStore, _streamops.getClientPrerender, // eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: initialServerResult.asUnclosingStream(), reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { signal: initialClientReactController.signal, onError: (err)=>{ const digest = (0, _createerrorhandler.getDigestForWellKnownError)(err); if (digest) { return digest; } if ((0, _reactlargeshellerror.isReactLargeShellError)(err)) { // TODO: Aggregate console.error(err); return undefined; } if (initialClientReactController.signal.aborted) { // These are expected errors that might error the prerender. we ignore them. } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { // We don't normally log these errors because we are going to retry anyway but // it can be useful for debugging Next.js itself to get visibility here when needed (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } }, bootstrapScripts: [ bootstrapScript ] }); // The listener to abort our own render controller must be added after // React has added its listener, to ensure that pending I/O is not // aborted/rejected too early. initialClientReactController.signal.addEventListener('abort', ()=>{ initialClientRenderController.abort(); }, { once: true }); pendingInitialClientResult.catch((err)=>{ if (initialClientReactController.signal.aborted || (0, _dynamicrendering.isPrerenderInterruptedError)(err)) { // These are expected errors that might error the prerender. we ignore them. } else if (process.env.NEXT_DEBUG_BUILD || process.env.__NEXT_VERBOSE_LOGGING) { // We don't normally log these errors because we are going to retry anyway but // it can be useful for debugging Next.js itself to get visibility here when needed (0, _prospectiverenderutils.printDebugThrownValueForProspectiveRender)(err, workStore.route, _prospectiverenderutils.Phase.ProspectiveRender); } }); // This is mostly needed for dynamic `import()`s in client components. // Promises passed to client were already awaited above (assuming that they came from cached functions) (0, _trackmoduleloadingexternal.trackPendingModules)(cacheSignal); await cacheSignal.cacheReady(); initialClientReactController.abort(); } if (renderOpts.renderResumeDataCache) { // Swap to the warmed cache so the final render uses entries produced during warmup. renderResumeDataCache = (0, _resumedatacache.createRenderResumeDataCache)(prerenderResumeDataCache); } const finalServerReactController = new AbortController(); const finalServerRenderController = new AbortController(); const varyParamsAccumulator = (0, _varyparams.createResponseVaryParamsAccumulator)(); const finalServerPayloadPrerenderStore = { type: 'prerender', phase: 'render', rootParams, fallbackRouteParams, implicitTags, // While this render signal isn't going to be used to abort a React render while getting the RSC payload // various request data APIs bind to this controller to reject after completion. renderSignal: finalServerRenderController.signal, // When we generate the RSC payload we might abort this controller due to sync IO // but we don't actually care about sync IO in this phase so we use a throw away controller // that isn't connected to anything controller: new AbortController(), // All caches we could read must already be filled so no tracking is necessary cacheSignal: null, dynamicTracking: null, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, varyParamsAccumulator }; const finalAttemptRSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalServerPayloadPrerenderStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404 }); let staleTimeIterable; if (cachedNavigations) { staleTimeIterable = new _staletime.StaleTimeIterable(); finalAttemptRSCPayload.s = staleTimeIterable; } const serverDynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(isDebugDynamicAccesses); let serverIsDynamic = false; const finalServerPrerenderStore = prerenderStore = { type: 'prerender', phase: 'render', rootParams, fallbackRouteParams, implicitTags, renderSignal: finalServerRenderController.signal, controller: finalServerReactController, // All caches we could read must already be filled so no tracking is necessary cacheSignal: null, dynamicTracking: serverDynamicTracking, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, varyParamsAccumulator }; if (staleTimeIterable !== undefined) { (0, _staletime.trackStaleTime)(finalServerPrerenderStore, staleTimeIterable, selectStaleTime); } let prerenderIsPending = true; const finalRSCPrerenderOptions = { filterStackFrame, onError: (err)=>{ return serverComponentsErrorHandler(err); }, signal: finalServerReactController.signal }; const finalRSCAbortCallback = async ()=>{ // Now that the prerendering is complete, we know the final stale // time and vary params. Close the stale time iterable and resolve // the vary params thenable so Flight can serialize their values // into the stream. The timing here is important: both were // included in the Flight payload, but they can only be serialized // at the very end, after all the components have finished. // // We resolve these directly here instead of reading from the work // unit store because this callback runs in a separate task (via // setTimeout) and may not have access to the async storage context. const pendingFinishes = [ (0, _varyparams.finishAccumulatingVaryParams)(varyParamsAccumulator) ]; if (staleTimeIterable !== undefined) { pendingFinishes.push((0, _staletime.finishStaleTimeTracking)(staleTimeIterable)); } await Promise.all(pendingFinishes); if (finalServerReactController.signal.aborted) { // If the server controller is already aborted we must have called something // that required aborting the prerender synchronously such as with new Date() serverIsDynamic = true; return; } if (prerenderIsPending) { // If prerenderIsPending then we have blocked for longer than a Task and we assume // there is something unfinished. serverIsDynamic = true; } finalServerReactController.abort(); }; const finalRSCPrerenderFn = async ()=>{ const pendingPrerenderResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(// The store to scope finalServerPrerenderStore, // The function to run (0, _streamops.getServerPrerender)(ComponentMod), // ... the arguments for the function to run finalAttemptRSCPayload, clientModules, finalRSCPrerenderOptions); // The listener to abort our own render controller must be added // after React has added its listener, to ensure that pending I/O // is not aborted/rejected too early. finalServerReactController.signal.addEventListener('abort', ()=>{ finalServerRenderController.abort(); }, { once: true }); const prerenderResult = await pendingPrerenderResult; prerenderIsPending = false; return prerenderResult; }; const reactServerResult = reactServerPrerenderResult = await (0, _apprenderprerenderutils.createReactServerPrerenderResult)((0, _apprenderrenderutils.runInSequentialTasks)(finalRSCPrerenderFn, finalRSCAbortCallback)); const clientDynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(isDebugDynamicAccesses); const finalClientReactController = new AbortController(); const finalClientRenderController = new AbortController(); const finalClientPrerenderStore = { type: 'prerender-client', phase: 'render', rootParams, fallbackRouteParams, implicitTags, renderSignal: finalClientRenderController.signal, controller: finalClientReactController, // No APIs require a cacheSignal through the workUnitStore during the HTML prerender cacheSignal: null, dynamicTracking: clientDynamicTracking, allowEmptyStaticShell, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache, renderResumeDataCache, hmrRefreshHash: undefined, // Client prerenders don't track server param access varyParamsAccumulator: null }; let dynamicValidation = (0, _dynamicrendering.createDynamicValidationState)(); const finalClientOnHeaders = (0, _streamops.createOnHeadersCallback)(appendHeader); let { prelude: unprocessedPrelude, postponed } = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ const pendingFinalClientResult = _workunitasyncstorageexternal.workUnitAsyncStorage.run(finalClientPrerenderStore, _streamops.getClientPrerender, // eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: reactServerResult.asUnclosingStream(), reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { signal: finalClientReactController.signal, onError: (err, errorInfo)=>{ if ((0, _dynamicrendering.isPrerenderInterruptedError)(err) || finalClientReactController.signal.aborted) { const componentStack = errorInfo.componentStack; if (typeof componentStack === 'string') { (0, _dynamicrendering.trackAllowedDynamicAccess)(workStore, componentStack, dynamicValidation, clientDynamicTracking); } return; } return htmlRendererErrorHandler(err, errorInfo); }, onHeaders: finalClientOnHeaders, maxHeadersLength: reactMaxHeadersLength, bootstrapScripts: [ bootstrapScript ] }); // The listener to abort our own render controller must be added // after React has added its listener, to ensure that pending I/O is // not aborted/rejected too early. finalClientReactController.signal.addEventListener('abort', ()=>{ finalClientRenderController.abort(); }, { once: true }); return pendingFinalClientResult; }, ()=>{ finalClientReactController.abort(); }); const { prelude, preludeIsEmpty } = await (0, _streamops.processPrelude)(unprocessedPrelude); // If we've disabled throwing on empty static shell, then we don't need to // track any dynamic access that occurs above the suspense boundary because // we'll do so in the route shell. if (!allowEmptyStaticShell) { (0, _dynamicrendering.throwIfDisallowedDynamic)(workStore, preludeIsEmpty ? _dynamicrendering.PreludeState.Empty : _dynamicrendering.PreludeState.Full, dynamicValidation, serverDynamicTracking); } const getServerInsertedHTML = (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: allCapturedErrors, basePath, tracingMetadata: tracingMetadata }); metadata.flightData = await (0, _streamops.streamToBuffer)(cachedNavigations ? prependIsPartialByte(reactServerResult.asStream(), serverIsDynamic) : reactServerResult.asStream()); // collectSegmentData needs the raw flight data without the marker byte. const flightData = cachedNavigations ? metadata.flightData.subarray(1) : metadata.flightData; await collectSegmentData(flightData, finalServerPrerenderStore, ComponentMod, renderOpts, ctx.pagePath, metadata); if (serverIsDynamic) { // Dynamic case // We will always need to perform a "resume" render of some kind when this route is accessed // because the RSC data itself is dynamic. We determine if there are any HTML holes or not // but generally this is a "partial" prerender in that there will be a per-request compute // concatenated to the static shell. if (postponed != null) { // Dynamic HTML case metadata.postponed = await (0, _postponedstate.getDynamicHTMLPostponedState)(postponed, preludeIsEmpty ? _postponedstate.DynamicHTMLPreludeState.Empty : _postponedstate.DynamicHTMLPreludeState.Full, fallbackRouteParams, prerenderResumeDataCache, cacheComponents); } else { // Dynamic Data case metadata.postponed = await (0, _postponedstate.getDynamicDataPostponedState)(prerenderResumeDataCache, cacheComponents); } reactServerResult.consume(); const continueDynamicPrerenderOpts = { getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }; return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: await (0, _streamops.continueDynamicPrerender)(prelude, continueDynamicPrerenderOpts), dynamicAccess: (0, _dynamicrendering.consumeDynamicAccess)(serverDynamicTracking, clientDynamicTracking), // TODO: Should this include the SSR pass? collectedRevalidate: finalServerPrerenderStore.revalidate, collectedExpire: finalServerPrerenderStore.expire, collectedStale: selectStaleTime(finalServerPrerenderStore.stale), collectedTags: finalServerPrerenderStore.tags, renderResumeDataCache: (0, _resumedatacache.createRenderResumeDataCache)(prerenderResumeDataCache) }; } else { // Static case // We will not perform resumption per request. The result can be served statically to the requestor // and if there was anything dynamic it will only be rendered in the browser. if (workStore.forceDynamic) { throw Object.defineProperty(new _staticgenerationbailout.StaticGenBailoutError('Invariant: a Page with `dynamic = "force-dynamic"` did not trigger the dynamic pathway. This is a bug in Next.js'), "__NEXT_ERROR_CODE", { value: "E598", enumerable: false, configurable: true }); } let htmlStream = prelude; if (postponed != null) { // We postponed but nothing dynamic was used. We resume the render now and immediately abort it // so we can set all the postponed boundaries to client render mode before we store the HTML response const foreverStream = (0, _streamops.createPendingStream)(); const resumePrelude = await (0, _streamops.resumeAndAbort)(// eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: foreverStream, reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: ()=>{}, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), JSON.parse(JSON.stringify(postponed)), { signal: (0, _dynamicrendering.createRenderInBrowserAbortSignal)(), onError: htmlRendererErrorHandler, nonce }); // First we write everything from the prerender, then we write everything from the aborted resume render htmlStream = (0, _streamops.chainStreams)(prelude, resumePrelude); } let finalStream; const hasFallbackRouteParams = fallbackRouteParams && fallbackRouteParams.size > 0; if (hasFallbackRouteParams) { // This is a "static fallback" prerender: although the page didn't // access any runtime params in a Server Component, it may have // accessed a runtime param in a client segment. // // TODO: If there were no client segments, we can use the fully static // path instead. // // Rather than use a dynamic server resume to fill in the params, // we can rely on the client to parse the params from the URL and use // that to hydrate the page. // // Send an empty InitialRSCPayload to the server component renderer // The data will be fetched by the client instead. // TODO: In the future, rather than defer the entire hydration payload // to be fetched by the client, we should only defer the client // segments, since those are the only ones whose data is not complete. const emptyReactServerResult = await (0, _apprenderprerenderutils.createReactServerPrerenderResultFromRender)((0, _streamops.renderToFlightStream)(ComponentMod, [], clientModules, { filterStackFrame, onError: serverComponentsErrorHandler })); finalStream = await (0, _streamops.continueStaticFallbackPrerender)(htmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(emptyReactServerResult.consumeAsStream(), nonce, formState), getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }); } else { // Normal static prerender case, no fallback param handling needed finalStream = await (0, _streamops.continueStaticPrerender)(htmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(reactServerResult.consumeAsStream(), nonce, formState), getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }); } return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: finalStream, dynamicAccess: (0, _dynamicrendering.consumeDynamicAccess)(serverDynamicTracking, clientDynamicTracking), // TODO: Should this include the SSR pass? collectedRevalidate: finalServerPrerenderStore.revalidate, collectedExpire: finalServerPrerenderStore.expire, collectedStale: selectStaleTime(finalServerPrerenderStore.stale), collectedTags: finalServerPrerenderStore.tags, renderResumeDataCache: (0, _resumedatacache.createRenderResumeDataCache)(prerenderResumeDataCache) }; } } else if (experimental.isRoutePPREnabled) { // We're statically generating with PPR and need to do dynamic tracking let dynamicTracking = (0, _dynamicrendering.createDynamicTrackingState)(isDebugDynamicAccesses); const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); const reactServerPrerenderStore = prerenderStore = { type: 'prerender-ppr', phase: 'render', rootParams, fallbackRouteParams, implicitTags, dynamicTracking, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache }; const RSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(reactServerPrerenderStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404 }); let reactServerResult; reactServerResult = reactServerPrerenderResult = await (0, _apprenderprerenderutils.createReactServerPrerenderResultFromRender)(_workunitasyncstorageexternal.workUnitAsyncStorage.run(reactServerPrerenderStore, _streamops.renderToFlightStream, ComponentMod, RSCPayload, clientModules, { filterStackFrame, onError: serverComponentsErrorHandler })); const ssrPrerenderStore = { type: 'prerender-ppr', phase: 'render', rootParams, fallbackRouteParams, implicitTags, dynamicTracking, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ], prerenderResumeDataCache }; const pprOnHeaders = (0, _streamops.createOnHeadersCallback)(appendHeader); const { prelude: unprocessedPrelude, postponed } = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(ssrPrerenderStore, _streamops.getClientPrerender, // eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: reactServerResult.asUnclosingStream(), reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { onError: htmlRendererErrorHandler, onHeaders: pprOnHeaders, maxHeadersLength: reactMaxHeadersLength, bootstrapScripts: [ bootstrapScript ] }); const getServerInsertedHTML = (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: allCapturedErrors, basePath, tracingMetadata: tracingMetadata }); // After awaiting here we've waited for the entire RSC render to complete. Crucially this means // that when we detect whether we've used dynamic APIs below we know we'll have picked up even // parts of the React Server render that might not be used in the SSR render. const flightData = await (0, _streamops.streamToBuffer)(reactServerResult.asStream()); if (shouldGenerateStaticFlightData(workStore)) { metadata.flightData = flightData; await collectSegmentData(flightData, ssrPrerenderStore, ComponentMod, renderOpts, ctx.pagePath, metadata); } const { prelude, preludeIsEmpty } = await (0, _streamops.processPrelude)(unprocessedPrelude); /** * When prerendering there are three outcomes to consider * * Dynamic HTML: The prerender has dynamic holes (caused by using Next.js Dynamic Rendering APIs) * We will need to resume this result when requests are handled and we don't include * any server inserted HTML or inlined flight data in the static HTML * * Dynamic Data: The prerender has no dynamic holes but dynamic APIs were used. We will not * resume this render when requests are handled but we will generate new inlined * flight data since it is dynamic and differences may end up reconciling on the client * * Static: The prerender has no dynamic holes and no dynamic APIs were used. We statically encode * all server inserted HTML and flight data */ // First we check if we have any dynamic holes in our HTML prerender if ((0, _dynamicrendering.accessedDynamicData)(dynamicTracking.dynamicAccesses)) { if (postponed != null) { // Dynamic HTML case. metadata.postponed = await (0, _postponedstate.getDynamicHTMLPostponedState)(postponed, preludeIsEmpty ? _postponedstate.DynamicHTMLPreludeState.Empty : _postponedstate.DynamicHTMLPreludeState.Full, fallbackRouteParams, prerenderResumeDataCache, cacheComponents); } else { // Dynamic Data case. metadata.postponed = await (0, _postponedstate.getDynamicDataPostponedState)(prerenderResumeDataCache, cacheComponents); } // Regardless of whether this is the Dynamic HTML or Dynamic Data case we need to ensure we include // server inserted html in the static response because the html that is part of the prerender may depend on it // It is possible in the set of stream transforms for Dynamic HTML vs Dynamic Data may differ but currently both states // require the same set so we unify the code path here reactServerResult.consume(); const pprDynamicOpts = { getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }; return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: await (0, _streamops.continueDynamicPrerender)(prelude, pprDynamicOpts), dynamicAccess: dynamicTracking.dynamicAccesses, // TODO: Should this include the SSR pass? collectedRevalidate: reactServerPrerenderStore.revalidate, collectedExpire: reactServerPrerenderStore.expire, collectedStale: selectStaleTime(reactServerPrerenderStore.stale), collectedTags: reactServerPrerenderStore.tags }; } else if (fallbackRouteParams && fallbackRouteParams.size > 0) { // Rendering the fallback case. metadata.postponed = await (0, _postponedstate.getDynamicDataPostponedState)(prerenderResumeDataCache, cacheComponents); const pprFallbackDynamicOpts = { getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }; return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: await (0, _streamops.continueDynamicPrerender)(prelude, pprFallbackDynamicOpts), dynamicAccess: dynamicTracking.dynamicAccesses, // TODO: Should this include the SSR pass? collectedRevalidate: reactServerPrerenderStore.revalidate, collectedExpire: reactServerPrerenderStore.expire, collectedStale: selectStaleTime(reactServerPrerenderStore.stale), collectedTags: reactServerPrerenderStore.tags }; } else { // Static case // We still have not used any dynamic APIs. At this point we can produce an entirely static prerender response if (workStore.forceDynamic) { throw Object.defineProperty(new _staticgenerationbailout.StaticGenBailoutError('Invariant: a Page with `dynamic = "force-dynamic"` did not trigger the dynamic pathway. This is a bug in Next.js'), "__NEXT_ERROR_CODE", { value: "E598", enumerable: false, configurable: true }); } let htmlStream = prelude; if (postponed != null) { // We postponed but nothing dynamic was used. We resume the render now and immediately abort it // so we can set all the postponed boundaries to client render mode before we store the HTML response const foreverStream = (0, _streamops.createPendingStream)(); const resumePrelude = await (0, _streamops.resumeAndAbort)(// eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: foreverStream, reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: ()=>{}, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), JSON.parse(JSON.stringify(postponed)), { signal: (0, _dynamicrendering.createRenderInBrowserAbortSignal)(), onError: htmlRendererErrorHandler, nonce }); // First we write everything from the prerender, then we write everything from the aborted resume render htmlStream = (0, _streamops.chainStreams)(prelude, resumePrelude); } return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: await (0, _streamops.continueStaticPrerender)(htmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(reactServerResult.consumeAsStream(), nonce, formState), getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }), dynamicAccess: dynamicTracking.dynamicAccesses, // TODO: Should this include the SSR pass? collectedRevalidate: reactServerPrerenderStore.revalidate, collectedExpire: reactServerPrerenderStore.expire, collectedStale: selectStaleTime(reactServerPrerenderStore.stale), collectedTags: reactServerPrerenderStore.tags }; } } else { const prerenderLegacyStore = prerenderStore = { type: 'prerender-legacy', phase: 'render', rootParams, implicitTags, revalidate: _constants1.INFINITE_CACHE, expire: _constants1.INFINITE_CACHE, stale: _constants1.INFINITE_CACHE, tags: [ ...implicitTags.tags ] }; // This is a regular static generation. We don't do dynamic tracking because we rely on // the old-school dynamic error handling to bail out of static generation const RSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderLegacyStore, getRSCPayload, tree, ctx, { is404: res.statusCode === 404 }); let reactServerResult; reactServerResult = reactServerPrerenderResult = await (0, _apprenderprerenderutils.createReactServerPrerenderResultFromRender)(_workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderLegacyStore, _streamops.renderToFlightStream, ComponentMod, RSCPayload, clientModules, { filterStackFrame, onError: serverComponentsErrorHandler })); const { stream: htmlStream } = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderLegacyStore, _streamops.renderToFizzStream, // eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(App, { reactServerStream: reactServerResult.asUnclosingStream(), reactDebugStream: undefined, debugEndTime: undefined, preinitScripts: preinitScripts, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, nonce: nonce, images: ctx.renderOpts.images }), { onError: htmlRendererErrorHandler, nonce, bootstrapScripts: [ bootstrapScript ] }); if (shouldGenerateStaticFlightData(workStore)) { const flightData = await (0, _streamops.streamToBuffer)(reactServerResult.asStream()); metadata.flightData = flightData; await collectSegmentData(flightData, prerenderLegacyStore, ComponentMod, renderOpts, ctx.pagePath, metadata); } const getServerInsertedHTML = (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: allCapturedErrors, basePath, tracingMetadata: tracingMetadata }); return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: await (0, _streamops.continueFizzStream)(htmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(reactServerResult.consumeAsStream(), nonce, formState), isStaticGeneration: true, getServerInsertedHTML, getServerInsertedMetadata, deploymentId: ctx.sharedContext.deploymentId }), // TODO: Should this include the SSR pass? collectedRevalidate: prerenderLegacyStore.revalidate, collectedExpire: prerenderLegacyStore.expire, collectedStale: selectStaleTime(prerenderLegacyStore.stale), collectedTags: prerenderLegacyStore.tags }; } } catch (err) { if ((0, _staticgenerationbailout.isStaticGenBailoutError)(err) || typeof err === 'object' && err !== null && 'message' in err && typeof err.message === 'string' && err.message.includes('https://nextjs.org/docs/advanced-features/static-html-export')) { // Ensure that "next dev" prints the red error overlay throw err; } // If this is a static generation error, we need to throw it so that it // can be handled by the caller if we're in static generation mode. if ((0, _hooksservercontext.isDynamicServerError)(err)) { throw err; } // If a bailout made it to this point, it means it wasn't wrapped inside // a suspense boundary. const shouldBailoutToCSR = (0, _bailouttocsr.isBailoutToCSRError)(err); if (shouldBailoutToCSR) { const stack = (0, _formatservererror.getStackWithoutErrorMessage)(err); (0, _log.error)(`${err.reason} should be wrapped in a suspense boundary at page "${pagePath}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout\n${stack}`); throw err; } // If we errored when we did not have an RSC stream to read from. This is // not just a render error, we need to throw early. if (reactServerPrerenderResult === null) { throw err; } let errorType; if ((0, _httpaccessfallback.isHTTPAccessFallbackError)(err)) { res.statusCode = (0, _httpaccessfallback.getAccessFallbackHTTPStatus)(err); metadata.statusCode = res.statusCode; errorType = (0, _httpaccessfallback.getAccessFallbackErrorTypeByStatus)(res.statusCode); } else if ((0, _redirecterror.isRedirectError)(err)) { errorType = 'redirect'; res.statusCode = (0, _redirect.getRedirectStatusCodeFromError)(err); metadata.statusCode = res.statusCode; const redirectUrl = (0, _addpathprefix.addPathPrefix)((0, _redirect.getURLFromRedirectError)(err), basePath); setHeader('location', redirectUrl); } else if (!shouldBailoutToCSR) { res.statusCode = 500; metadata.statusCode = res.statusCode; } const [errorPreinitScripts, errorBootstrapScript] = (0, _requiredscripts.getRequiredScripts)(buildManifest, assetPrefix, crossOrigin, subresourceIntegrityManifest, (0, _getassetquerystring.getAssetQueryString)(ctx, false), nonce, '/_not-found/page'); const prerenderLegacyStore = prerenderStore = { type: 'prerender-legacy', phase: 'render', rootParams, implicitTags: implicitTags, revalidate: typeof (prerenderStore == null ? void 0 : prerenderStore.revalidate) !== 'undefined' ? prerenderStore.revalidate : _constants1.INFINITE_CACHE, expire: typeof (prerenderStore == null ? void 0 : prerenderStore.expire) !== 'undefined' ? prerenderStore.expire : _constants1.INFINITE_CACHE, stale: typeof (prerenderStore == null ? void 0 : prerenderStore.stale) !== 'undefined' ? prerenderStore.stale : _constants1.INFINITE_CACHE, tags: [ ...(prerenderStore == null ? void 0 : prerenderStore.tags) || implicitTags.tags ] }; const errorRSCPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderLegacyStore, getErrorRSCPayload, tree, ctx, reactServerErrorsByDigest.has(err.digest) ? undefined : err, errorType); const errorServerStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderLegacyStore, _streamops.renderToFlightStream, ComponentMod, errorRSCPayload, clientModules, { filterStackFrame, onError: serverComponentsErrorHandler }); try { const { stream: errorHtmlStream } = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(prerenderLegacyStore, _streamops.renderToFizzStream, // eslint-disable-next-line @next/internal/no-ambiguous-jsx /*#__PURE__*/ (0, _jsxruntime.jsx)(ErrorApp, { reactServerStream: errorServerStream, ServerInsertedHTMLProvider: ServerInsertedHTMLProvider, preinitScripts: errorPreinitScripts, nonce: nonce, images: ctx.renderOpts.images }), { nonce, bootstrapScripts: [ errorBootstrapScript ], formState }); if (shouldGenerateStaticFlightData(workStore)) { const flightData = await (0, _streamops.streamToBuffer)(reactServerPrerenderResult.asStream()); metadata.flightData = flightData; await collectSegmentData(flightData, prerenderLegacyStore, ComponentMod, renderOpts, ctx.pagePath, metadata); } // This is intentionally using the readable datastream from the main // render rather than the flight data from the error page render const flightStream = reactServerPrerenderResult.consumeAsStream(); return { digestErrorsMap: reactServerErrorsByDigest, ssrErrors: allCapturedErrors, stream: await (0, _streamops.continueFizzStream)(errorHtmlStream, { inlinedDataStream: (0, _streamops.createInlinedDataStream)(flightStream, nonce, formState), isStaticGeneration: true, getServerInsertedHTML: (0, _makegetserverinsertedhtml.makeGetServerInsertedHTML)({ polyfills, renderServerInsertedHTML, serverCapturedErrors: [], basePath, tracingMetadata: tracingMetadata }), getServerInsertedMetadata, validateRootLayout: !!process.env.__NEXT_DEV_SERVER, deploymentId: ctx.sharedContext.deploymentId }), dynamicAccess: null, collectedRevalidate: prerenderStore !== null ? prerenderStore.revalidate : _constants1.INFINITE_CACHE, collectedExpire: prerenderStore !== null ? prerenderStore.expire : _constants1.INFINITE_CACHE, collectedStale: selectStaleTime(prerenderStore !== null ? prerenderStore.stale : _constants1.INFINITE_CACHE), collectedTags: prerenderStore !== null ? prerenderStore.tags : null }; } catch (finalErr) { if (process.env.__NEXT_DEV_SERVER && (0, _httpaccessfallback.isHTTPAccessFallbackError)(finalErr)) { const { bailOnRootNotFound } = require('../../client/components/dev-root-http-access-fallback-boundary'); bailOnRootNotFound(); } throw finalErr; } } } const getGlobalErrorStyles = async (tree, ctx)=>{ const globalErrorModule = (0, _parseloadertree.parseLoaderTree)(tree).modules['global-error']; if (!globalErrorModule) { throw Object.defineProperty(new Error('Invariant: global-error module is required but not found in loader tree'), "__NEXT_ERROR_CODE", { value: "E983", enumerable: false, configurable: true }); } const { componentMod: { createElement } } = ctx; // Get the GlobalError component and styles from the loader tree const [GlobalErrorComponent, styles] = await (0, _createcomponentstylesandscripts.createComponentStylesAndScripts)({ ctx, filePath: globalErrorModule[1], getComponent: globalErrorModule[0], injectedCSS: new Set(), injectedJS: new Set() }); let globalErrorStyles = styles; if (process.env.__NEXT_DEV_SERVER) { const dir = (process.env.NEXT_RUNTIME === 'edge' ? process.env.__NEXT_EDGE_PROJECT_DIR : ctx.renderOpts.dir) || ''; const globalErrorModulePath = (0, _segmentexplorerpath.normalizeConventionFilePath)(dir, globalErrorModule[1]); if (globalErrorModulePath) { const SegmentViewNode = ctx.componentMod.SegmentViewNode; globalErrorStyles = // This will be rendered next to GlobalError component under ErrorBoundary, // it requires a key to avoid React warning about duplicate keys. createElement(SegmentViewNode, { key: 'ge-svn', type: 'global-error', pagePath: globalErrorModulePath }, globalErrorStyles); } } return { GlobalError: GlobalErrorComponent, styles: globalErrorStyles }; }; async function collectSegmentData(fullPageDataBuffer, prerenderStore, ComponentMod, renderOpts, pagePath, metadata) { // Per-segment prefetch data // // All of the segments for a page are generated simultaneously, including // during revalidations. This is to ensure consistency, because it's // possible for a mismatch between a layout and page segment can cause the // client to error during rendering. We want to preserve the ability of the // client to recover from such a mismatch by re-requesting all the segments // to get a consistent view of the page. // // For performance, we reuse the Flight output that was created when // generating the initial page HTML. The Flight stream for the whole page is // decomposed into a separate stream per segment. const { clientModules, edgeRscModuleMapping, rscModuleMapping } = (0, _manifestssingleton.getClientReferenceManifest)(); // Manifest passed to the Flight client for reading the full-page Flight // stream. Based off similar code in use-cache-wrapper.ts. const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'; const serverConsumerManifest = { // moduleLoading must be null because we don't want to trigger preloads of ClientReferences // to be added to the consumer. Instead, we'll wait for any ClientReference to be emitted // which themselves will handle the preloading. moduleLoading: null, moduleMap: isEdgeRuntime ? edgeRscModuleMapping : rscModuleMapping, serverModuleMap: (0, _manifestssingleton.getServerModuleMap)() }; const selectStaleTime = (0, _staletime.createSelectStaleTime)(renderOpts.experimental); const staleTime = selectStaleTime(prerenderStore.stale); // Resolve prefetch hints. At runtime (next start / ISR), the precomputed // hints are already loaded from the prefetch-hints.json manifest. During // build, compute them by measuring segment gzip sizes and write them to // metadata so the build pipeline can persist them to the manifest. let hints; const prefetchInlining = renderOpts.experimental.prefetchInlining; if (!prefetchInlining) { hints = null; } else if (renderOpts.isBuildTimePrerendering) { // Build time: compute fresh hints and store in metadata for the manifest. hints = await ComponentMod.collectPrefetchHints(fullPageDataBuffer, staleTime, clientModules, serverConsumerManifest, prefetchInlining.maxSize, prefetchInlining.maxBundleSize); metadata.prefetchHints = hints; } else { var _renderOpts_prefetchHints; // Runtime: use hints from the manifest. Never compute fresh hints // during ISR/revalidation. hints = ((_renderOpts_prefetchHints = renderOpts.prefetchHints) == null ? void 0 : _renderOpts_prefetchHints[pagePath]) ?? null; } // Pass the resolved hints so collectSegmentData can union them into // the TreePrefetch. During the initial build the FlightRouterState in // the buffer doesn't have inlining hints yet (they were just computed // above), so we need to merge them in here. At runtime/ISR the hints // are already embedded in the FlightRouterState, so this is null. metadata.segmentData = await ComponentMod.collectSegmentData(renderOpts.cacheComponents, fullPageDataBuffer, staleTime, clientModules, serverConsumerManifest, Boolean(renderOpts.experimental.prefetchInlining), hints); } function isBypassingCachesInDev(requestStore) { return !!process.env.__NEXT_DEV_SERVER && requestStore.headers.get('cache-control') === 'no-cache'; } function WarnForBypassCachesInDev({ route }) { (0, _warnonce.warnOnce)(`Route ${route} is rendering with server caches disabled. For this navigation, Component Metadata in React DevTools will not accurately reflect what is statically prerenderable and runtime prefetchable. See more info here: https://nextjs.org/docs/messages/cache-bypass-in-dev`); return null; } function nodeStreamFromReadableStream(stream) { if (process.env.NEXT_RUNTIME === 'edge') { throw Object.defineProperty(new _invarianterror.InvariantError('nodeStreamFromReadableStream cannot be used in the edge runtime'), "__NEXT_ERROR_CODE", { value: "E944", enumerable: false, configurable: true }); } else { const reader = stream.getReader(); const { Readable } = require('node:stream'); return new Readable({ read () { reader.read().then(({ done, value })=>{ if (done) { this.push(null); } else { this.push(value); } }).catch((err)=>this.destroy(err)); } }); } } //# sourceMappingURL=app-render.js.map