UNPKG

next

Version:

The React Framework

867 lines 371 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { PrefetchingMode: null, renderToHTMLOrFlight: null, runValidationInDevFromSnapshot: null, toValidationRenderContext: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { PrefetchingMode: function() { return PrefetchingMode; }, renderToHTMLOrFlight: function() { return renderToHTMLOrFlight; }, runValidationInDevFromSnapshot: function() { return runValidationInDevFromSnapshot; }, toValidationRenderContext: function() { return toValidationRenderContext; } }); const _jsxruntime = require("react/jsx-runtime"); const _approutertypes = require("../../shared/lib/app-router-types"); const _workasyncstorageexternal = require("../app-render/work-async-storage.external"); const _getpagefiles = require("../get-page-files"); const _entryconstants = require("../../shared/lib/entry-constants"); const _react = /*#__PURE__*/ _interop_require_wildcard(require("react")); const _renderresult = /*#__PURE__*/ _interop_require_default(require("../render-result")); const _streamops = require("./stream-ops"); const _instanttestbootstrap = require("./instant-test-bootstrap"); 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 _isrscrequest = require("../lib/is-rsc-request"); const _workstore = require("../async-storage/work-store"); const _devvalidationevents = require("./dev-validation-events"); const _asynclocalstorage = require("./async-local-storage"); const _devvalidationworkerglobals = require("./dev-validation-worker-globals"); const _devvalidationworkersnapshot = require("./dev-validation-worker-snapshot"); 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 _requestinsightsidentity = require("../lib/trace/request-insights-identity"); const _tracer = require("../lib/trace/tracer"); const _localspanrecorder = require("../lib/trace/local-span-recorder"); const _requestinsights = require("../lib/trace/request-insights"); 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 _headers = require("../web/spec-extension/adapters/headers"); 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 _blockingroutemessages = require("./blocking-route-messages"); const _clientcomponentrendererlogger = require("../client-component-renderer-logger"); const _helpers = require("../base-http/helpers"); const _waitforresponse = require("./wait-for-response"); const _devvalidationscheduler = require("./dev-validation-scheduler"); const _nextrequest = require("../web/spec-extension/adapters/next-request"); 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"); const _promisewithresolvers = require("../../shared/lib/promise-with-resolvers"); const _dynamicrenderingutils = require("../dynamic-rendering-utils"); const _paramsutils = require("../lib/params-utils"); 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) { const isRSCRequest = (0, _isrscrequest.isRSCRequestHeader)(headers[_approuterheaders.RSC_HEADER]); // runtime prefetch requests are *not* treated as prefetch requests // (TODO: this is confusing, we should refactor this to express this better) const isPrefetchRequest = isRSCRequest && headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '1'; const isAppShellPrefetchRequest = isRSCRequest && headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '3'; // App Shell prefetches are a subtype of runtime prefetch — same code path, // but with less resolved content (omitting link data) const isRuntimePrefetchRequest = isRSCRequest && (headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '2' || isAppShellPrefetchRequest); const isHmrRefresh = headers[_approuterheaders.NEXT_HMR_REFRESH_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 = isRSCRequest && 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, isAppShellPrefetchRequest, 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 value1 = pageMod.unstable_dynamicStaleTime; result = result !== null ? Math.min(result, value1) : value1; } } 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 = []; const requestStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore(); // 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 && !((requestStore == null ? void 0 : requestStore.type) === 'request' && isBypassingCachesInDev(requestStore, workStore)) && !(options == null ? void 0 : options.actionResult) && // Only for navigations await (0, _instantconfig.anySegmentNeedsInstantValidationInDev)(loaderTree); const { Viewport, Metadata, MetadataOutlet } = createMetadataComponents({ tree: loaderTree, parsedQuery: query, pathname: url.pathname, metadataContext: (0, _metadatacontext.createMetadataContext)(ctx.renderOpts), interpolatedParams: ctx.interpolatedParams, serveStreamingMetadata }); 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.getMetadataVaryParamsAccumulator)(), r: (0, _varyparams.getRootParamsVaryParamsAccumulator)() ?? undefined }); 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.shellByteLengthPromise) !== undefined) { baseResponse.a = options.shellByteLengthPromise; } if ((options == null ? void 0 : options.shellUsedSessionDataPromise) !== undefined) { baseResponse.u = options.shellUsedSessionDataPromise; } 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); // With Server Components HMR cancellation enabled, a superseded HMR refresh // aborts its own client fetch, which closes this response. We use that // response-close to abort the discarded render. This is the // non-Cache-Components dev RSC path; unlike the Cache Components staged path // it has no detached validation, so the render is the only work to cancel. const requestAbortSignal = process.env.__NEXT_DEV_SERVER && renderOpts.experimental.serverComponentsHmrCancellation === true && requestStore.isHmrRefresh === true && (0, _helpers.isNodeNextResponse)(ctx.res) ? (0, _nextrequest.signalFromNodeResponse)(ctx.res.originalResponse) : undefined; if (process.env.__NEXT_USE_NODE_STREAMS) { const debugChannel = setReactDebugChannel && (0, _debugchannelserver.createNodeDebugChannel)(); if (debugChannel) { setReactDebugChannel(debugChannel.clientSide, htmlRequestId, requestId); } const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const rscPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, generateDynamicRSCPayload, ctx, options); const flightStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToNodeFlightStream, ctx.componentMod, rscPayload, clientModules, { onError, temporaryReferences: options == null ? void 0 : options.temporaryReferences, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide, signal: requestAbortSignal }); return new _flightrenderresult.FlightRenderResult(flightStream, { fetchMetrics: workStore.fetchMetrics }, options == null ? void 0 : options.waitUntil); } else { const debugChannel = setReactDebugChannel && (0, _debugchannelserver.createWebDebugChannel)(); if (debugChannel) { setReactDebugChannel(debugChannel.clientSide, htmlRequestId, requestId); } const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const rscPayload = await _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, generateDynamicRSCPayload, ctx, options); const flightStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToWebFlightStream, ctx.componentMod, rscPayload, clientModules, { onError, temporaryReferences: options == null ? void 0 : options.temporaryReferences, filterStackFrame, debugChannel: debugChannel == null ? void 0 : debugChannel.serverSide, signal: requestAbortSignal }); return new _flightrenderresult.FlightRenderResult(flightStream, { fetchMetrics: workStore.fetchMetrics }, options == null ? void 0 : options.waitUntil); } } /** * Production-only staged dynamic flight render for cache components (Node.js * streams). Uses staged rendering to separate static (RDC-backed) from * runtime/dynamic content. */ async function generateStagedDynamicFlightRenderResultNode(req, ctx, requestStore) { const { componentMod, workStore, renderOpts } = ctx; const { 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(); const stageController = new _stagedrendering.StagedRenderingController({ abortSignal: null, abandonController: null, // 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. syncIO: _stagedrendering.SyncIOMode.Untracked, finalStage: null }); // Initialize stale time tracking on the request store. requestStore.stale = _constants1.INFINITE_CACHE; requestStore.stagedRendering = stageController; requestStore.varyParamsAccumulator = (0, _varyparams.createResponseVaryParamsAccumulator)(); requestStore.asyncApiPromises = createAsyncApiPromises(stageController, requestStore.cookies, requestStore.mutableCookies, requestStore.headers); (0, _staletime.trackStaleTime)(requestStore, staleTimeIterable, selectStaleTime); const shellByteLengthDeferred = (0, _promisewithresolvers.createPromiseWithResolvers)(); const staticStageByteLengthDeferred = (0, _promisewithresolvers.createPromiseWithResolvers)(); let runtimePrefetchStream; // Check if this route should runtime-cache its navigation. This happens when // Partial Prefetching is enabled for the route, either per segment (a // `prefetch` of 'partial' or 'unstable_eager') or globally (the // `partialPrefetching` config). 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 because it adds extra server // processing and increases the response payload size. if (Boolean(renderOpts.partialPrefetching) || await (0, _instantconfig.anySegmentHasPartialPrefetchingEnabled)(loaderTree)) { // Create a mutable cache that gets filled during the dynamic render. const prerenderResumeDataCache = (0, _resumedatacache.createPrerenderResumeDataCache)(); requestStore.resumeDataCache = 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: staticStageByteLengthDeferred.promise, shellByteLengthPromise: shellByteLengthDeferred.promise, runtimePrefetchStream }); const { clientModules } = (0, _manifestssingleton.getClientReferenceManifest)(); const flightStream = await (0, _apprenderrenderutils.runInSequentialTasks)(()=>{ stageController.advanceStage(_stagedrendering.RenderStage.ShellStatic); const sourceStream = _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToNodeFlightStream, ctx.componentMod, rscPayload, clientModules, { onError, filterStackFrame }); const replayable = new _apprenderprerenderutils.ReplayableNodeStream(sourceStream); const dynamicStream = replayable.createReplayStream(); const staticStream = replayable.createReplayStream(); void countShellAndStaticStageBytes(staticStream, stageController).then((byteLengths)=>{ staticStageByteLengthDeferred.resolve(byteLengths[_stagedrendering.RenderStage.Static]); shellByteLengthDeferred.resolve(byteLengths[_stagedrendering.RenderStage.ShellStatic]); }); return dynamicStream; }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Static); }, ()=>{ // This is a separate task that doesn't advance a stage. It forces // draining the immediate queue so that the stale time iterable and vary // params accumulators are flushed before we advance to the dynamic stage. staleTimeIterable.close(); if (requestStore.varyParamsAccumulator) { (0, _varyparams.finishAccumulatingVaryParams)(requestStore.varyParamsAccumulator); } }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); return new _flightrenderresult.FlightRenderResult(flightStream, { 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(); // We want to be able to rewind the result to a session shell. const mode = { type: 'rewindable-session-shell', shellUsedSessionDataDeferred: (0, _promisewithresolvers.createPromiseWithResolvers)(), shellByteLengthDeferred: (0, _promisewithresolvers.createPromiseWithResolvers)() }; const { result } = await finalRuntimeServerPrerender(mode, ctx, generateDynamicRSCPayload.bind(null, ctx, { staleTimeIterable, shellByteLengthPromise: mode.type === 'rewindable-session-shell' ? mode.shellByteLengthDeferred.promise : undefined, shellUsedSessionDataPromise: mode.shellUsedSessionDataDeferred.promise }), prerenderResumeDataCache, rootParams, requestStore.headers, requestStore.cookies, requestStore.draftMode, onError, staleTimeIterable, // This path is only reached on the production Cache Components + Cached // Navigations renders (the staged Flight response and the HTML hydration // payload), which set up no React debug channel. undefined); 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 stagedRenderWithoutCachesInDevNode(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({ abortSignal: null, abandonController: null, syncIO: _stagedrendering.SyncIOMode.Untracked, finalStage: null }); const environmentName = ()=>{ const currentStage = stageController.currentStage; return getEnvironmentNameForStageWithoutCaches(currentStage); }; 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.ShellStatic); return _workunitasyncstorageexternal.workUnitAsyncStorage.run(requestStore, _streamops.renderToNodeFlightStream, ctx.componentMod, rscPayload, clientModules, { ...options, environmentName }); }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Static); }, ()=>{ stageController.advanceStage(_stagedrendering.RenderStage.Dynamic); }); } function getEnvironmentNameForStageWithoutCaches(stage) { switch(stage){ case _stagedrendering.RenderStage.Before: case _stagedrendering.RenderStage.ShellStatic: case _stagedrendering.RenderStage.Static: return 'Prerender'; case _stagedrendering.RenderStage.ShellRuntime: case _stagedrendering.RenderStage.Runtime: case _stagedrendering.RenderStage.Dynamic: case _stagedrendering.RenderStage.Abandoned: return 'Server'; default: stage; throw Object.defineProperty(new _invarianterror.InvariantError(`Invalid render stage: ${stage}`), "__NEXT_ERROR_CODE", { value: "E881", enumerable: false, configurable: true }); } } /** * 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; let didErrorObservably = false; function onFlightDataRenderError(err, silenceLog) { didErrorObservably = true; 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 = !ctx.isPrefetch && !isBypassingCachesInDev(initialRequestStore, workStore) && (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, workStore)) { // 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, a hard refresh (cache-control: "no-cache"), // or draft mode. !isBypassingCachesInDev(initialRequestStore, workStore)) { // 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 prefetchMode = await getPrefetchingModeForPage(renderOpts, loaderTree); // A client navigation into a Partial Prefetching route extends the shell // through the runtime-prefetchable content: it has already settled on the // client (via the prefetch) by the time it navigates, so it belongs in this // response's shell. Everything else uses the static shell, like an initial // load: plain navigations, and HMR refreshes (a fresh render of the current // page, with no settled prefetch to draw on). Dynamic content always // streams in after the shell. let prefetchStage; if (initialRequestStore.isHmrRefresh === true) { prefetchStage = _stagedrendering.RenderStage.Static; } else { if (prefetchMode === 2) { // TODO(app-shells): model `partialPrefetching: "unstable_eager"` // TODO(app-shells): if this navigation came from <Link prefetch={true} />, // we should show the shell for a speculative prefetch // (which can have more data than the app shell) prefetchStage = _stagedrendering.RenderStage.ShellRuntime; } else { prefetchStage = _stagedrendering.RenderStage.Static; } } // With Server Components HMR cancellation enabled, a superseded HMR refresh // aborts its own client fetch (see the client-side supersession logic), // which closes this response. We use that response-close as the signal to // stop the server work this refresh started that's now discarded: the // streaming render below is aborted, and the detached validation is skipped // (including aborting the background renders it uses to prepare its // inputs). The render's in-flight `'use cache'` fills are left running, // since they aren't tied to its controller. A superseding refresh can't // reuse those fills today, because each edit changes the HMR hash baked // into the cache key; that becomes useful only once those keys use // implementation-derived hashes instead (see `use-cache-wrapper.ts`). // // The detached validation is Cache Components only: it runs only on this // staged dev render, so there's nothing to skip on the non-Cache Components // dev RSC path. That path (`generateDynamicFlightRenderResult`) aborts its // superseded render the same way; it just has no validation to skip. // // TODO: The gate is `isHmrRefresh` for now because that's the only case we // cancel today. The response-close signal itself is general, so this could // later be relaxed to also cover a browser stop or a devtools "cancel // render" button. const requestAbortSignal = renderOpts.experimental.serverComponentsHmrCancellation === true && initialRequestStore.isHmrRefresh === true && (0, _helpers.isNodeNextResponse)(ctx.res) ? (0, _nextrequest.signalFromNodeResponse)(ctx.res.originalResponse) : undefined; const result = await stagedRenderWithCachesInDev({ prefetchMode, ctx, requestStore: initialRequestStore, createRequestStore, getPayload, onError, shouldValidate, fallbackRouteParams: fallbackParams, getDevRenderDidError: ()=>didErrorObservably, navigationKind: { type: 'prefetched-client', prefetchStage }, requestAbortSignal }); stream = result.stream; debugChannel = result.debugChannel; } 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.createNodeDebugChannel)(); stream = await stagedRenderWithoutCachesInDevNode(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, isShellPrefetch) { const { workStore, renderOpts, htmlRequestId, requestId } = ctx; const { isBuildTimePrerendering = false, onInstrumentationRequestError, setReactDebugChannel } = 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)(); await prospectiveRuntimeServerPrerender(ctx, isShellPrefetch, generateDynamicRSCPayload.bind(null, ctx), prerenderResumeDataCache, rootParams, requestStore.headers, requestStore.cookies, requestStore.draftMode); const mode = isShellPrefetch ? { type: 'session-shell-only', shellUsedSessionDataDeferred: (0, _promisewithresolvers.createPromiseWithResolvers)() } : { type: 'rewindable-session-shell', shellUsedSessionDataDeferred: (0, _promisewithresolvers.createPromiseWithResolvers)(), shellByteLengthDeferred: (0, _promisewithresolvers.createPromiseWithResolvers)() }; const debugChannel = setReactDebugChannel ? (0, _debugchannelserver.createWebDebugChannel)() : undefined; if (debugChannel && setReactDebugChannel) { setReactDebugChannel(debugChannel.clientSide, htmlRequestId, requestId); } const response = await finalRuntimeServerPrerender(mode, ctx, generateDynamicRSCPayload.bind(null, ctx, { staleTimeIterable, shellByteLengthPromise: mode.type === 'rewindable-session-shell' ? mode.shellByteLengthDeferred.promise : undefined, shellUsedSessionDataPromise: mode.shellUsedSessionDataDeferred.promise }), prerenderResumeDataCache, rootParams, requestStore.headers, requestStore.cookies, requestStore.draftMode, onError, staleTimeIterable, debugChannel == null ? void 0 : debugChannel.serverSide); applyMetadataFromPrerenderResult(response, metadata, workStore); metadata.fetchMetrics = ctx.workStore.fetchMetrics; return new _flightrenderresult.FlightRenderResult(response.result.prelude, metadata); } async function prospectiveRuntimeServerPrerender(ctx, isShellPrefetch, getPayload, resumeDataCache, 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