"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "createHotReloaderTurbopack", {
    enumerable: true,
    get: function() {
        return createHotReloaderTurbopack;
    }
});
const _ws = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/ws"));
const _swc = require("../../build/swc");
const _path = require("path");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../build/output/log"));
const _hotreloaderwebpack = require("./hot-reloader-webpack");
const _apppaths = require("../../shared/lib/router/utils/app-paths");
const _store = require("../../build/output/store");
const _middlewareturbopack = require("../../client/components/react-dev-overlay/server/middleware-turbopack");
const _promises = require("fs/promises");
const _utils = require("../../shared/lib/utils");
const _hotreloadertypes = require("./hot-reloader-types");
const _utils1 = require("../utils");
const _nextjsrequirecachehotreloader = require("../../build/webpack/plugins/nextjs-require-cache-hot-reloader");
const _getmetadataroute = require("../../lib/metadata/get-metadata-route");
const _renderserver = require("../lib/render-server");
const _denormalizepagepath = require("../../shared/lib/page-path/denormalize-page-path");
const _trace = require("../../trace");
const _turbopackutils = require("./turbopack-utils");
const _setupdevbundler = require("../lib/router-utils/setup-dev-bundler");
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 = {};
    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 wsServer = new _ws.default.Server({
    noServer: true
});
const isTestMode = !!(process.env.NEXT_TEST_MODE || process.env.__NEXT_TEST_MODE || process.env.DEBUG);
async function createHotReloaderTurbopack(opts, serverFields, distDir) {
    const buildId = "development";
    const { nextConfig, dir } = opts;
    const { loadBindings } = require("../../build/swc");
    let bindings = await loadBindings();
    // For the debugging purpose, check if createNext or equivalent next instance setup in test cases
    // works correctly. Normally `run-test` hides output so only will be visible when `--debug` flag is used.
    if (process.env.TURBOPACK && isTestMode) {
        require("console").log("Creating turbopack project", {
            dir,
            testMode: isTestMode
        });
    }
    const hasRewrites = opts.fsChecker.rewrites.afterFiles.length > 0 || opts.fsChecker.rewrites.beforeFiles.length > 0 || opts.fsChecker.rewrites.fallback.length > 0;
    const hotReloaderSpan = (0, _trace.trace)("hot-reloader", undefined, {
        version: "14.1.1-canary.61"
    });
    // Ensure the hotReloaderSpan is flushed immediately as it's the parentSpan for all processing
    // of the current `next dev` invocation.
    hotReloaderSpan.stop();
    const project = await bindings.turbo.createProject({
        projectPath: dir,
        rootPath: opts.nextConfig.experimental.outputFileTracingRoot || dir,
        nextConfig: opts.nextConfig,
        jsConfig: await (0, _turbopackutils.getTurbopackJsConfig)(dir, nextConfig),
        watch: true,
        dev: true,
        env: process.env,
        defineEnv: (0, _swc.createDefineEnv)({
            isTurbopack: true,
            allowedRevalidateHeaderKeys: undefined,
            clientRouterFilters: undefined,
            config: nextConfig,
            dev: true,
            distDir,
            fetchCacheKeyPrefix: undefined,
            hasRewrites,
            middlewareMatchers: undefined,
            previewModeId: undefined
        })
    });
    const entrypointsSubscription = project.entrypointsSubscribe();
    const globalEntrypoints = {
        app: undefined,
        document: undefined,
        error: undefined
    };
    const currentEntrypoints = new Map();
    const currentIssues = new Map();
    const buildManifests = new Map();
    const appBuildManifests = new Map();
    const pagesManifests = new Map();
    const appPathsManifests = new Map();
    const middlewareManifests = new Map();
    const actionManifests = new Map();
    const fontManifests = new Map();
    const loadableManifests = new Map();
    // Dev specific
    const hmrPayloads = new Map();
    const turbopackUpdates = [];
    const changeSubscriptions = new Map();
    const serverPathState = new Map();
    const readyIds = new Set();
    let currentEntriesHandlingResolve;
    let currentEntriesHandling = new Promise((resolve)=>currentEntriesHandlingResolve = resolve);
    let prevMiddleware = undefined;
    const handleRequireCacheClearing = (id, result)=>{
        // Figure out if the server files have changed
        let hasChange = false;
        for (const { path, contentHash } of result.serverPaths){
            // We ignore source maps
            if (path.endsWith(".map")) continue;
            const key = `${id}:${path}`;
            const localHash = serverPathState.get(key);
            const globalHash = serverPathState.get(path);
            if (localHash && localHash !== contentHash || globalHash && globalHash !== contentHash) {
                hasChange = true;
                serverPathState.set(key, contentHash);
                serverPathState.set(path, contentHash);
            } else {
                if (!localHash) {
                    serverPathState.set(key, contentHash);
                }
                if (!globalHash) {
                    serverPathState.set(path, contentHash);
                }
            }
        }
        if (!hasChange) {
            return;
        }
        const hasAppPaths = result.serverPaths.some(({ path: p })=>p.startsWith("server/app"));
        if (hasAppPaths) {
            (0, _nextjsrequirecachehotreloader.deleteAppClientCache)();
        }
        const serverPaths = result.serverPaths.map(({ path: p })=>(0, _path.join)(distDir, p));
        for (const file of serverPaths){
            (0, _renderserver.clearModuleContext)(file);
            (0, _nextjsrequirecachehotreloader.deleteCache)(file);
        }
        return;
    };
    const buildingIds = new Set();
    const startBuilding = (id, requestUrl, forceRebuild)=>{
        if (!forceRebuild && readyIds.has(id)) {
            return ()=>{};
        }
        if (buildingIds.size === 0) {
            _store.store.setState({
                loading: true,
                trigger: id,
                url: requestUrl
            }, true);
        }
        buildingIds.add(id);
        return function finishBuilding() {
            if (buildingIds.size === 0) {
                return;
            }
            readyIds.add(id);
            buildingIds.delete(id);
            if (buildingIds.size === 0) {
                _store.store.setState({
                    loading: false
                }, true);
            }
        };
    };
    let hmrEventHappened = false;
    let hmrHash = 0;
    const sendEnqueuedMessages = ()=>{
        for (const [, issueMap] of currentIssues){
            if (issueMap.size > 0) {
                // During compilation errors we want to delay the HMR events until errors are fixed
                return;
            }
        }
        for (const payload of hmrPayloads.values()){
            hotReloader.send(payload);
        }
        hmrPayloads.clear();
        if (turbopackUpdates.length > 0) {
            hotReloader.send({
                action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE,
                data: turbopackUpdates
            });
            turbopackUpdates.length = 0;
        }
    };
    const sendEnqueuedMessagesDebounce = (0, _utils1.debounce)(sendEnqueuedMessages, 2);
    const sendHmr = (id, payload)=>{
        hmrPayloads.set(`${id}`, payload);
        hmrEventHappened = true;
        sendEnqueuedMessagesDebounce();
    };
    function sendTurbopackMessage(payload) {
        turbopackUpdates.push(payload);
        hmrEventHappened = true;
        sendEnqueuedMessagesDebounce();
    }
    const clientToHmrSubscription = new Map();
    const clients = new Set();
    const changeSubscription = async (page, type, includeIssues, endpoint, makePayload)=>{
        const key = `${page} (${type})`;
        if (!endpoint || changeSubscriptions.has(key)) return;
        const changedPromise = endpoint[`${type}Changed`](includeIssues);
        changeSubscriptions.set(key, changedPromise);
        const changed = await changedPromise;
        for await (const change of changed){
            (0, _turbopackutils.processIssues)(currentIssues, page, change);
            const payload = await makePayload(page, change);
            if (payload) {
                sendHmr(key, payload);
            }
        }
    };
    const clearChangeSubscription = async (page, type)=>{
        const key = `${page} (${type})`;
        const subscription = await changeSubscriptions.get(key);
        if (subscription) {
            subscription.return == null ? void 0 : subscription.return.call(subscription);
            changeSubscriptions.delete(key);
        }
        currentIssues.delete(key);
    };
    async function subscribeToHmrEvents(id, client) {
        let mapping = clientToHmrSubscription.get(client);
        if (mapping === undefined) {
            mapping = new Map();
            clientToHmrSubscription.set(client, mapping);
        }
        if (mapping.has(id)) return;
        const subscription = project.hmrEvents(id);
        mapping.set(id, subscription);
        // The subscription will always emit once, which is the initial
        // computation. This is not a change, so swallow it.
        try {
            await subscription.next();
            for await (const data of subscription){
                (0, _turbopackutils.processIssues)(currentIssues, id, data);
                if (data.type !== "issues") {
                    sendTurbopackMessage(data);
                }
            }
        } catch (e) {
            // The client might be using an HMR session from a previous server, tell them
            // to fully reload the page to resolve the issue. We can't use
            // `hotReloader.send` since that would force very connected client to
            // reload, only this client is out of date.
            const reloadAction = {
                action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.RELOAD_PAGE
            };
            client.send(JSON.stringify(reloadAction));
            client.close();
            return;
        }
    }
    function unsubscribeToHmrEvents(id, client) {
        const mapping = clientToHmrSubscription.get(client);
        const subscription = mapping == null ? void 0 : mapping.get(id);
        subscription == null ? void 0 : subscription.return();
    }
    try {
        async function handleEntrypointsSubscription() {
            for await (const entrypoints of entrypointsSubscription){
                if (!currentEntriesHandlingResolve) {
                    currentEntriesHandling = new Promise(// eslint-disable-next-line no-loop-func
                    (resolve)=>currentEntriesHandlingResolve = resolve);
                }
                await (0, _turbopackutils.handleEntrypoints)({
                    rewrites: opts.fsChecker.rewrites,
                    nextConfig: opts.nextConfig,
                    entrypoints,
                    serverFields,
                    propagateServerField: async (key, value)=>{
                        await (0, _setupdevbundler.propagateServerField)(opts, key, value);
                    },
                    distDir,
                    buildId,
                    globalEntrypoints,
                    currentEntrypoints,
                    changeSubscriptions,
                    changeSubscription,
                    clearChangeSubscription,
                    sendHmr,
                    startBuilding,
                    handleRequireCacheClearing,
                    prevMiddleware,
                    currentIssues,
                    buildManifests,
                    appBuildManifests,
                    pagesManifests,
                    appPathsManifests,
                    middlewareManifests,
                    actionManifests,
                    fontManifests,
                    loadableManifests
                });
                currentEntriesHandlingResolve();
                currentEntriesHandlingResolve = undefined;
            }
        }
        handleEntrypointsSubscription().catch((err)=>{
            console.error(err);
            process.exit(1);
        });
    } catch (e) {
        console.error(e);
    }
    // Write empty manifests
    await (0, _promises.mkdir)((0, _path.join)(distDir, "server"), {
        recursive: true
    });
    await (0, _promises.mkdir)((0, _path.join)(distDir, "static", buildId), {
        recursive: true
    });
    await (0, _promises.writeFile)((0, _path.join)(distDir, "package.json"), JSON.stringify({
        type: "commonjs"
    }, null, 2));
    await currentEntriesHandling;
    await (0, _turbopackutils.writeManifests)({
        rewrites: opts.fsChecker.rewrites,
        distDir,
        buildId,
        buildManifests,
        appBuildManifests,
        pagesManifests,
        appPathsManifests,
        middlewareManifests,
        actionManifests,
        fontManifests,
        loadableManifests,
        currentEntrypoints
    });
    const overlayMiddleware = (0, _middlewareturbopack.getOverlayMiddleware)(project);
    const versionInfo = await (0, _hotreloaderwebpack.getVersionInfo)(isTestMode || opts.telemetry.isEnabled);
    const hotReloader = {
        turbopackProject: project,
        activeWebpackConfigs: undefined,
        serverStats: null,
        edgeServerStats: null,
        async run (req, res, _parsedUrl) {
            var _req_url;
            // intercept page chunks request and ensure them with turbopack
            if ((_req_url = req.url) == null ? void 0 : _req_url.startsWith("/_next/static/chunks/pages/")) {
                const params = (0, _hotreloaderwebpack.matchNextPageBundleRequest)(req.url);
                if (params) {
                    const decodedPagePath = `/${params.path.map((param)=>decodeURIComponent(param)).join("/")}`;
                    const denormalizedPagePath = (0, _denormalizepagepath.denormalizePagePath)(decodedPagePath);
                    await hotReloader.ensurePage({
                        page: denormalizedPagePath,
                        clientOnly: false,
                        definition: undefined,
                        url: req.url
                    }).catch(console.error);
                }
            }
            await overlayMiddleware(req, res);
            // Request was not finished.
            return {
                finished: undefined
            };
        },
        // TODO: Figure out if socket type can match the NextJsHotReloaderInterface
        onHMR (req, socket, head) {
            wsServer.handleUpgrade(req, socket, head, (client)=>{
                clients.add(client);
                client.on("close", ()=>clients.delete(client));
                client.addEventListener("message", ({ data })=>{
                    const parsedData = JSON.parse(typeof data !== "string" ? data.toString() : data);
                    // Next.js messages
                    switch(parsedData.event){
                        case "ping":
                            break;
                        case "span-end":
                            {
                                hotReloaderSpan.manualTraceChild(parsedData.spanName, (0, _turbopackutils.msToNs)(parsedData.startTime), (0, _turbopackutils.msToNs)(parsedData.endTime), parsedData.attributes);
                                break;
                            }
                        case "client-hmr-latency":
                            hotReloaderSpan.manualTraceChild(parsedData.event, (0, _turbopackutils.msToNs)(parsedData.startTime), (0, _turbopackutils.msToNs)(parsedData.endTime), {
                                updatedModules: parsedData.updatedModules,
                                page: parsedData.page,
                                isPageHidden: parsedData.isPageHidden
                            });
                            break;
                        case "client-error":
                        case "client-warning":
                        case "client-success":
                        case "server-component-reload-page":
                        case "client-reload-page":
                        case "client-removed-page":
                        case "client-full-reload":
                        case "client-added-page":
                            break;
                        default:
                            // Might be a Turbopack message...
                            if (!parsedData.type) {
                                throw new Error(`unrecognized HMR message "${data}"`);
                            }
                    }
                    // Turbopack messages
                    switch(parsedData.type){
                        case "turbopack-subscribe":
                            subscribeToHmrEvents(parsedData.path, client);
                            break;
                        case "turbopack-unsubscribe":
                            unsubscribeToHmrEvents(parsedData.path, client);
                            break;
                        default:
                            if (!parsedData.event) {
                                throw new Error(`unrecognized Turbopack HMR message "${data}"`);
                            }
                    }
                });
                const turbopackConnected = {
                    action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_CONNECTED
                };
                client.send(JSON.stringify(turbopackConnected));
                const errors = [];
                for (const pageIssues of currentIssues.values()){
                    for (const issue of pageIssues.values()){
                        errors.push({
                            message: (0, _turbopackutils.formatIssue)(issue)
                        });
                    }
                }
                const sync = {
                    action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.SYNC,
                    errors,
                    warnings: [],
                    hash: "",
                    versionInfo
                };
                this.send(sync);
            });
        },
        send (action) {
            const payload = JSON.stringify(action);
            for (const client of clients){
                client.send(payload);
            }
        },
        setHmrServerError (_error) {
        // Not implemented yet.
        },
        clearHmrServerError () {
        // Not implemented yet.
        },
        async start () {},
        async stop () {
        // Not implemented yet.
        },
        async getCompilationErrors (page) {
            const thisPageIssues = currentIssues.get(page);
            if (thisPageIssues !== undefined && thisPageIssues.size > 0) {
                // If there is an error related to the requesting page we display it instead of the first error
                return [
                    ...thisPageIssues.values()
                ].map((issue)=>new Error((0, _turbopackutils.formatIssue)(issue)));
            }
            // Otherwise, return all errors across pages
            const errors = [];
            for (const pageIssues of currentIssues.values()){
                for (const issue of pageIssues.values()){
                    errors.push(new Error((0, _turbopackutils.formatIssue)(issue)));
                }
            }
            return errors;
        },
        async invalidate ({ // .env files or tsconfig/jsconfig change
        reloadAfterInvalidation }) {
            if (reloadAfterInvalidation) {
                await (0, _renderserver.clearAllModuleContexts)();
                this.send({
                    action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.SERVER_COMPONENT_CHANGES
                });
            }
        },
        async buildFallbackError () {
        // Not implemented yet.
        },
        async ensurePage ({ page: inputPage, // Unused parameters
        // clientOnly,
        // appPaths,
        definition, isApp, url: requestUrl }) {
            const page = (definition == null ? void 0 : definition.pathname) ?? inputPage;
            if (page === "/_error") {
                let finishBuilding = startBuilding(page, requestUrl, false);
                try {
                    await (0, _turbopackutils.handlePagesErrorRoute)({
                        rewrites: opts.fsChecker.rewrites,
                        globalEntrypoints,
                        currentIssues,
                        distDir,
                        buildId,
                        buildManifests,
                        pagesManifests,
                        fontManifests,
                        appBuildManifests,
                        appPathsManifests,
                        middlewareManifests,
                        actionManifests,
                        loadableManifests,
                        currentEntrypoints,
                        handleRequireCacheClearing,
                        changeSubscription
                    });
                } finally{
                    finishBuilding();
                }
                return;
            }
            await currentEntriesHandling;
            const route = currentEntrypoints.get(page) ?? currentEntrypoints.get((0, _apppaths.normalizeAppPath)((0, _getmetadataroute.normalizeMetadataRoute)((definition == null ? void 0 : definition.page) ?? inputPage)));
            if (!route) {
                // TODO: why is this entry missing in turbopack?
                if (page === "/_app") return;
                if (page === "/_document") return;
                if (page === "/middleware") return;
                if (page === "/src/middleware") return;
                if (page === "/instrumentation") return;
                if (page === "/src/instrumentation") return;
                throw new _utils.PageNotFoundError(`route not found ${page}`);
            }
            // We don't throw on ensureOpts.isApp === true for page-api
            // since this can happen when app pages make
            // api requests to page API routes.
            if (isApp && route.type === "page") {
                throw new Error(`mis-matched route type: isApp && page for ${page}`);
            }
            const finishBuilding = startBuilding(page, requestUrl, false);
            try {
                await (0, _turbopackutils.handleRouteType)({
                    rewrites: opts.fsChecker.rewrites,
                    distDir,
                    buildId,
                    globalEntrypoints,
                    currentIssues,
                    buildManifests,
                    appBuildManifests,
                    pagesManifests,
                    appPathsManifests,
                    middlewareManifests,
                    actionManifests,
                    fontManifests,
                    loadableManifests,
                    currentEntrypoints,
                    handleRequireCacheClearing,
                    changeSubscription,
                    readyIds,
                    page,
                    route
                });
            } finally{
                finishBuilding();
            }
        }
    };
    (async function() {
        for await (const updateMessage of project.updateInfoSubscribe(30)){
            switch(updateMessage.updateType){
                case "start":
                    {
                        hotReloader.send({
                            action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.BUILDING
                        });
                        break;
                    }
                case "end":
                    {
                        sendEnqueuedMessages();
                        const errors = new Map();
                        for (const [, issueMap] of currentIssues){
                            for (const [key, issue] of issueMap){
                                if (errors.has(key)) continue;
                                const message = (0, _turbopackutils.formatIssue)(issue);
                                errors.set(key, {
                                    message,
                                    details: issue.detail ? (0, _turbopackutils.renderStyledStringToErrorAnsi)(issue.detail) : undefined
                                });
                            }
                        }
                        hotReloader.send({
                            action: _hotreloadertypes.HMR_ACTIONS_SENT_TO_BROWSER.BUILT,
                            hash: String(++hmrHash),
                            errors: [
                                ...errors.values()
                            ],
                            warnings: []
                        });
                        if (hmrEventHappened) {
                            const time = updateMessage.value.duration;
                            const timeMessage = time > 2000 ? `${Math.round(time / 100) / 10}s` : `${time}ms`;
                            _log.event(`Compiled in ${timeMessage}`);
                            hmrEventHappened = false;
                        }
                        break;
                    }
                default:
            }
        }
    })();
    return hotReloader;
}

//# sourceMappingURL=hot-reloader-turbopack.js.map