"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
var _exportNames = {};
exports.default = void 0;
require("./node-polyfill-fetch");
require("./node-polyfill-web-streams");
var _utils = require("../shared/lib/utils");
var _fs = _interopRequireDefault(require("fs"));
var _path = require("path");
var _http = require("http");
var _react = _interopRequireDefault(require("react"));
var _requestMeta = require("./request-meta");
var _constants = require("../shared/lib/constants");
var _recursiveReaddirSync = require("./lib/recursive-readdir-sync");
var _url = require("url");
var _compression = _interopRequireDefault(require("next/dist/compiled/compression"));
var _httpProxy = _interopRequireDefault(require("next/dist/compiled/http-proxy"));
var _pathMatch = require("../shared/lib/router/utils/path-match");
var _sandbox = require("./web/sandbox");
var _node = require("./base-http/node");
var _sendPayload = require("./send-payload");
var _serveStatic = require("./serve-static");
var _node1 = require("./api-utils/node");
var _render = require("./render");
var _appRender = require("./app-render");
var _parseUrl = require("../shared/lib/router/utils/parse-url");
var Log = _interopRequireWildcard(require("../build/output/log"));
var _baseServer = _interopRequireWildcard(require("./base-server"));
Object.keys(_baseServer).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
    if (key in exports && exports[key] === _baseServer[key]) return;
    Object.defineProperty(exports, key, {
        enumerable: true,
        get: function() {
            return _baseServer[key];
        }
    });
});
var _require = require("./require");
var _denormalizePagePath = require("../shared/lib/page-path/denormalize-page-path");
var _normalizePagePath = require("../shared/lib/page-path/normalize-page-path");
var _loadComponents = require("./load-components");
var _isError = _interopRequireWildcard(require("../lib/is-error"));
var _utils1 = require("./web/utils");
var _relativizeUrl = require("../shared/lib/router/utils/relativize-url");
var _prepareDestination = require("../shared/lib/router/utils/prepare-destination");
var _normalizeLocalePath = require("../shared/lib/i18n/normalize-locale-path");
var _routeMatcher = require("../shared/lib/router/utils/route-matcher");
var _env = require("@next/env");
var _serverRouteUtils = require("./server-route-utils");
var _querystring = require("../shared/lib/router/utils/querystring");
var _responseCache = _interopRequireDefault(require("../server/response-cache"));
var _removeTrailingSlash = require("../shared/lib/router/utils/remove-trailing-slash");
var _bodyStreams = require("./body-streams");
var _getNextPathnameInfo = require("../shared/lib/router/utils/get-next-pathname-info");
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _interopRequireWildcard(obj) {
    if (obj && obj.__esModule) {
        return obj;
    } else {
        var newObj = {};
        if (obj != null) {
            for(var key in obj){
                if (Object.prototype.hasOwnProperty.call(obj, key)) {
                    var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
                    if (desc.get || desc.set) {
                        Object.defineProperty(newObj, key, desc);
                    } else {
                        newObj[key] = obj[key];
                    }
                }
            }
        }
        newObj.default = obj;
        return newObj;
    }
}
const shouldUseReactRoot = parseInt(_react.default.version) >= 18;
if (shouldUseReactRoot) {
    process.env.__NEXT_REACT_ROOT = 'true';
}
const middlewareBetaWarning = (0, _utils).execOnce(()=>{
    Log.warn(`using beta Middleware (not covered by semver) - https://nextjs.org/docs/messages/beta-middleware`);
});
class NextNodeServer extends _baseServer.default {
    constructor(options){
        // Initialize super class
        super(options);
        this.compression = this.nextConfig.compress && this.nextConfig.target === 'server' ? (0, _compression).default() : undefined;
        this._validFilesystemPathSet = null;
        /**
     * This sets environment variable to be used at the time of SSR by head.tsx.
     * Using this from process.env allows targeting both serverless and SSR by calling
     * `process.env.__NEXT_OPTIMIZE_CSS`.
     */ if (this.renderOpts.optimizeFonts) {
            process.env.__NEXT_OPTIMIZE_FONTS = JSON.stringify(true);
        }
        if (this.renderOpts.optimizeCss) {
            process.env.__NEXT_OPTIMIZE_CSS = JSON.stringify(true);
        }
        if (this.renderOpts.nextScriptWorkers) {
            process.env.__NEXT_SCRIPT_WORKERS = JSON.stringify(true);
        }
        if (!this.minimalMode) {
            const { ImageOptimizerCache  } = require('./image-optimizer');
            this.imageResponseCache = new _responseCache.default(new ImageOptimizerCache({
                distDir: this.distDir,
                nextConfig: this.nextConfig
            }), this.minimalMode);
        }
        if (!options.dev) {
            // pre-warm _document and _app as these will be
            // needed for most requests
            (0, _loadComponents).loadComponents(this.distDir, '/_document', this._isLikeServerless).catch(()=>{});
            (0, _loadComponents).loadComponents(this.distDir, '/_app', this._isLikeServerless).catch(()=>{});
        }
    }
    loadEnvConfig({ dev  }) {
        (0, _env).loadEnvConfig(this.dir, dev, Log);
    }
    getPublicDir() {
        return (0, _path).join(this.dir, _constants.CLIENT_PUBLIC_FILES_PATH);
    }
    getHasStaticDir() {
        return _fs.default.existsSync((0, _path).join(this.dir, 'static'));
    }
    getPagesManifest() {
        return require((0, _path).join(this.serverDistDir, _constants.PAGES_MANIFEST));
    }
    getAppPathsManifest() {
        if (this.nextConfig.experimental.appDir) {
            const appPathsManifestPath = (0, _path).join(this.serverDistDir, _constants.APP_PATHS_MANIFEST);
            return require(appPathsManifestPath);
        }
    }
    getBuildId() {
        const buildIdFile = (0, _path).join(this.distDir, _constants.BUILD_ID_FILE);
        try {
            return _fs.default.readFileSync(buildIdFile, 'utf8').trim();
        } catch (err) {
            if (!_fs.default.existsSync(buildIdFile)) {
                throw new Error(`Could not find a production build in the '${this.distDir}' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id`);
            }
            throw err;
        }
    }
    generateImageRoutes() {
        return [
            {
                match: (0, _pathMatch).getPathMatch('/_next/image'),
                type: 'route',
                name: '_next/image catchall',
                fn: async (req, res, _params, parsedUrl)=>{
                    if (this.minimalMode) {
                        res.statusCode = 400;
                        res.body('Bad Request').send();
                        return {
                            finished: true
                        };
                    }
                    const { getHash , ImageOptimizerCache , sendResponse , ImageError  } = require('./image-optimizer');
                    if (!this.imageResponseCache) {
                        throw new Error('invariant image optimizer cache was not initialized');
                    }
                    const imagesConfig = this.nextConfig.images;
                    if (imagesConfig.loader !== 'default') {
                        await this.render404(req, res);
                        return {
                            finished: true
                        };
                    }
                    const paramsResult = ImageOptimizerCache.validateParams(req.originalRequest, parsedUrl.query, this.nextConfig, !!this.renderOpts.dev);
                    if ('errorMessage' in paramsResult) {
                        res.statusCode = 400;
                        res.body(paramsResult.errorMessage).send();
                        return {
                            finished: true
                        };
                    }
                    const cacheKey = ImageOptimizerCache.getCacheKey(paramsResult);
                    try {
                        var ref;
                        const cacheEntry = await this.imageResponseCache.get(cacheKey, async ()=>{
                            const { buffer , contentType , maxAge  } = await this.imageOptimizer(req, res, paramsResult);
                            const etag = getHash([
                                buffer
                            ]);
                            return {
                                value: {
                                    kind: 'IMAGE',
                                    buffer,
                                    etag,
                                    extension: (0, _serveStatic).getExtension(contentType)
                                },
                                revalidate: maxAge
                            };
                        }, {});
                        if ((cacheEntry === null || cacheEntry === void 0 ? void 0 : (ref = cacheEntry.value) === null || ref === void 0 ? void 0 : ref.kind) !== 'IMAGE') {
                            throw new Error('invariant did not get entry from image response cache');
                        }
                        sendResponse(req.originalRequest, res.originalResponse, paramsResult.href, cacheEntry.value.extension, cacheEntry.value.buffer, paramsResult.isStatic, cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT', imagesConfig.contentSecurityPolicy);
                    } catch (err) {
                        if (err instanceof ImageError) {
                            res.statusCode = err.statusCode;
                            res.body(err.message).send();
                            return {
                                finished: true
                            };
                        }
                        throw err;
                    }
                    return {
                        finished: true
                    };
                }
            }, 
        ];
    }
    generateStaticRoutes() {
        return this.hasStaticDir ? [
            {
                // It's very important to keep this route's param optional.
                // (but it should support as many params as needed, separated by '/')
                // Otherwise this will lead to a pretty simple DOS attack.
                // See more: https://github.com/vercel/next.js/issues/2617
                match: (0, _pathMatch).getPathMatch('/static/:path*'),
                name: 'static catchall',
                fn: async (req, res, params, parsedUrl)=>{
                    const p = (0, _path).join(this.dir, 'static', ...params.path);
                    await this.serveStatic(req, res, p, parsedUrl);
                    return {
                        finished: true
                    };
                }
            }, 
        ] : [];
    }
    setImmutableAssetCacheControl(res) {
        res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
    }
    generateFsStaticRoutes() {
        return [
            {
                match: (0, _pathMatch).getPathMatch('/_next/static/:path*'),
                type: 'route',
                name: '_next/static catchall',
                fn: async (req, res, params, parsedUrl)=>{
                    // make sure to 404 for /_next/static itself
                    if (!params.path) {
                        await this.render404(req, res, parsedUrl);
                        return {
                            finished: true
                        };
                    }
                    if (params.path[0] === _constants.CLIENT_STATIC_FILES_RUNTIME || params.path[0] === 'chunks' || params.path[0] === 'css' || params.path[0] === 'image' || params.path[0] === 'media' || params.path[0] === this.buildId || params.path[0] === 'pages' || params.path[1] === 'pages') {
                        this.setImmutableAssetCacheControl(res);
                    }
                    const p = (0, _path).join(this.distDir, _constants.CLIENT_STATIC_FILES_PATH, ...params.path || []);
                    await this.serveStatic(req, res, p, parsedUrl);
                    return {
                        finished: true
                    };
                }
            }, 
        ];
    }
    generatePublicRoutes() {
        if (!_fs.default.existsSync(this.publicDir)) return [];
        const publicFiles = new Set((0, _recursiveReaddirSync).recursiveReadDirSync(this.publicDir).map((p)=>encodeURI(p.replace(/\\/g, '/'))
        ));
        return [
            {
                match: (0, _pathMatch).getPathMatch('/:path*'),
                name: 'public folder catchall',
                fn: async (req, res, params, parsedUrl)=>{
                    const pathParts = params.path || [];
                    const { basePath  } = this.nextConfig;
                    // if basePath is defined require it be present
                    if (basePath) {
                        const basePathParts = basePath.split('/');
                        // remove first empty value
                        basePathParts.shift();
                        if (!basePathParts.every((part, idx)=>{
                            return part === pathParts[idx];
                        })) {
                            return {
                                finished: false
                            };
                        }
                        pathParts.splice(0, basePathParts.length);
                    }
                    let path = `/${pathParts.join('/')}`;
                    if (!publicFiles.has(path)) {
                        // In `next-dev-server.ts`, we ensure encoded paths match
                        // decoded paths on the filesystem. So we need do the
                        // opposite here: make sure decoded paths match encoded.
                        path = encodeURI(path);
                    }
                    if (publicFiles.has(path)) {
                        await this.serveStatic(req, res, (0, _path).join(this.publicDir, ...pathParts), parsedUrl);
                        return {
                            finished: true
                        };
                    }
                    return {
                        finished: false
                    };
                }
            }, 
        ];
    }
    getFilesystemPaths() {
        if (this._validFilesystemPathSet) {
            return this._validFilesystemPathSet;
        }
        const pathUserFilesStatic = (0, _path).join(this.dir, 'static');
        let userFilesStatic = [];
        if (this.hasStaticDir && _fs.default.existsSync(pathUserFilesStatic)) {
            userFilesStatic = (0, _recursiveReaddirSync).recursiveReadDirSync(pathUserFilesStatic).map((f)=>(0, _path).join('.', 'static', f)
            );
        }
        let userFilesPublic = [];
        if (this.publicDir && _fs.default.existsSync(this.publicDir)) {
            userFilesPublic = (0, _recursiveReaddirSync).recursiveReadDirSync(this.publicDir).map((f)=>(0, _path).join('.', 'public', f)
            );
        }
        let nextFilesStatic = [];
        nextFilesStatic = !this.minimalMode && _fs.default.existsSync((0, _path).join(this.distDir, 'static')) ? (0, _recursiveReaddirSync).recursiveReadDirSync((0, _path).join(this.distDir, 'static')).map((f)=>(0, _path).join('.', (0, _path).relative(this.dir, this.distDir), 'static', f)
        ) : [];
        return this._validFilesystemPathSet = new Set([
            ...nextFilesStatic,
            ...userFilesPublic,
            ...userFilesStatic, 
        ]);
    }
    sendRenderResult(req, res, options) {
        return (0, _sendPayload).sendRenderResult({
            req: req.originalRequest,
            res: res.originalResponse,
            ...options
        });
    }
    sendStatic(req, res, path) {
        return (0, _serveStatic).serveStatic(req.originalRequest, res.originalResponse, path);
    }
    handleCompression(req, res) {
        if (this.compression) {
            this.compression(req.originalRequest, res.originalResponse, ()=>{});
        }
    }
    async proxyRequest(req, res, parsedUrl) {
        const { query  } = parsedUrl;
        delete parsedUrl.query;
        parsedUrl.search = (0, _baseServer).stringifyQuery(req, query);
        const target = (0, _url).format(parsedUrl);
        const proxy = new _httpProxy.default({
            target,
            changeOrigin: true,
            ignorePath: true,
            xfwd: true,
            proxyTimeout: 30000
        });
        await new Promise((proxyResolve, proxyReject)=>{
            let finished = false;
            proxy.on('proxyReq', (proxyReq)=>{
                proxyReq.on('close', ()=>{
                    if (!finished) {
                        finished = true;
                        proxyResolve(true);
                    }
                });
            });
            proxy.on('error', (err)=>{
                if (!finished) {
                    finished = true;
                    proxyReject(err);
                }
            });
            proxy.web(req.originalRequest, res.originalResponse);
        });
        return {
            finished: true
        };
    }
    async runApi(req, res, query, params, page, builtPagePath) {
        const pageModule = await require(builtPagePath);
        query = {
            ...query,
            ...params
        };
        delete query.__nextLocale;
        delete query.__nextDefaultLocale;
        if (!this.renderOpts.dev && this._isLikeServerless) {
            if (typeof pageModule.default === 'function') {
                (0, _baseServer).prepareServerlessUrl(req, query);
                await pageModule.default(req, res);
                return true;
            }
        }
        await (0, _node1).apiResolver(req.originalRequest, res.originalResponse, query, pageModule, {
            ...this.renderOpts.previewProps,
            revalidate: (newReq, newRes)=>this.getRequestHandler()(new _node.NodeNextRequest(newReq), new _node.NodeNextResponse(newRes))
            ,
            // internal config so is not typed
            trustHostHeader: this.nextConfig.experimental.trustHostHeader
        }, this.minimalMode, this.renderOpts.dev, page);
        return true;
    }
    async renderHTML(req, res, pathname, query, renderOpts) {
        // Due to the way we pass data by mutating `renderOpts`, we can't extend the
        // object here but only updating its `serverComponentManifest` field.
        // https://github.com/vercel/next.js/blob/df7cbd904c3bd85f399d1ce90680c0ecf92d2752/packages/next/server/render.tsx#L947-L952
        renderOpts.serverComponentManifest = this.serverComponentManifest;
        if (renderOpts.isAppPath) {
            return (0, _appRender).renderToHTML(req.originalRequest, res.originalResponse, pathname, query, renderOpts);
        }
        return (0, _render).renderToHTML(req.originalRequest, res.originalResponse, pathname, query, renderOpts);
    }
    streamResponseChunk(res, chunk) {
        res.originalResponse.write(chunk);
        // When both compression and streaming are enabled, we need to explicitly
        // flush the response to avoid it being buffered by gzip.
        if (this.compression && 'flush' in res.originalResponse) {
            res.originalResponse.flush();
        }
    }
    async imageOptimizer(req, res, paramsResult) {
        const { imageOptimizer  } = require('./image-optimizer');
        return imageOptimizer(req.originalRequest, res.originalResponse, paramsResult, this.nextConfig, (newReq, newRes, newParsedUrl)=>this.getRequestHandler()(new _node.NodeNextRequest(newReq), new _node.NodeNextResponse(newRes), newParsedUrl)
        );
    }
    getPagePath(pathname, locales) {
        return (0, _require).getPagePath(pathname, this.distDir, this._isLikeServerless, this.renderOpts.dev, locales, this.nextConfig.experimental.appDir);
    }
    async findPageComponents(pathname, query = {}, params = null) {
        let paths = [
            // try serving a static AMP version first
            query.amp ? (0, _normalizePagePath).normalizePagePath(pathname) + '.amp' : null,
            pathname, 
        ].filter(Boolean);
        if (query.__nextLocale) {
            paths = [
                ...paths.map((path)=>`/${query.__nextLocale}${path === '/' ? '' : path}`
                ),
                ...paths, 
            ];
        }
        for (const pagePath of paths){
            try {
                const components = await (0, _loadComponents).loadComponents(this.distDir, pagePath, !this.renderOpts.dev && this._isLikeServerless, this.renderOpts.serverComponents, this.nextConfig.experimental.appDir);
                if (query.__nextLocale && typeof components.Component === 'string' && !(pagePath === null || pagePath === void 0 ? void 0 : pagePath.startsWith(`/${query.__nextLocale}`))) {
                    continue;
                }
                return {
                    components,
                    query: {
                        ...components.getStaticProps ? {
                            amp: query.amp,
                            __nextDataReq: query.__nextDataReq,
                            __nextLocale: query.__nextLocale,
                            __nextDefaultLocale: query.__nextDefaultLocale,
                            __flight__: query.__flight__
                        } : query,
                        ...params || {}
                    }
                };
            } catch (err) {
                // we should only not throw if we failed to find the page
                // in the pages-manifest
                if (!(err instanceof _utils.PageNotFoundError)) {
                    throw err;
                }
            }
        }
        return null;
    }
    getFontManifest() {
        return (0, _require).requireFontManifest(this.distDir, this._isLikeServerless);
    }
    getServerComponentManifest() {
        if (!this.nextConfig.experimental.serverComponents) return undefined;
        return require((0, _path).join(this.distDir, 'server', _constants.MIDDLEWARE_FLIGHT_MANIFEST + '.json'));
    }
    getCacheFilesystem() {
        return {
            readFile: (f)=>_fs.default.promises.readFile(f, 'utf8')
            ,
            readFileSync: (f)=>_fs.default.readFileSync(f, 'utf8')
            ,
            writeFile: (f, d)=>_fs.default.promises.writeFile(f, d, 'utf8')
            ,
            mkdir: (dir)=>_fs.default.promises.mkdir(dir, {
                    recursive: true
                })
            ,
            stat: (f)=>_fs.default.promises.stat(f)
        };
    }
    normalizeReq(req) {
        return req instanceof _http.IncomingMessage ? new _node.NodeNextRequest(req) : req;
    }
    normalizeRes(res) {
        return res instanceof _http.ServerResponse ? new _node.NodeNextResponse(res) : res;
    }
    getRequestHandler() {
        const handler = super.getRequestHandler();
        return async (req, res, parsedUrl)=>{
            return handler(this.normalizeReq(req), this.normalizeRes(res), parsedUrl);
        };
    }
    async render(req, res, pathname, query, parsedUrl, internal = false) {
        return super.render(this.normalizeReq(req), this.normalizeRes(res), pathname, query, parsedUrl, internal);
    }
    async renderToHTML(req, res, pathname, query) {
        return super.renderToHTML(this.normalizeReq(req), this.normalizeRes(res), pathname, query);
    }
    async renderError(err, req, res, pathname, query, setHeaders) {
        return super.renderError(err, this.normalizeReq(req), this.normalizeRes(res), pathname, query, setHeaders);
    }
    async renderErrorToHTML(err, req, res, pathname, query) {
        return super.renderErrorToHTML(err, this.normalizeReq(req), this.normalizeRes(res), pathname, query);
    }
    async render404(req, res, parsedUrl, setHeaders) {
        return super.render404(this.normalizeReq(req), this.normalizeRes(res), parsedUrl, setHeaders);
    }
    async serveStatic(req, res, path, parsedUrl) {
        if (!this.isServeableUrl(path)) {
            return this.render404(req, res, parsedUrl);
        }
        if (!(req.method === 'GET' || req.method === 'HEAD')) {
            res.statusCode = 405;
            res.setHeader('Allow', [
                'GET',
                'HEAD'
            ]);
            return this.renderError(null, req, res, path);
        }
        try {
            await this.sendStatic(req, res, path);
        } catch (error) {
            if (!(0, _isError).default(error)) throw error;
            const err = error;
            if (err.code === 'ENOENT' || err.statusCode === 404) {
                this.render404(req, res, parsedUrl);
            } else if (err.statusCode === 412) {
                res.statusCode = 412;
                return this.renderError(err, req, res, path);
            } else {
                throw err;
            }
        }
    }
    getStaticRoutes() {
        return this.hasStaticDir ? [
            {
                // It's very important to keep this route's param optional.
                // (but it should support as many params as needed, separated by '/')
                // Otherwise this will lead to a pretty simple DOS attack.
                // See more: https://github.com/vercel/next.js/issues/2617
                match: (0, _pathMatch).getPathMatch('/static/:path*'),
                name: 'static catchall',
                fn: async (req, res, params, parsedUrl)=>{
                    const p = (0, _path).join(this.dir, 'static', ...params.path);
                    await this.serveStatic(req, res, p, parsedUrl);
                    return {
                        finished: true
                    };
                }
            }, 
        ] : [];
    }
    isServeableUrl(untrustedFileUrl) {
        // This method mimics what the version of `send` we use does:
        // 1. decodeURIComponent:
        //    https://github.com/pillarjs/send/blob/0.17.1/index.js#L989
        //    https://github.com/pillarjs/send/blob/0.17.1/index.js#L518-L522
        // 2. resolve:
        //    https://github.com/pillarjs/send/blob/de073ed3237ade9ff71c61673a34474b30e5d45b/index.js#L561
        let decodedUntrustedFilePath;
        try {
            // (1) Decode the URL so we have the proper file name
            decodedUntrustedFilePath = decodeURIComponent(untrustedFileUrl);
        } catch  {
            return false;
        }
        // (2) Resolve "up paths" to determine real request
        const untrustedFilePath = (0, _path).resolve(decodedUntrustedFilePath);
        // don't allow null bytes anywhere in the file path
        if (untrustedFilePath.indexOf('\x00') !== -1) {
            return false;
        }
        // Check if .next/static, static and public are in the path.
        // If not the path is not available.
        if ((untrustedFilePath.startsWith((0, _path).join(this.distDir, 'static') + _path.sep) || untrustedFilePath.startsWith((0, _path).join(this.dir, 'static') + _path.sep) || untrustedFilePath.startsWith((0, _path).join(this.dir, 'public') + _path.sep)) === false) {
            return false;
        }
        // Check against the real filesystem paths
        const filesystemUrls = this.getFilesystemPaths();
        const resolved = (0, _path).relative(this.dir, untrustedFilePath);
        return filesystemUrls.has(resolved);
    }
    generateRewrites({ restrictedRedirectPaths  }) {
        let beforeFiles = [];
        let afterFiles = [];
        let fallback = [];
        if (!this.minimalMode) {
            const buildRewrite = (rewrite, check = true)=>{
                const rewriteRoute = (0, _serverRouteUtils).getCustomRoute({
                    type: 'rewrite',
                    rule: rewrite,
                    restrictedRedirectPaths
                });
                return {
                    ...rewriteRoute,
                    check,
                    type: rewriteRoute.type,
                    name: `Rewrite route ${rewriteRoute.source}`,
                    match: rewriteRoute.match,
                    fn: async (req, res, params, parsedUrl)=>{
                        const { newUrl , parsedDestination  } = (0, _prepareDestination).prepareDestination({
                            appendParamsToQuery: true,
                            destination: rewriteRoute.destination,
                            params: params,
                            query: parsedUrl.query
                        });
                        // external rewrite, proxy it
                        if (parsedDestination.protocol) {
                            return this.proxyRequest(req, res, parsedDestination);
                        }
                        (0, _requestMeta).addRequestMeta(req, '_nextRewroteUrl', newUrl);
                        (0, _requestMeta).addRequestMeta(req, '_nextDidRewrite', newUrl !== req.url);
                        return {
                            finished: false,
                            pathname: newUrl,
                            query: parsedDestination.query
                        };
                    }
                };
            };
            if (Array.isArray(this.customRoutes.rewrites)) {
                afterFiles = this.customRoutes.rewrites.map((r)=>buildRewrite(r)
                );
            } else {
                beforeFiles = this.customRoutes.rewrites.beforeFiles.map((r)=>buildRewrite(r, false)
                );
                afterFiles = this.customRoutes.rewrites.afterFiles.map((r)=>buildRewrite(r)
                );
                fallback = this.customRoutes.rewrites.fallback.map((r)=>buildRewrite(r)
                );
            }
        }
        return {
            beforeFiles,
            afterFiles,
            fallback
        };
    }
    /**
   * Return a list of middleware routing items. This method exists to be later
   * overridden by the development server in order to use a different source
   * to get the list.
   */ getMiddleware() {
        if (this.minimalMode) {
            return [];
        }
        const manifest = require((0, _path).join(this.serverDistDir, _constants.MIDDLEWARE_MANIFEST));
        return manifest.sortedMiddleware.map((page)=>({
                match: getMiddlewareMatcher(manifest.middleware[page]),
                page
            })
        );
    }
    /**
   * Get information for the middleware located in the provided page
   * folder. If the middleware info can't be found it will throw
   * an error.
   */ getMiddlewareInfo(page) {
        const manifest = require((0, _path).join(this.serverDistDir, _constants.MIDDLEWARE_MANIFEST));
        let foundPage;
        try {
            foundPage = (0, _denormalizePagePath).denormalizePagePath((0, _normalizePagePath).normalizePagePath(page));
        } catch (err) {
            throw new _utils.PageNotFoundError(page);
        }
        let pageInfo = manifest.middleware[foundPage];
        if (!pageInfo) {
            throw new _utils.PageNotFoundError(foundPage);
        }
        var _env1, _wasm;
        return {
            name: pageInfo.name,
            paths: pageInfo.files.map((file)=>(0, _path).join(this.distDir, file)
            ),
            env: (_env1 = pageInfo.env) !== null && _env1 !== void 0 ? _env1 : [],
            wasm: ((_wasm = pageInfo.wasm) !== null && _wasm !== void 0 ? _wasm : []).map((binding)=>({
                    ...binding,
                    filePath: (0, _path).join(this.distDir, binding.filePath)
                })
            )
        };
    }
    /**
   * Checks if a middleware exists. This method is useful for the development
   * server where we need to check the filesystem. Here we just check the
   * middleware manifest.
   */ async hasMiddleware(pathname, _isSSR) {
        try {
            return this.getMiddlewareInfo(pathname).paths.length > 0;
        } catch (_) {}
        return false;
    }
    /**
   * A placeholder for a function to be defined in the development server.
   * It will make sure that the middleware has been compiled so that we
   * can run it.
   */ async ensureMiddleware(_pathname, _isSSR) {}
    /**
   * This method gets all middleware matchers and execute them when the request
   * matches. It will make sure that each middleware exists and is compiled and
   * ready to be invoked. The development server will decorate it to add warns
   * and errors with rich traces.
   */ async runMiddleware(params) {
        middlewareBetaWarning();
        const normalizedPathname = (0, _removeTrailingSlash).removeTrailingSlash(params.parsedUrl.pathname);
        // For middleware to "fetch" we must always provide an absolute URL
        const query = (0, _querystring).urlQueryToSearchParams(params.parsed.query).toString();
        const locale = params.parsed.query.__nextLocale;
        const url = `http://${this.hostname}:${this.port}${locale ? `/${locale}` : ''}${params.parsed.pathname}${query ? `?${query}` : ''}`;
        if (!url.startsWith('http')) {
            throw new Error('To use middleware you must provide a `hostname` and `port` to the Next.js Server');
        }
        const page = {};
        if (await this.hasPage(normalizedPathname)) {
            page.name = params.parsedUrl.pathname;
        } else if (this.dynamicRoutes) {
            for (const dynamicRoute of this.dynamicRoutes){
                const matchParams = dynamicRoute.match(normalizedPathname);
                if (matchParams) {
                    page.name = dynamicRoute.page;
                    page.params = matchParams;
                    break;
                }
            }
        }
        const allHeaders = new Headers();
        let result = null;
        const method = (params.request.method || 'GET').toUpperCase();
        let originalBody = method !== 'GET' && method !== 'HEAD' ? (0, _bodyStreams).clonableBodyForRequest(params.request.body) : undefined;
        for (const middleware of this.getMiddleware()){
            if (middleware.match(normalizedPathname)) {
                if (!await this.hasMiddleware(middleware.page, middleware.ssr)) {
                    console.warn(`The Edge Function for ${middleware.page} was not found`);
                    continue;
                }
                await this.ensureMiddleware(middleware.page, middleware.ssr);
                const middlewareInfo = this.getMiddlewareInfo(middleware.page);
                result = await (0, _sandbox).run({
                    name: middlewareInfo.name,
                    paths: middlewareInfo.paths,
                    env: middlewareInfo.env,
                    wasm: middlewareInfo.wasm,
                    request: {
                        headers: params.request.headers,
                        method,
                        nextConfig: {
                            basePath: this.nextConfig.basePath,
                            i18n: this.nextConfig.i18n,
                            trailingSlash: this.nextConfig.trailingSlash
                        },
                        url: url,
                        page: page,
                        body: originalBody === null || originalBody === void 0 ? void 0 : originalBody.cloneBodyStream()
                    },
                    useCache: !this.nextConfig.experimental.runtime,
                    onWarning: (warning)=>{
                        if (params.onWarning) {
                            warning.message += ` "./${middlewareInfo.name}"`;
                            params.onWarning(warning);
                        }
                    }
                });
                for (let [key, value] of result.response.headers){
                    if (key !== 'x-middleware-next') {
                        allHeaders.append(key, value);
                    }
                }
                if (!this.renderOpts.dev) {
                    result.waitUntil.catch((error)=>{
                        console.error(`Uncaught: middleware waitUntil errored`, error);
                    });
                }
                if (!result.response.headers.has('x-middleware-next')) {
                    break;
                }
            }
        }
        if (!result) {
            this.render404(params.request, params.response, params.parsed);
        } else {
            for (let [key, value] of allHeaders){
                result.response.headers.set(key, value);
            }
        }
        await (originalBody === null || originalBody === void 0 ? void 0 : originalBody.finalize());
        return result;
    }
    generateCatchAllMiddlewareRoute(devReady) {
        if (this.minimalMode) return undefined;
        if ((!this.renderOpts.dev || devReady) && !this.getMiddleware().length) {
            return undefined;
        }
        return {
            match: (0, _pathMatch).getPathMatch('/:path*'),
            type: 'route',
            name: 'middleware catchall',
            fn: async (req, res, _params, parsed)=>{
                const middleware = this.getMiddleware();
                if (!middleware.length) {
                    return {
                        finished: false
                    };
                }
                const initUrl = (0, _requestMeta).getRequestMeta(req, '__NEXT_INIT_URL');
                const parsedUrl = (0, _parseUrl).parseUrl(initUrl);
                const pathnameInfo = (0, _getNextPathnameInfo).getNextPathnameInfo(parsedUrl.pathname, {
                    nextConfig: this.nextConfig
                });
                parsedUrl.pathname = pathnameInfo.pathname;
                const normalizedPathname = (0, _removeTrailingSlash).removeTrailingSlash(parsedUrl.pathname);
                if (!middleware.some((m)=>m.match(normalizedPathname)
                )) {
                    return {
                        finished: false
                    };
                }
                let result = null;
                try {
                    result = await this.runMiddleware({
                        request: req,
                        response: res,
                        parsedUrl: parsedUrl,
                        parsed: parsed
                    });
                } catch (err) {
                    if ((0, _isError).default(err) && err.code === 'ENOENT') {
                        await this.render404(req, res, parsed);
                        return {
                            finished: true
                        };
                    }
                    if (err instanceof _utils.DecodeError) {
                        res.statusCode = 400;
                        this.renderError(err, req, res, parsed.pathname || '');
                        return {
                            finished: true
                        };
                    }
                    const error = (0, _isError).getProperError(err);
                    console.error(error);
                    res.statusCode = 500;
                    this.renderError(error, req, res, parsed.pathname || '');
                    return {
                        finished: true
                    };
                }
                if (result === null) {
                    return {
                        finished: true
                    };
                }
                if (result.response.headers.has('x-middleware-rewrite')) {
                    const value = result.response.headers.get('x-middleware-rewrite');
                    const rel = (0, _relativizeUrl).relativizeURL(value, initUrl);
                    result.response.headers.set('x-middleware-rewrite', rel);
                }
                if (result.response.headers.has('Location')) {
                    const value = result.response.headers.get('Location');
                    const rel = (0, _relativizeUrl).relativizeURL(value, initUrl);
                    result.response.headers.set('Location', rel);
                }
                if (!result.response.headers.has('x-middleware-rewrite') && !result.response.headers.has('x-middleware-next') && !result.response.headers.has('Location')) {
                    result.response.headers.set('x-middleware-refresh', '1');
                }
                result.response.headers.delete('x-middleware-next');
                for (const [key, value] of Object.entries((0, _utils1).toNodeHeaders(result.response.headers))){
                    if (key !== 'content-encoding' && value !== undefined) {
                        res.setHeader(key, value);
                    }
                }
                res.statusCode = result.response.status;
                res.statusMessage = result.response.statusText;
                const location = result.response.headers.get('Location');
                if (location) {
                    res.statusCode = result.response.status;
                    if (res.statusCode === 308) {
                        res.setHeader('Refresh', `0;url=${location}`);
                    }
                    res.body(location).send();
                    return {
                        finished: true
                    };
                }
                if (result.response.headers.has('x-middleware-rewrite')) {
                    const rewritePath = result.response.headers.get('x-middleware-rewrite');
                    const parsedDestination = (0, _parseUrl).parseUrl(rewritePath);
                    const newUrl = parsedDestination.pathname;
                    // TODO: remove after next minor version current `v12.0.9`
                    this.warnIfQueryParametersWereDeleted(parsedUrl.query, parsedDestination.query);
                    if (parsedDestination.protocol && (parsedDestination.port ? `${parsedDestination.hostname}:${parsedDestination.port}` : parsedDestination.hostname) !== req.headers.host) {
                        return this.proxyRequest(req, res, parsedDestination);
                    }
                    if (this.nextConfig.i18n) {
                        const localePathResult = (0, _normalizeLocalePath).normalizeLocalePath(newUrl, this.nextConfig.i18n.locales);
                        if (localePathResult.detectedLocale) {
                            parsedDestination.query.__nextLocale = localePathResult.detectedLocale;
                        }
                    }
                    (0, _requestMeta).addRequestMeta(req, '_nextRewroteUrl', newUrl);
                    (0, _requestMeta).addRequestMeta(req, '_nextDidRewrite', newUrl !== req.url);
                    return {
                        finished: false,
                        pathname: newUrl,
                        query: parsedDestination.query
                    };
                }
                if (result.response.headers.has('x-middleware-refresh')) {
                    res.statusCode = result.response.status;
                    for await (const chunk of result.response.body || []){
                        this.streamResponseChunk(res, chunk);
                    }
                    res.send();
                    return {
                        finished: true
                    };
                }
                return {
                    finished: false
                };
            }
        };
    }
    getPrerenderManifest() {
        if (this._cachedPreviewManifest) {
            return this._cachedPreviewManifest;
        }
        const manifest = require((0, _path).join(this.distDir, _constants.PRERENDER_MANIFEST));
        return this._cachedPreviewManifest = manifest;
    }
    getRoutesManifest() {
        return require((0, _path).join(this.distDir, _constants.ROUTES_MANIFEST));
    }
    // TODO: remove after next minor version current `v12.0.9`
    warnIfQueryParametersWereDeleted(incoming, rewritten) {
        const incomingQuery = (0, _querystring).urlQueryToSearchParams(incoming);
        const rewrittenQuery = (0, _querystring).urlQueryToSearchParams(rewritten);
        const missingKeys = [
            ...incomingQuery.keys()
        ].filter((key)=>{
            return !rewrittenQuery.has(key);
        });
        if (missingKeys.length > 0) {
            Log.warn(`Query params are no longer automatically merged for rewrites in middleware, see more info here: https://nextjs.org/docs/messages/deleting-query-params-in-middlewares`);
            this.warnIfQueryParametersWereDeleted = ()=>{};
        }
    }
}
exports.default = NextNodeServer;
const MiddlewareMatcherCache = new WeakMap();
function getMiddlewareMatcher(info) {
    const stored = MiddlewareMatcherCache.get(info);
    if (stored) {
        return stored;
    }
    if (typeof info.regexp !== 'string' || !info.regexp) {
        throw new Error(`Invariant: invalid regexp for middleware ${JSON.stringify(info)}`);
    }
    const matcher = (0, _routeMatcher).getRouteMatcher({
        re: new RegExp(info.regexp),
        groups: {}
    });
    MiddlewareMatcherCache.set(info, matcher);
    return matcher;
}

//# sourceMappingURL=next-server.js.map