next
Version:
The React Framework
794 lines • 79.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
__next_app__: null,
handler: null,
routeModule: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
__next_app__: function() {
return __next_app__;
},
handler: function() {
return handler;
},
routeModule: function() {
return routeModule;
}
});
0 && __export(require("../../server/app-render/entry-base"));
const _modulecompiled = require("../../server/route-modules/app-page/module.compiled");
const _routekind = require("../../server/route-kind");
const _utils = require("../../server/instrumentation/utils");
const _tracer = require("../../server/lib/trace/tracer");
const _requestmeta = require("../../server/request-meta");
const _constants = require("../../server/lib/trace/constants");
const _interopdefault = require("../../server/app-render/interop-default");
const _stripflightheaders = require("../../server/app-render/strip-flight-headers");
const _node = require("../../server/base-http/node");
const _ppr = require("../../server/lib/experimental/ppr");
const _fallbackparams = require("../../server/request/fallback-params");
const _manifestssingleton = require("../../server/app-render/manifests-singleton");
const _streamingmetadata = require("../../server/lib/streaming-metadata");
const _apppaths = require("../../shared/lib/router/utils/app-paths");
const _serveractionrequestmeta = require("../../server/lib/server-action-request-meta");
const _approuterheaders = require("../../client/components/app-router-headers");
const _isbot = require("../../shared/lib/router/utils/is-bot");
const _responsecache = require("../../server/response-cache");
const _fallback = require("../../lib/fallback");
const _renderresult = /*#__PURE__*/ _interop_require_default(require("../../server/render-result"));
const _constants1 = require("../../lib/constants");
const _encodedtags = require("../../server/stream-utils/encoded-tags");
const _nodewebstreamshelper = require("../../server/stream-utils/node-web-streams-helper");
const _sendpayload = require("../../server/send-payload");
const _nofallbackerrorexternal = require("../../shared/lib/no-fallback-error.external");
const _sizelimit = require("../../shared/lib/size-limit");
const _postponedrequestbody = require("../../server/lib/postponed-request-body");
const _entrybase = /*#__PURE__*/ _interop_require_wildcard(_export_star(require("../../server/app-render/entry-base"), exports));
const _redirectstatuscode = require("../../client/components/redirect-status-code");
const _invarianterror = require("../../shared/lib/invariant-error");
const _scheduler = require("../../lib/scheduler");
const _interceptionroutes = require("../../shared/lib/router/utils/interception-routes");
const _getsegmentparam = require("../../shared/lib/router/utils/get-segment-param");
function _export_star(from, to) {
Object.keys(from).forEach(function(k) {
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
Object.defineProperty(to, k, {
enumerable: true,
get: function() {
return from[k];
}
});
}
});
return from;
}
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;
}
const __next_app__ = {
require: __next_app_require__,
loadChunk: __next_app_load_chunk__
};
const routeModule = new _modulecompiled.AppPageRouteModule({
definition: {
kind: _routekind.RouteKind.APP_PAGE,
page: 'VAR_DEFINITION_PAGE',
pathname: 'VAR_DEFINITION_PATHNAME',
// The following aren't used in production.
bundlePath: '',
filename: '',
appPaths: []
},
userland: {
loaderTree: tree
},
distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '',
relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || ''
});
function buildDynamicSegmentPlaceholder(param) {
const { repeat, optional } = (0, _getsegmentparam.getParamProperties)(param.paramType);
if (optional) {
return `[[...${param.paramName}]]`;
}
if (repeat) {
return `[...${param.paramName}]`;
}
return `[${param.paramName}]`;
}
/**
* Builds the cache key for the most complete prerenderable shell we can derive
* from the shell that matched this request. Only params that can still be
* filled by `generateStaticParams` are substituted; fully dynamic params stay
* as placeholders so a request like `/c/foo` can complete `/[one]/[two]` into
* `/c/[two]` rather than `/c/foo`.
*/ function buildCompletedShellCacheKey(fallbackPathname, remainingPrerenderableParams, params) {
const prerenderableParamsByName = new Map(remainingPrerenderableParams.map((param)=>[
param.paramName,
param
]));
return fallbackPathname.split('/').map((segment)=>{
const segmentParam = (0, _getsegmentparam.getSegmentParam)(segment);
if (!segmentParam) {
return segment;
}
const remainingParam = prerenderableParamsByName.get(segmentParam.paramName);
if (!remainingParam) {
return segment;
}
const value = params == null ? void 0 : params[remainingParam.paramName];
if (!value) {
return segment;
}
const encodedValue = Array.isArray(value) ? value.map((item)=>encodeURIComponent(item)).join('/') : encodeURIComponent(value);
return segment.replace(buildDynamicSegmentPlaceholder(remainingParam), encodedValue);
}).join('/') || '/';
}
async function handler(req, res, ctx) {
var _this, _prerenderManifest_routes_resolvedPathname, _prerenderInfo_fallbackRootParams, _prerenderInfo_fallbackRouteParams;
if (ctx.requestMeta) {
(0, _requestmeta.setRequestMeta)(req, ctx.requestMeta);
}
if (routeModule.isDev) {
(0, _requestmeta.addRequestMeta)(req, 'devRequestTimingInternalsEnd', process.hrtime.bigint());
}
const isMinimalMode = Boolean((0, _requestmeta.getRequestMeta)(req, 'minimalMode'));
let srcPage = 'VAR_DEFINITION_PAGE';
// turbopack doesn't normalize `/index` in the page name
// so we need to to process dynamic routes properly
// TODO: fix turbopack providing differing value from webpack
if (process.env.TURBOPACK) {
srcPage = srcPage.replace(/\/index$/, '') || '/';
} else if (srcPage === '/index') {
// we always normalize /index specifically
srcPage = '/';
}
const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE;
const prepareResult = await routeModule.prepare(req, res, {
srcPage,
multiZoneDraftMode
});
if (!prepareResult) {
res.statusCode = 400;
res.end('Bad Request');
ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve());
return null;
}
const { buildId, query, params, pageIsDynamic, buildManifest, nextFontManifest, reactLoadableManifest, serverActionsManifest, clientReferenceManifest, subresourceIntegrityManifest, prerenderManifest, isDraftMode, resolvedPathname, revalidateOnlyGenerated, routerServerContext, nextConfig, parsedUrl, interceptionRoutePatterns, deploymentId, clientAssetToken } = prepareResult;
const normalizedSrcPage = (0, _apppaths.normalizeAppPath)(srcPage);
let { isOnDemandRevalidate } = prepareResult;
// We use the resolvedPathname instead of the parsedUrl.pathname because it
// is not rewritten as resolvedPathname is. This will ensure that the correct
// prerender info is used instead of using the original pathname as the
// source. If however PPR is enabled and cacheComponents is disabled, we
// treat the pathname as dynamic. Currently, there's a bug in the PPR
// implementation that incorrectly leaves %%drp placeholders in the output of
// parallel routes. This is addressed with cacheComponents.
const prerenderMatch = nextConfig.experimental.ppr && !nextConfig.cacheComponents && (0, _interceptionroutes.isInterceptionRouteAppPath)(resolvedPathname) ? null : routeModule.match(resolvedPathname, prerenderManifest);
const prerenderInfo = (prerenderMatch == null ? void 0 : prerenderMatch.route) ?? null;
const isPrerendered = !!prerenderManifest.routes[resolvedPathname];
const userAgent = req.headers['user-agent'] || '';
const botType = (0, _isbot.getBotType)(userAgent);
const isHtmlBot = (0, _streamingmetadata.isHtmlBotRequest)(req);
/**
* If true, this indicates that the request being made is for an app
* prefetch request.
*/ const isPrefetchRSCRequest = (0, _requestmeta.getRequestMeta)(req, 'isPrefetchRSCRequest') ?? req.headers[_approuterheaders.NEXT_ROUTER_PREFETCH_HEADER] === '1' // exclude runtime prefetches, which use '2'
;
// NOTE: Don't delete headers[RSC] yet, it still needs to be used in renderToHTML later
const isRSCRequest = (0, _requestmeta.getRequestMeta)(req, 'isRSCRequest') ?? Boolean(req.headers[_approuterheaders.RSC_HEADER]);
const isPossibleServerAction = (0, _serveractionrequestmeta.getIsPossibleServerAction)(req);
/**
* If the route being rendered is an app page, and the ppr feature has been
* enabled, then the given route _could_ support PPR.
*/ const couldSupportPPR = (0, _ppr.checkIsAppPPREnabled)(nextConfig.experimental.ppr);
// Stash postponed state for server actions when in minimal mode.
// We extract it here so the RDC is available for the re-render after the action completes.
const resumeStateLengthHeader = req.headers[_constants1.NEXT_RESUME_STATE_LENGTH_HEADER];
if (!(0, _requestmeta.getRequestMeta)(req, 'postponed') && isMinimalMode && couldSupportPPR && isPossibleServerAction && resumeStateLengthHeader && typeof resumeStateLengthHeader === 'string') {
const stateLength = parseInt(resumeStateLengthHeader, 10);
const { maxPostponedStateSize, maxPostponedStateSizeBytes } = (0, _postponedrequestbody.getMaxPostponedStateSize)(nextConfig.experimental.maxPostponedStateSize);
if (!isNaN(stateLength) && stateLength > 0) {
var _nextConfig_experimental_serverActions;
if (stateLength > maxPostponedStateSizeBytes) {
res.statusCode = 413;
res.end((0, _postponedrequestbody.getPostponedStateExceededErrorMessage)(maxPostponedStateSize));
ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve());
return null;
}
// Calculate max total body size to prevent buffering excessively large
// payloads before the action handler checks. We use stateLength (not
// maxPostponedStateSizeBytes) so the postponed state doesn't eat into
// the action body budget - it's already validated above.
const defaultActionBodySizeLimit = '1 MB';
const actionBodySizeLimit = ((_nextConfig_experimental_serverActions = nextConfig.experimental.serverActions) == null ? void 0 : _nextConfig_experimental_serverActions.bodySizeLimit) ?? defaultActionBodySizeLimit;
const actionBodySizeLimitBytes = actionBodySizeLimit !== defaultActionBodySizeLimit ? require('next/dist/compiled/bytes').parse(actionBodySizeLimit) : 1024 * 1024 // 1 MB
;
const maxTotalBodySize = stateLength + actionBodySizeLimitBytes;
const fullBody = await (0, _postponedrequestbody.readBodyWithSizeLimit)(req, maxTotalBodySize);
if (fullBody === null) {
res.statusCode = 413;
res.end(`Request body exceeded limit. ` + `To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit`);
ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve());
return null;
}
if (fullBody.length >= stateLength) {
// Extract postponed state from the beginning
const postponedState = fullBody.subarray(0, stateLength).toString('utf8');
(0, _requestmeta.addRequestMeta)(req, 'postponed', postponedState);
// Store the remaining action body for the action handler
const actionBody = fullBody.subarray(stateLength);
(0, _requestmeta.addRequestMeta)(req, 'actionBody', actionBody);
} else {
throw Object.defineProperty(new Error(`invariant: expected ${stateLength} bytes of postponed state but only received ${fullBody.length} bytes`), "__NEXT_ERROR_CODE", {
value: "E979",
enumerable: false,
configurable: true
});
}
}
}
if (!(0, _requestmeta.getRequestMeta)(req, 'postponed') && couldSupportPPR && req.headers[_constants1.NEXT_RESUME_HEADER] === '1' && req.method === 'POST') {
const { maxPostponedStateSize, maxPostponedStateSizeBytes } = (0, _postponedrequestbody.getMaxPostponedStateSize)(nextConfig.experimental.maxPostponedStateSize);
// Decode the postponed state from the request body, it will come as
// an array of buffers, so collect them and then concat them to form
// the string.
const body = await (0, _postponedrequestbody.readBodyWithSizeLimit)(req, maxPostponedStateSizeBytes);
if (body === null) {
res.statusCode = 413;
res.end((0, _postponedrequestbody.getPostponedStateExceededErrorMessage)(maxPostponedStateSize));
ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve());
return null;
}
const postponed = body.toString('utf8');
(0, _requestmeta.addRequestMeta)(req, 'postponed', postponed);
}
// When enabled, this will allow the use of the `?__nextppronly` query to
// enable debugging of the static shell.
const hasDebugStaticShellQuery = process.env.__NEXT_EXPERIMENTAL_STATIC_SHELL_DEBUGGING === '1' && typeof query.__nextppronly !== 'undefined' && couldSupportPPR;
// When enabled, this will allow the use of the `?__nextppronly` query
// to enable debugging of the fallback shell.
const hasDebugFallbackShellQuery = hasDebugStaticShellQuery && query.__nextppronly === 'fallback';
// Whether the testing API is exposed (dev mode or explicit flag)
const exposeTestingApi = routeModule.isDev === true || nextConfig.experimental.exposeTestingApiInProductionBuild === true;
// Enable the Instant Navigation Testing API. Renders only the prefetched
// portion of the page, excluding dynamic content. This allows tests to
// assert on the prefetched UI state deterministically.
// - Header: Used for client-side navigations where we can set request headers
// - Cookie: Used for MPA navigations (page reload, full page load) where we
// can't set request headers. Only applies to document requests (no RSC
// header) - RSC requests should proceed normally even during a locked scope,
// with blocking happening on the client side.
const isInstantNavigationTest = exposeTestingApi && (req.headers[_approuterheaders.NEXT_INSTANT_PREFETCH_HEADER] === '1' || req.headers[_approuterheaders.RSC_HEADER] === undefined && typeof req.headers.cookie === 'string' && req.headers.cookie.includes(_approuterheaders.NEXT_INSTANT_TEST_COOKIE + '='));
// This page supports PPR if it is marked as being `PARTIALLY_STATIC` in the
// prerender manifest and this is an app page.
const isRoutePPREnabled = // When the instant navigation testing API is active, enable the PPR
// prerender path even without Cache Components. In dev mode without CC,
// static pages need this path to produce buffered segment data (the
// legacy prerender path hangs in dev mode).
(couldSupportPPR || isInstantNavigationTest) && (((_this = prerenderManifest.routes[normalizedSrcPage] ?? prerenderManifest.dynamicRoutes[normalizedSrcPage]) == null ? void 0 : _this.renderingMode) === 'PARTIALLY_STATIC' || // Ideally we'd want to check the appConfig to see if this page has PPR
// enabled or not, but that would require plumbing the appConfig through
// to the server during development. We assume that the page supports it
// but only during development or when the testing API is exposed.
(hasDebugStaticShellQuery || isInstantNavigationTest) && (exposeTestingApi || (routerServerContext == null ? void 0 : routerServerContext.experimentalTestProxy) === true));
const isDebugStaticShell = (hasDebugStaticShellQuery || isInstantNavigationTest) && isRoutePPREnabled;
// We should enable debugging dynamic accesses when the static shell
// debugging has been enabled and we're also in development mode.
const isDebugDynamicAccesses = isDebugStaticShell && routeModule.isDev === true;
const isDebugFallbackShell = hasDebugFallbackShellQuery && isRoutePPREnabled;
// If we're in minimal mode, then try to get the postponed information from
// the request metadata. If available, use it for resuming the postponed
// render.
const minimalPostponed = isRoutePPREnabled ? (0, _requestmeta.getRequestMeta)(req, 'postponed') : undefined;
// If PPR is enabled, and this is a RSC request (but not a prefetch), then
// we can use this fact to only generate the flight data for the request
// because we can't cache the HTML (as it's also dynamic).
const staticPrefetchDataRoute = (_prerenderManifest_routes_resolvedPathname = prerenderManifest.routes[resolvedPathname]) == null ? void 0 : _prerenderManifest_routes_resolvedPathname.prefetchDataRoute;
let isDynamicRSCRequest = isRoutePPREnabled && isRSCRequest && !isPrefetchRSCRequest && // If generated at build time, treat the RSC request as static
// so we can serve the prebuilt .rsc without a dynamic render.
// Only do this for routes that have a concrete prefetchDataRoute.
!staticPrefetchDataRoute;
// During a PPR revalidation, the RSC request is not dynamic if we do not have the postponed data.
// We only attach the postponed data during a resume. If there's no postponed data, then it must be a revalidation.
// This is to ensure that we don't bypass the cache during a revalidation.
if (isMinimalMode) {
isDynamicRSCRequest = isDynamicRSCRequest && !!minimalPostponed;
}
// Need to read this before it's stripped by stripFlightHeaders. We don't
// need to transfer it to the request meta because it's only read
// within this function; the static segment data should have already been
// generated, so we will always either return a static response or a 404.
const segmentPrefetchHeader = (0, _requestmeta.getRequestMeta)(req, 'segmentPrefetchRSCRequest');
// TODO: investigate existing bug with shouldServeStreamingMetadata always
// being true for a revalidate due to modifying the base-server this.renderOpts
// when fixing this to correct logic it causes hydration issue since we set
// serveStreamingMetadata to true during export
const serveStreamingMetadata = botType && isRoutePPREnabled ? false : !userAgent ? true : (0, _streamingmetadata.shouldServeStreamingMetadata)(userAgent, nextConfig.htmlLimitedBots);
const isSSG = Boolean((prerenderInfo || isPrerendered || prerenderManifest.routes[normalizedSrcPage]) && // If this is a bot request and PPR is enabled, then we don't want
// to serve a static response. This applies to both DOM bots (like Googlebot)
// and HTML-limited bots.
!(botType && isRoutePPREnabled));
// When a page supports cacheComponents, we can support RDC for Navigations
const supportsRDCForNavigations = isRoutePPREnabled && nextConfig.cacheComponents === true;
// In development, we always want to generate dynamic HTML.
const supportsDynamicResponse = // If we're in development, we always support dynamic HTML, unless it's
// a data request, in which case we only produce static HTML.
routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports
// dynamic HTML.
!isSSG || // If this request has provided postponed data, it supports dynamic
// HTML.
typeof minimalPostponed === 'string' || // If this handler supports onCacheEntryV2, then we can only support
// dynamic responses if it's a dynamic RSC request and not in minimal mode. If it
// doesn't support it we must fallback to the default behavior.
(supportsRDCForNavigations && (0, _requestmeta.getRequestMeta)(req, 'onCacheEntryV2') ? // which will generate the RDC for the route. When resuming a Dynamic
// RSC request, we'll pass the minimal postponed data to the render
// which will trigger the `supportsDynamicResponse` to be true.
isDynamicRSCRequest && !isMinimalMode : isDynamicRSCRequest);
// When bots request PPR page, perform the full dynamic rendering.
// This applies to both DOM bots (like Googlebot) and HTML-limited bots.
const shouldWaitOnAllReady = Boolean(botType) && isRoutePPREnabled;
const remainingPrerenderableParams = (prerenderInfo == null ? void 0 : prerenderInfo.remainingPrerenderableParams) ?? [];
const hasUnresolvedRootFallbackParams = (prerenderInfo == null ? void 0 : prerenderInfo.fallback) === null && (((_prerenderInfo_fallbackRootParams = prerenderInfo.fallbackRootParams) == null ? void 0 : _prerenderInfo_fallbackRootParams.length) ?? 0) > 0;
let ssgCacheKey = null;
if (!isDraftMode && isSSG && !supportsDynamicResponse && !isPossibleServerAction && !minimalPostponed && !isDynamicRSCRequest) {
// For normal SSG routes we cache by the fully resolved pathname. For
// partial fallbacks we instead derive the cache key from the shell
// that matched this request so `/prefix/[one]/[two]` can specialize into
// `/prefix/c/[two]` without promoting all the way to `/prefix/c/foo`.
const fallbackPathname = prerenderMatch ? typeof (prerenderInfo == null ? void 0 : prerenderInfo.fallback) === 'string' ? prerenderInfo.fallback : prerenderMatch.source : null;
if (nextConfig.experimental.partialFallbacks === true && fallbackPathname && (prerenderInfo == null ? void 0 : prerenderInfo.fallbackRouteParams) && !hasUnresolvedRootFallbackParams) {
if (remainingPrerenderableParams.length > 0) {
const completedShellCacheKey = buildCompletedShellCacheKey(fallbackPathname, remainingPrerenderableParams, params);
// If applying the current request params doesn't make the shell any
// more complete, then this shell is already at its most complete
// form and should remain shared rather than creating a new cache entry.
ssgCacheKey = completedShellCacheKey !== fallbackPathname ? completedShellCacheKey : null;
}
} else {
ssgCacheKey = resolvedPathname;
}
}
// the staticPathKey differs from ssgCacheKey since
// ssgCacheKey is null in dev since we're always in "dynamic"
// mode in dev to bypass the cache. It can also be null for partial
// fallback shells that should remain shared and must not create a
// param-specific ISR entry, but we still need to honor fallback handling.
let staticPathKey = ssgCacheKey;
if (!staticPathKey && (routeModule.isDev || isSSG && pageIsDynamic && (prerenderInfo == null ? void 0 : prerenderInfo.fallbackRouteParams) && // Server action requests must not get a staticPathKey, otherwise they
// enter the fallback rendering block below and return the cached HTML
// shell with the action result appended, instead of responding with
// just the RSC action result.
!isPossibleServerAction)) {
staticPathKey = resolvedPathname;
}
// If this is a request for an app path that should be statically generated
// and we aren't in the edge runtime, strip the flight headers so it will
// generate the static response.
if (!routeModule.isDev && !isDraftMode && isSSG && isRSCRequest && !isDynamicRSCRequest) {
(0, _stripflightheaders.stripFlightHeaders)(req.headers);
}
const ComponentMod = {
..._entrybase,
tree,
handler,
routeModule,
__next_app__
};
// Before rendering (which initializes component tree modules), we have to
// set the reference manifests to our global store so Server Action's
// encryption util can access to them at the top level of the page module.
if (serverActionsManifest && clientReferenceManifest) {
(0, _manifestssingleton.setManifestsSingleton)({
page: srcPage,
clientReferenceManifest,
serverActionsManifest
});
}
const method = req.method || 'GET';
const tracer = (0, _tracer.getTracer)();
const activeSpan = tracer.getActiveScopeSpan();
const isWrappedByNextServer = Boolean(routerServerContext == null ? void 0 : routerServerContext.isWrappedByNextServer);
const remainingFallbackRouteParams = nextConfig.experimental.partialFallbacks === true && remainingPrerenderableParams.length > 0 ? (prerenderInfo == null ? void 0 : (_prerenderInfo_fallbackRouteParams = prerenderInfo.fallbackRouteParams) == null ? void 0 : _prerenderInfo_fallbackRouteParams.filter((param)=>!remainingPrerenderableParams.some((prerenderableParam)=>prerenderableParam.paramName === param.paramName))) ?? [] : [];
const render404 = async ()=>{
// TODO: should route-module itself handle rendering the 404
if (routerServerContext == null ? void 0 : routerServerContext.render404) {
await routerServerContext.render404(req, res, parsedUrl, false);
} else {
res.end('This page could not be found');
}
return null;
};
try {
const varyHeader = routeModule.getVaryHeader(resolvedPathname, interceptionRoutePatterns);
res.setHeader('Vary', varyHeader);
let parentSpan;
const invokeRouteModule = async (span, context)=>{
const nextReq = new _node.NodeNextRequest(req);
const nextRes = new _node.NodeNextResponse(res);
return routeModule.render(nextReq, nextRes, context).finally(()=>{
if (!span) return;
span.setAttributes({
'http.status_code': res.statusCode,
'next.rsc': false
});
const rootSpanAttributes = tracer.getRootSpanAttributes();
// We were unable to get attributes, probably OTEL is not enabled
if (!rootSpanAttributes) {
return;
}
if (rootSpanAttributes.get('next.span_type') !== _constants.BaseServerSpan.handleRequest) {
console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`);
return;
}
const route = rootSpanAttributes.get('next.route');
if (route) {
const name = `${method} ${route}`;
span.setAttributes({
'next.route': route,
'http.route': route,
'next.span_name': name
});
span.updateName(name);
// Propagate http.route to the parent span if one exists (e.g.
// a platform-created HTTP span in adapter deployments).
if (parentSpan && parentSpan !== span) {
parentSpan.setAttribute('http.route', route);
parentSpan.updateName(name);
}
} else {
span.updateName(`${method} ${srcPage}`);
}
});
};
const incrementalCache = (0, _requestmeta.getRequestMeta)(req, 'incrementalCache') || await routeModule.getIncrementalCache(req, nextConfig, prerenderManifest, isMinimalMode);
incrementalCache == null ? void 0 : incrementalCache.resetRequestCache();
globalThis.__incrementalCache = incrementalCache;
const doRender = async ({ span, postponed, fallbackRouteParams, forceStaticRender })=>{
const context = {
query,
params,
page: normalizedSrcPage,
sharedContext: {
buildId,
deploymentId,
clientAssetToken
},
serverComponentsHmrCache: (0, _requestmeta.getRequestMeta)(req, 'serverComponentsHmrCache'),
fallbackRouteParams,
renderOpts: {
App: ()=>null,
Document: ()=>null,
pageConfig: {},
ComponentMod,
Component: (0, _interopdefault.interopDefault)(ComponentMod),
params,
routeModule,
page: srcPage,
postponed,
shouldWaitOnAllReady,
serveStreamingMetadata,
supportsDynamicResponse: typeof postponed === 'string' || supportsDynamicResponse,
buildManifest,
nextFontManifest,
reactLoadableManifest,
subresourceIntegrityManifest,
setCacheStatus: routerServerContext == null ? void 0 : routerServerContext.setCacheStatus,
setIsrStatus: routerServerContext == null ? void 0 : routerServerContext.setIsrStatus,
setReactDebugChannel: routerServerContext == null ? void 0 : routerServerContext.setReactDebugChannel,
sendErrorsToBrowser: routerServerContext == null ? void 0 : routerServerContext.sendErrorsToBrowser,
dir: process.env.NEXT_RUNTIME === 'nodejs' ? require('path').join(/* turbopackIgnore: true */ process.cwd(), routeModule.relativeProjectDir) : `${process.cwd()}/${routeModule.relativeProjectDir}`,
isDraftMode,
botType,
isOnDemandRevalidate,
isPossibleServerAction,
assetPrefix: nextConfig.assetPrefix,
nextConfigOutput: nextConfig.output,
crossOrigin: nextConfig.crossOrigin,
trailingSlash: nextConfig.trailingSlash,
images: nextConfig.images,
previewProps: prerenderManifest.preview,
enableTainting: nextConfig.experimental.taint,
htmlLimitedBots: nextConfig.htmlLimitedBots,
reactMaxHeadersLength: nextConfig.reactMaxHeadersLength,
multiZoneDraftMode,
incrementalCache,
cacheLifeProfiles: nextConfig.cacheLife,
basePath: nextConfig.basePath,
serverActions: nextConfig.experimental.serverActions,
logServerFunctions: typeof nextConfig.logging === 'object' && Boolean(nextConfig.logging.serverFunctions),
...isDebugStaticShell || isDebugDynamicAccesses || isDebugFallbackShell ? {
isBuildTimePrerendering: true,
supportsDynamicResponse: false,
isStaticGeneration: true,
isDebugDynamicAccesses: isDebugDynamicAccesses
} : {},
cacheComponents: Boolean(nextConfig.cacheComponents),
experimental: {
isRoutePPREnabled,
expireTime: nextConfig.expireTime,
staleTimes: nextConfig.experimental.staleTimes,
dynamicOnHover: Boolean(nextConfig.experimental.dynamicOnHover),
optimisticRouting: Boolean(nextConfig.experimental.optimisticRouting),
inlineCss: Boolean(nextConfig.experimental.inlineCss),
prefetchInlining: nextConfig.experimental.prefetchInlining ?? false,
authInterrupts: Boolean(nextConfig.experimental.authInterrupts),
cachedNavigations: Boolean(nextConfig.experimental.cachedNavigations),
clientTraceMetadata: nextConfig.experimental.clientTraceMetadata || [],
clientParamParsingOrigins: nextConfig.experimental.clientParamParsingOrigins,
maxPostponedStateSizeBytes: (0, _sizelimit.parseMaxPostponedStateSize)(nextConfig.experimental.maxPostponedStateSize)
},
waitUntil: ctx.waitUntil,
onClose: (cb)=>{
res.on('close', cb);
},
onAfterTaskError: ()=>{},
onInstrumentationRequestError: (error, _request, errorContext, silenceLog)=>routeModule.onRequestError(req, error, errorContext, silenceLog, routerServerContext),
err: (0, _requestmeta.getRequestMeta)(req, 'invokeError')
}
};
// When we're revalidating in the background, we should not allow dynamic
// responses.
if (forceStaticRender) {
context.renderOpts.supportsDynamicResponse = false;
}
const result = await invokeRouteModule(span, context);
const { metadata } = result;
const { cacheControl, headers = {}, // Add any fetch tags that were on the page to the response headers.
fetchTags: cacheTags, fetchMetrics } = metadata;
if (cacheTags) {
headers[_constants1.NEXT_CACHE_TAGS_HEADER] = cacheTags;
}
// Pull any fetch metrics from the render onto the request.
;
req.fetchMetrics = fetchMetrics;
// we don't throw static to dynamic errors in dev as isSSG
// is a best guess in dev since we don't have the prerender pass
// to know whether the path is actually static or not
if (isSSG && (cacheControl == null ? void 0 : cacheControl.revalidate) === 0 && !routeModule.isDev && !isRoutePPREnabled) {
const staticBailoutInfo = metadata.staticBailoutInfo;
const err = Object.defineProperty(new Error(`Page changed from static to dynamic at runtime ${resolvedPathname}${(staticBailoutInfo == null ? void 0 : staticBailoutInfo.description) ? `, reason: ${staticBailoutInfo.description}` : ``}` + `\nsee more here https://nextjs.org/docs/messages/app-static-to-dynamic-error`), "__NEXT_ERROR_CODE", {
value: "E132",
enumerable: false,
configurable: true
});
if (staticBailoutInfo == null ? void 0 : staticBailoutInfo.stack) {
const stack = staticBailoutInfo.stack;
err.stack = err.message + stack.substring(stack.indexOf('\n'));
}
throw err;
}
return {
value: {
kind: _responsecache.CachedRouteKind.APP_PAGE,
html: result,
headers,
rscData: metadata.flightData,
postponed: metadata.postponed,
status: metadata.statusCode,
segmentData: metadata.segmentData
},
cacheControl
};
};
const responseGenerator = async ({ hasResolved, previousCacheEntry: previousIncrementalCacheEntry, isRevalidating, span, forceStaticRender = false })=>{
const isProduction = routeModule.isDev === false;
const didRespond = hasResolved || res.writableEnded;
// skip on-demand revalidate if cache is not present and
// revalidate-if-generated is set
if (isOnDemandRevalidate && revalidateOnlyGenerated && !previousIncrementalCacheEntry && !isMinimalMode) {
if (routerServerContext == null ? void 0 : routerServerContext.render404) {
await routerServerContext.render404(req, res);
} else {
res.statusCode = 404;
res.end('This page could not be found');
}
return null;
}
let fallbackMode;
if (prerenderInfo) {
fallbackMode = (0, _fallback.parseFallbackField)(prerenderInfo.fallback);
}
if (nextConfig.experimental.partialFallbacks === true && (prerenderInfo == null ? void 0 : prerenderInfo.fallback) === null && !hasUnresolvedRootFallbackParams && remainingPrerenderableParams.length > 0) {
// Generic source shells without unresolved root params don't have a
// concrete fallback file of their own, so they're marked as blocking.
// When we can complete the shell into a more specific
// prerendered shell for this request, treat it like a prerender
// fallback so we can serve that shell instead of blocking on the full
// route. Root-param shells stay blocking, since unknown root branches
// should not inherit a shell from another generated branch.
fallbackMode = _fallback.FallbackMode.PRERENDER;
}
// When serving a HTML bot request, we want to serve a blocking render and
// not the prerendered page. This ensures that the correct content is served
// to the bot in the head.
if (fallbackMode === _fallback.FallbackMode.PRERENDER && (0, _isbot.isBot)(userAgent)) {
if (!isRoutePPREnabled || isHtmlBot) {
fallbackMode = _fallback.FallbackMode.BLOCKING_STATIC_RENDER;
}
}
if ((previousIncrementalCacheEntry == null ? void 0 : previousIncrementalCacheEntry.isStale) === -1) {
isOnDemandRevalidate = true;
}
// TODO: adapt for PPR
// only allow on-demand revalidate for fallback: true/blocking
// or for prerendered fallback: false paths
if (isOnDemandRevalidate && (fallbackMode !== _fallback.FallbackMode.NOT_FOUND || previousIncrementalCacheEntry)) {
fallbackMode = _fallback.FallbackMode.BLOCKING_STATIC_RENDER;
}
if (!isMinimalMode && fallbackMode !== _fallback.FallbackMode.BLOCKING_STATIC_RENDER && staticPathKey && !didRespond && !isDraftMode && pageIsDynamic && (isProduction || !isPrerendered)) {
// if the page has dynamicParams: false and this pathname wasn't
// prerendered trigger the no fallback handling
if (// In development, fall through to render to handle missing
// getStaticPaths.
(isProduction || prerenderInfo) && // When fallback isn't present, abort this render so we 404
fallbackMode === _fallback.FallbackMode.NOT_FOUND) {
if (nextConfig.adapterPath) {
return await render404();
}
throw new _nofallbackerrorexternal.NoFallbackError();
}
// When cacheComponents is enabled, we can use the fallback
// response if the request is not a dynamic RSC request because the
// RSC data when this feature flag is enabled does not contain any
// param references. Without this feature flag enabled, the RSC data
// contains param references, and therefore we can't use the fallback.
if (isRoutePPREnabled && (nextConfig.cacheComponents ? !isDynamicRSCRequest : !isRSCRequest)) {
const cacheKey = isProduction && typeof (prerenderInfo == null ? void 0 : prerenderInfo.fallback) === 'string' ? prerenderInfo.fallback : normalizedSrcPage;
const fallbackRouteParams = // In production or when debugging the static shell (e.g. instant
// navigation testing), use the prerender manifest's fallback
// route params which correctly identifies which params are
// unknown. Note: in dev, this block is only entered for
// non-prerendered URLs (guarded by the outer condition).
(isProduction || isDebugStaticShell) && (prerenderInfo == null ? void 0 : prerenderInfo.fallbackRouteParams) ? (0, _fallbackparams.createOpaqueFallbackRouteParams)(prerenderInfo.fallbackRouteParams) : // fallback (simulating the worst-case shell).
isDebugFallbackShell ? (0, _fallbackparams.getFallbackRouteParams)(normalizedSrcPage, routeModule) : null;
// When rendering a debug static shell, override the fallback
// params on the request so that the staged rendering correctly
// defers params that are not statically known.
if (isDebugStaticShell && fallbackRouteParams) {
(0, _requestmeta.addRequestMeta)(req, 'fallbackParams', fallbackRouteParams);
}
// We use the response cache here to handle the revalidation and
// management of the fallback shell.
const fallbackResponse = await routeModule.handleResponse({
cacheKey,
req,
nextConfig,
routeKind: _routekind.RouteKind.APP_PAGE,
isFallback: true,
prerenderManifest,
isRoutePPREnabled,
responseGenerator: async ()=>doRender({
span,
// We pass `undefined` as rendering a fallback isn't resumed
// here.
postponed: undefined,
// Always serve the shell that matched this request
// immediately. If there are still prerenderable params left,
// the background path below will complete the shell into a
// more specific cache entry for later requests.
fallbackRouteParams,
forceStaticRender: true
}),
waitUntil: ctx.waitUntil,
isMinimalMode
});
// If the fallback response was set to null, then we should return null.
if (fallbackResponse === null) return null;
// Otherwise, if we did get a fallback response, we should return it.
if (fallbackResponse) {
if (!isMinimalMode && isRoutePPREnabled && // Match the build-time contract: only fallback shells that can
// still be completed with prerenderable params should upgrade.
remainingPrerenderableParams.length > 0 && nextConfig.experimental.partialFallbacks === true && ssgCacheKey && incrementalCache && !isOnDemandRevalidate && !isDebugFallbackShell && // The testing API relies on deterministic shell behavior, so
// don't upgrade fallback shells in the background when it's
// exposed.
!exposeTestingApi && // Instant Navigation Testing API requests intentionally keep
// the route in shell mode; don't upgrade these in background.
!isInstantNavigationTest && // Avoid background revalidate during prefetches; this can trigger
// static prerender errors that surface as 500s for the prefetch
// request itself.
!isPrefetchRSCRequest) {
(0, _scheduler.scheduleOnNextTick)(async ()=>{
const responseCache = routeModule.getResponseCache(req);
try {
// Only the params that were just specialized should be
// removed from the fallback render. Any remaining fallback
// params stay deferred so the revalidated result is a more
// specific shell (e.g. `/prefix/c/[two]`), not a fully
// concrete route (`/prefix/c/foo`).
await responseCache.revalidate(ssgCacheKey, incrementalCache, isRoutePPREnabled, false, (c)=>{
return doRender({
span: c.span,
postponed: undefined,
fallbackRouteParams: remainingFallbackRouteParams.length > 0 ? (0, _fallbackparams.createOpaqueFallbackRouteParams)(remainingFallbackRouteParams) : null,
forceStaticRender: true
});
}, // We don't have a prior entry for this param-specific shell.
null, hasResolved, ctx.waitUntil);
} catch (err) {
console.error('Error revalidating the page in the background', err);
}
});
}
// Remove the cache control from the response to prevent it from being
// used in the surrounding cache.
delete fallbackResponse.cacheControl;
return fallbackResponse;
}
}
}
// Only requests that aren't revalidating can be resumed. If we have the
// minimal postponed data, then we should resume the render with it.
let postponed = !isOnDemandRevalidate && !isRevalidating && minimalPostponed ? minimalPostponed : undefined;
// If this is a dynamic RSC request or a server action request, we should
// use the postponed data from the static render (if available). This
// ensures that we can utilize the resume data cache (RDC) from the static
// render to ensure that the data is consistent between the static and
// dynamic renders (for navigations) or when re-rendering after a server
// action.
if (// Only enable RDC for Navigations if the feature is enabled.
supportsRDCForNavigations && process.env.NEXT_RUNTIME !== 'edge' && !isMinimalMode && incrementalCache && // Include both dynamic RSC requests (navigations) and server actions
(isDynamicRSCRequest || isPossibleServerAction) && // We don't typically trigger an on-demand revalidation for dynamic RSC
// requests, as we're typically revalidating the page in the background
// instead. However, if the cache entry is stale, we should trigger a
// background revalidation on dynamic RSC requests. This prevents us
// from entering an infinite loop of revalidations.
!forceStaticRender) {
const incrementalCacheEntry = await incrementalCache.get(resolvedPathname, {
kind: _responsecache.IncrementalCacheKind.APP_PAGE,
isRoutePPREnabled: true,
isFallback: false
});
// If the cache entry is found, we should use the postponed data from
// the cache.
if (incrementalCacheEntry && incrementalCacheEntry.value && incrementalCacheEntry.value.kind === _responsecache.CachedRouteKind.APP_PAGE) {