next
Version:
The React Framework
867 lines • 371 kB
JavaScript
"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