"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "getHandler", {
    enumerable: true,
    get: function() {
        return getHandler;
    }
});
const _routekind = require("../../route-kind");
const _constants = require("../../lib/trace/constants");
const _tracer = require("../../lib/trace/tracer");
const _formaturl = require("../../../shared/lib/router/utils/format-url");
const _requestmeta = require("../../request-meta");
const _interopdefault = require("../../app-render/interop-default");
const _utils = require("../../instrumentation/utils");
const _normalizedatapath = require("../../../shared/lib/page-path/normalize-data-path");
const _responsecache = require("../../response-cache");
const _cachecontrol = require("../../lib/cache-control");
const _utils1 = require("../../../shared/lib/utils");
const _redirectstatus = require("../../../lib/redirect-status");
const _constants1 = require("../../../lib/constants");
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _sendpayload = require("../../send-payload");
const _renderresult = /*#__PURE__*/ _interop_require_default(require("../../render-result"));
const _utils2 = require("../../response-cache/utils");
const _nofallbackerrorexternal = require("../../../shared/lib/no-fallback-error.external");
const _redirectstatuscode = require("../../../client/components/redirect-status-code");
const _isbot = require("../../../shared/lib/router/utils/is-bot");
const _addpathprefix = require("../../../shared/lib/router/utils/add-path-prefix");
const _removetrailingslash = require("../../../shared/lib/router/utils/remove-trailing-slash");
const _deploymentid = require("../../../shared/lib/deployment-id");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const getHandler = ({ srcPage: originalSrcPage, config, userland, routeModule, isFallbackError, getStaticPaths, getStaticProps, getServerSideProps })=>{
    return async function handler(req, res, ctx) {
        var _serverFilesManifest_config_experimental, _serverFilesManifest_config;
        if (routeModule.isDev) {
            (0, _requestmeta.addRequestMeta)(req, 'devRequestTimingInternalsEnd', process.hrtime.bigint());
        }
        let srcPage = originalSrcPage;
        // 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;
        }
        const isMinimalMode = Boolean(process.env.MINIMAL_MODE || (0, _requestmeta.getRequestMeta)(req, 'minimalMode'));
        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');
            }
        };
        const { buildId, query, params, parsedUrl, originalQuery, originalPathname, buildManifest, fallbackBuildManifest, nextFontManifest, serverFilesManifest, reactLoadableManifest, prerenderManifest, isDraftMode, isOnDemandRevalidate, revalidateOnlyGenerated, locale, locales, defaultLocale, routerServerContext, nextConfig, resolvedPathname, encodedResolvedPathname } = prepareResult;
        const isExperimentalCompile = serverFilesManifest == null ? void 0 : (_serverFilesManifest_config = serverFilesManifest.config) == null ? void 0 : (_serverFilesManifest_config_experimental = _serverFilesManifest_config.experimental) == null ? void 0 : _serverFilesManifest_config_experimental.isExperimentalCompile;
        const hasServerProps = Boolean(getServerSideProps);
        const hasStaticProps = Boolean(getStaticProps);
        const hasStaticPaths = Boolean(getStaticPaths);
        const hasGetInitialProps = Boolean((userland.default || userland).getInitialProps);
        let cacheKey = null;
        let isIsrFallback = false;
        let isNextDataRequest = prepareResult.isNextDataRequest && (hasStaticProps || hasServerProps);
        const is404Page = srcPage === '/404';
        const is500Page = srcPage === '/500';
        const isErrorPage = srcPage === '/_error';
        if (!routeModule.isDev && !isDraftMode && hasStaticProps) {
            cacheKey = `${locale ? `/${locale}` : ''}${(srcPage === '/' || resolvedPathname === '/') && locale ? '' : resolvedPathname}`;
            if (is404Page || is500Page || isErrorPage) {
                cacheKey = `${locale ? `/${locale}` : ''}${srcPage}`;
            }
            // ensure /index and / is normalized to one key
            cacheKey = cacheKey === '/index' ? '/' : cacheKey;
        }
        if (hasStaticPaths && !isDraftMode) {
            const decodedPathname = (0, _removetrailingslash.removeTrailingSlash)(locale ? (0, _addpathprefix.addPathPrefix)(resolvedPathname, `/${locale}`) : resolvedPathname);
            const isPrerendered = Boolean(prerenderManifest.routes[decodedPathname]) || prerenderManifest.notFoundRoutes.includes(decodedPathname);
            const prerenderInfo = prerenderManifest.dynamicRoutes[srcPage];
            if (prerenderInfo) {
                if (prerenderInfo.fallback === false && !isPrerendered) {
                    if (nextConfig.experimental.adapterPath) {
                        return await render404();
                    }
                    throw new _nofallbackerrorexternal.NoFallbackError();
                }
                if (typeof prerenderInfo.fallback === 'string' && !isPrerendered && !isNextDataRequest) {
                    isIsrFallback = true;
                }
            }
        }
        // When serving a 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 (isIsrFallback && (0, _isbot.isBot)(req.headers['user-agent'] || '') || isMinimalMode) {
            isIsrFallback = false;
        }
        const tracer = (0, _tracer.getTracer)();
        const activeSpan = tracer.getActiveScopeSpan();
        try {
            var _parsedUrl_pathname;
            const method = req.method || 'GET';
            const resolvedUrl = (0, _formaturl.formatUrl)({
                pathname: nextConfig.trailingSlash ? `${encodedResolvedPathname}${!encodedResolvedPathname.endsWith('/') && ((_parsedUrl_pathname = parsedUrl.pathname) == null ? void 0 : _parsedUrl_pathname.endsWith('/')) ? '/' : ''}` : (0, _removetrailingslash.removeTrailingSlash)(encodedResolvedPathname || '/'),
                // make sure to only add query values from original URL
                query: hasStaticProps ? {} : originalQuery
            });
            const handleResponse = async (span)=>{
                const responseGenerator = async ({ previousCacheEntry })=>{
                    var _previousCacheEntry_value;
                    const doRender = async ()=>{
                        try {
                            var _nextConfig_i18n;
                            return await routeModule.render(req, res, {
                                query: hasStaticProps && !isExperimentalCompile ? {
                                    ...params
                                } : {
                                    ...query,
                                    ...params
                                },
                                params,
                                page: srcPage,
                                renderContext: {
                                    isDraftMode,
                                    isFallback: isIsrFallback,
                                    developmentNotFoundSourcePage: (0, _requestmeta.getRequestMeta)(req, 'developmentNotFoundSourcePage')
                                },
                                sharedContext: {
                                    buildId,
                                    customServer: Boolean(routerServerContext == null ? void 0 : routerServerContext.isCustomServer) || undefined,
                                    deploymentId: (0, _deploymentid.getDeploymentId)()
                                },
                                renderOpts: {
                                    params,
                                    routeModule,
                                    page: srcPage,
                                    pageConfig: config || {},
                                    Component: (0, _interopdefault.interopDefault)(userland),
                                    ComponentMod: userland,
                                    getStaticProps,
                                    getStaticPaths,
                                    getServerSideProps,
                                    supportsDynamicResponse: !hasStaticProps,
                                    buildManifest: isFallbackError ? fallbackBuildManifest : buildManifest,
                                    nextFontManifest,
                                    reactLoadableManifest,
                                    assetPrefix: nextConfig.assetPrefix,
                                    previewProps: prerenderManifest.preview,
                                    images: nextConfig.images,
                                    nextConfigOutput: nextConfig.output,
                                    optimizeCss: Boolean(nextConfig.experimental.optimizeCss),
                                    nextScriptWorkers: Boolean(nextConfig.experimental.nextScriptWorkers),
                                    domainLocales: (_nextConfig_i18n = nextConfig.i18n) == null ? void 0 : _nextConfig_i18n.domains,
                                    crossOrigin: nextConfig.crossOrigin,
                                    multiZoneDraftMode,
                                    basePath: nextConfig.basePath,
                                    disableOptimizedLoading: nextConfig.experimental.disableOptimizedLoading,
                                    largePageDataBytes: nextConfig.experimental.largePageDataBytes,
                                    isExperimentalCompile,
                                    experimental: {
                                        clientTraceMetadata: nextConfig.experimental.clientTraceMetadata || []
                                    },
                                    locale,
                                    locales,
                                    defaultLocale,
                                    setIsrStatus: routerServerContext == null ? void 0 : routerServerContext.setIsrStatus,
                                    isNextDataRequest: isNextDataRequest && (hasServerProps || hasStaticProps),
                                    resolvedUrl,
                                    // For getServerSideProps and getInitialProps we need to ensure we use the original URL
                                    // and not the resolved URL to prevent a hydration mismatch on
                                    // asPath
                                    resolvedAsPath: hasServerProps || hasGetInitialProps ? (0, _formaturl.formatUrl)({
                                        // we use the original URL pathname less the _next/data prefix if
                                        // present
                                        pathname: isNextDataRequest ? (0, _normalizedatapath.normalizeDataPath)(originalPathname) : originalPathname,
                                        query: originalQuery
                                    }) : resolvedUrl,
                                    isOnDemandRevalidate,
                                    ErrorDebug: (0, _requestmeta.getRequestMeta)(req, 'PagesErrorDebug'),
                                    err: (0, _requestmeta.getRequestMeta)(req, 'invokeError'),
                                    dev: routeModule.isDev,
                                    // needed for experimental.optimizeCss feature
                                    distDir: _path.default.join(/* turbopackIgnore: true */ process.cwd(), routeModule.relativeProjectDir, routeModule.distDir)
                                }
                            }).then((renderResult)=>{
                                const { metadata } = renderResult;
                                let cacheControl = metadata.cacheControl;
                                if ('isNotFound' in metadata && metadata.isNotFound) {
                                    return {
                                        value: null,
                                        cacheControl
                                    };
                                }
                                // Handle `isRedirect`.
                                if (metadata.isRedirect) {
                                    return {
                                        value: {
                                            kind: _responsecache.CachedRouteKind.REDIRECT,
                                            props: metadata.pageData ?? metadata.flightData
                                        },
                                        cacheControl
                                    };
                                }
                                return {
                                    value: {
                                        kind: _responsecache.CachedRouteKind.PAGES,
                                        html: renderResult,
                                        pageData: renderResult.metadata.pageData,
                                        headers: renderResult.metadata.headers,
                                        status: renderResult.metadata.statusCode
                                    },
                                    cacheControl
                                };
                            }).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);
                                } else {
                                    span.updateName(`${method} ${srcPage}`);
                                }
                            });
                        } catch (err) {
                            // if this is a background revalidate we need to report
                            // the request error here as it won't be bubbled
                            if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) {
                                const silenceLog = false;
                                await routeModule.onRequestError(req, err, {
                                    routerKind: 'Pages Router',
                                    routePath: srcPage,
                                    routeType: 'render',
                                    revalidateReason: (0, _utils.getRevalidateReason)({
                                        isStaticGeneration: hasStaticProps,
                                        isOnDemandRevalidate
                                    })
                                }, silenceLog, routerServerContext);
                            }
                            throw err;
                        }
                    };
                    // if we've already generated this page we no longer
                    // serve the fallback
                    if (previousCacheEntry) {
                        isIsrFallback = false;
                    }
                    if (isIsrFallback) {
                        const fallbackResponse = await routeModule.getResponseCache(req).get(routeModule.isDev ? null : locale ? `/${locale}${srcPage}` : srcPage, async ({ previousCacheEntry: previousFallbackCacheEntry = null })=>{
                            if (!routeModule.isDev) {
                                return (0, _utils2.toResponseCacheEntry)(previousFallbackCacheEntry);
                            }
                            return doRender();
                        }, {
                            routeKind: _routekind.RouteKind.PAGES,
                            isFallback: true,
                            isRoutePPREnabled: false,
                            isOnDemandRevalidate: false,
                            incrementalCache: await routeModule.getIncrementalCache(req, nextConfig, prerenderManifest, isMinimalMode),
                            waitUntil: ctx.waitUntil
                        });
                        if (fallbackResponse) {
                            // Remove the cache control from the response to prevent it from being
                            // used in the surrounding cache.
                            delete fallbackResponse.cacheControl;
                            fallbackResponse.isMiss = true;
                            return fallbackResponse;
                        }
                    }
                    if (!isMinimalMode && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) {
                        res.statusCode = 404;
                        // on-demand revalidate always sets this header
                        res.setHeader('x-nextjs-cache', 'REVALIDATED');
                        res.end('This page could not be found');
                        return null;
                    }
                    if (isIsrFallback && (previousCacheEntry == null ? void 0 : (_previousCacheEntry_value = previousCacheEntry.value) == null ? void 0 : _previousCacheEntry_value.kind) === _responsecache.CachedRouteKind.PAGES) {
                        return {
                            value: {
                                kind: _responsecache.CachedRouteKind.PAGES,
                                html: new _renderresult.default(Buffer.from(previousCacheEntry.value.html), {
                                    contentType: _constants1.HTML_CONTENT_TYPE_HEADER,
                                    metadata: {
                                        statusCode: previousCacheEntry.value.status,
                                        headers: previousCacheEntry.value.headers
                                    }
                                }),
                                pageData: {},
                                status: previousCacheEntry.value.status,
                                headers: previousCacheEntry.value.headers
                            },
                            cacheControl: {
                                revalidate: 0,
                                expire: undefined
                            }
                        };
                    }
                    return doRender();
                };
                const result = await routeModule.handleResponse({
                    cacheKey,
                    req,
                    nextConfig,
                    routeKind: _routekind.RouteKind.PAGES,
                    isOnDemandRevalidate,
                    revalidateOnlyGenerated,
                    waitUntil: ctx.waitUntil,
                    responseGenerator: responseGenerator,
                    prerenderManifest,
                    isMinimalMode
                });
                // if we got a cache hit this wasn't an ISR fallback
                // but it wasn't generated during build so isn't in the
                // prerender-manifest
                if (isIsrFallback && !(result == null ? void 0 : result.isMiss)) {
                    isIsrFallback = false;
                }
                // response is finished is no cache entry
                if (!result) {
                    return;
                }
                if (hasStaticProps && !isMinimalMode) {
                    res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : result.isMiss ? 'MISS' : result.isStale ? 'STALE' : 'HIT');
                }
                let cacheControl;
                if (!hasStaticProps || isIsrFallback) {
                    if (!res.getHeader('Cache-Control')) {
                        cacheControl = {
                            revalidate: 0,
                            expire: undefined
                        };
                    }
                } else if (is404Page) {
                    const notFoundRevalidate = (0, _requestmeta.getRequestMeta)(req, 'notFoundRevalidate');
                    cacheControl = {
                        revalidate: typeof notFoundRevalidate === 'undefined' ? 0 : notFoundRevalidate,
                        expire: undefined
                    };
                } else if (is500Page) {
                    cacheControl = {
                        revalidate: 0,
                        expire: undefined
                    };
                } else if (result.cacheControl) {
                    // If the cache entry has a cache control with a revalidate value that's
                    // a number, use it.
                    if (typeof result.cacheControl.revalidate === 'number') {
                        var _result_cacheControl;
                        if (result.cacheControl.revalidate < 1) {
                            throw Object.defineProperty(new Error(`Invalid revalidate configuration provided: ${result.cacheControl.revalidate} < 1`), "__NEXT_ERROR_CODE", {
                                value: "E22",
                                enumerable: false,
                                configurable: true
                            });
                        }
                        cacheControl = {
                            revalidate: result.cacheControl.revalidate,
                            expire: ((_result_cacheControl = result.cacheControl) == null ? void 0 : _result_cacheControl.expire) ?? nextConfig.expireTime
                        };
                    } else {
                        // revalidate: false
                        cacheControl = {
                            revalidate: _constants1.CACHE_ONE_YEAR,
                            expire: undefined
                        };
                    }
                }
                // If cache control is already set on the response we don't
                // override it to allow users to customize it via next.config
                if (cacheControl && !res.getHeader('Cache-Control')) {
                    res.setHeader('Cache-Control', (0, _cachecontrol.getCacheControlHeader)(cacheControl));
                }
                // notFound: true case
                if (!result.value) {
                    var _result_cacheControl1;
                    // add revalidate metadata before rendering 404 page
                    // so that we can use this as source of truth for the
                    // cache-control header instead of what the 404 page returns
                    // for the revalidate value
                    (0, _requestmeta.addRequestMeta)(req, 'notFoundRevalidate', (_result_cacheControl1 = result.cacheControl) == null ? void 0 : _result_cacheControl1.revalidate);
                    res.statusCode = 404;
                    if (isNextDataRequest) {
                        res.end('{"notFound":true}');
                        return;
                    }
                    return await render404();
                }
                if (result.value.kind === _responsecache.CachedRouteKind.REDIRECT) {
                    if (isNextDataRequest) {
                        res.setHeader('content-type', _constants1.JSON_CONTENT_TYPE_HEADER);
                        res.end(JSON.stringify(result.value.props));
                        return;
                    } else {
                        const handleRedirect = (pageData)=>{
                            const redirect = {
                                destination: pageData.pageProps.__N_REDIRECT,
                                statusCode: pageData.pageProps.__N_REDIRECT_STATUS,
                                basePath: pageData.pageProps.__N_REDIRECT_BASE_PATH
                            };
                            const statusCode = (0, _redirectstatus.getRedirectStatus)(redirect);
                            const { basePath } = nextConfig;
                            if (basePath && redirect.basePath !== false && redirect.destination.startsWith('/')) {
                                redirect.destination = `${basePath}${redirect.destination}`;
                            }
                            if (redirect.destination.startsWith('/')) {
                                redirect.destination = (0, _utils1.normalizeRepeatedSlashes)(redirect.destination);
                            }
                            res.statusCode = statusCode;
                            res.setHeader('Location', redirect.destination);
                            if (statusCode === _redirectstatuscode.RedirectStatusCode.PermanentRedirect) {
                                res.setHeader('Refresh', `0;url=${redirect.destination}`);
                            }
                            res.end(redirect.destination);
                        };
                        await handleRedirect(result.value.props);
                        return null;
                    }
                }
                if (result.value.kind !== _responsecache.CachedRouteKind.PAGES) {
                    throw Object.defineProperty(new Error(`Invariant: received non-pages cache entry in pages handler`), "__NEXT_ERROR_CODE", {
                        value: "E695",
                        enumerable: false,
                        configurable: true
                    });
                }
                // In dev, we should not cache pages for any reason.
                if (routeModule.isDev) {
                    res.setHeader('Cache-Control', 'no-store, must-revalidate');
                }
                // Draft mode should never be cached
                if (isDraftMode) {
                    res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate');
                }
                // when invoking _error before pages/500 we don't actually
                // send the _error response
                if ((0, _requestmeta.getRequestMeta)(req, 'customErrorRender') || isErrorPage && isMinimalMode && res.statusCode === 500) {
                    return null;
                }
                await (0, _sendpayload.sendRenderResult)({
                    req,
                    res,
                    // If we are rendering the error page it's not a data request
                    // anymore
                    result: isNextDataRequest && !isErrorPage && !is500Page ? new _renderresult.default(Buffer.from(JSON.stringify(result.value.pageData)), {
                        contentType: _constants1.JSON_CONTENT_TYPE_HEADER,
                        metadata: result.value.html.metadata
                    }) : result.value.html,
                    generateEtags: nextConfig.generateEtags,
                    poweredByHeader: nextConfig.poweredByHeader,
                    cacheControl: routeModule.isDev ? undefined : cacheControl
                });
            };
            // TODO: activeSpan code path is for when wrapped by
            // next-server can be removed when this is no longer used
            if (activeSpan) {
                await handleResponse();
            } else {
                await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(_constants.BaseServerSpan.handleRequest, {
                        spanName: `${method} ${srcPage}`,
                        kind: _tracer.SpanKind.SERVER,
                        attributes: {
                            'http.method': method,
                            'http.target': req.url
                        }
                    }, handleResponse));
            }
        } catch (err) {
            if (!(err instanceof _nofallbackerrorexternal.NoFallbackError)) {
                const silenceLog = false;
                await routeModule.onRequestError(req, err, {
                    routerKind: 'Pages Router',
                    routePath: srcPage,
                    routeType: 'render',
                    revalidateReason: (0, _utils.getRevalidateReason)({
                        isStaticGeneration: hasStaticProps,
                        isOnDemandRevalidate
                    })
                }, silenceLog, routerServerContext);
            }
            // rethrow so that we can handle serving error page
            throw err;
        }
    };
};

//# sourceMappingURL=pages-handler.js.map