"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const cpx_1 = __importDefault(require("cpx"));
const uuidv4_1 = __importDefault(require("uuidv4"));
const talonServerCopy_1 = require("./talonServerCopy");
const ComponentIndex_1 = __importDefault(require("../common/ComponentIndex"));
const webruntimeConfig_1 = require("./webruntimeConfig");
const fileUtils_1 = require("../common/fileUtils");
const rollup_plugin_custom_components_1 = require("./config/rollup-plugin-custom-components");
const rollup_plugin_salesforce_apex_1 = __importDefault(require("./config/rollup-plugin-salesforce-apex"));
const labelResolver_1 = __importDefault(require("./labelResolver"));
const debug_1 = __importDefault(require("debug"));
const perf_hooks_1 = require("perf_hooks");
const LocalDevTelemetryReporter_1 = __importDefault(require("../instrumentation/LocalDevTelemetryReporter"));
const crypto_1 = __importDefault(require("crypto"));
const debug = debug_1.default('localdevserver');
const packageRoot = path_1.default.join(__dirname, '..', '..');
const DEFAULT_API_VERSION = '46.0';
const ALLOWED_SHOW_EXTENSIONS = {
    '.html': true,
    '.css': true,
    '.js': true
};
exports.defaultOutputDirectory = '.localdevserver';
class LocalDevServer {
    constructor(devhubUser) {
        this.devhubUser = devhubUser || '';
        this.anonymousUserId = devhubUser
            ? crypto_1.default
                .createHash('md5')
                .update(this.devhubUser)
                .digest('hex')
            : '';
        this.nonce = uuidv4_1.default();
    }
    async start(project, connection) {
        const startTime = perf_hooks_1.performance.now();
        const configuration = project.configuration;
        const directory = project.directory;
        const nodePaths = require.resolve.paths('.') || [];
        const version = configuration.api_version !== undefined
            ? parseInt(configuration.api_version, 10) * 2 + 128
            : 0;
        const vendors = path_1.default.resolve(path_1.default.join(require.resolve('@salesforce/lwc-dev-server-dependencies'), '..', 'vendors', `dependencies-${version}`));
        const localDependencies = packageRoot;
        const virtualModules = path_1.default.join(packageRoot, 'virtual-modules', `${version}`);
        const reporter = await LocalDevTelemetryReporter_1.default.getInstance(this.anonymousUserId, this.nonce);
        let modulePaths = [
            vendors,
            virtualModules,
            localDependencies,
            ...nodePaths
        ];
        if (version === 222 || version === 224) {
            modulePaths.unshift(path_1.default.resolve(path_1.default.join(require.resolve('@salesforce/lwc-dev-server-dependencies'), '..', 'vendors', `dependencies-218`)));
        }
        modulePaths = modulePaths.filter(fs_1.default.existsSync);
        try {
            if (project.isSfdx) {
                webruntimeConfig_1.webruntimeConfig.rollup.plugins.push(rollup_plugin_custom_components_1.customComponentPlugin(configuration.namespace, 'lwc', project.directory));
            }
            webruntimeConfig_1.webruntimeConfig.rollup.plugins.push(rollup_plugin_salesforce_apex_1.default());
            const resolver = labelResolver_1.default({
                customLabelsPath: project.customLabelsPath
            });
            const labels = resolver.createProxiedObject();
            const config = {
                templateDir: directory,
                webruntimeConfig: webruntimeConfig_1.webruntimeConfig,
                srcDir: project.modulesSourceDirectory,
                views: webruntimeConfig_1.views,
                partials: { nonce: this.nonce },
                indexHtml: path_1.default.join(__dirname, '..', 'html', 'index.html'),
                routes: webruntimeConfig_1.routes,
                labels,
                theme: webruntimeConfig_1.theme,
                outputDir: path_1.default.join(directory, exports.defaultOutputDirectory),
                locale: 'en_US',
                basePath: '',
                isPreview: false,
                modulePaths,
                runInBand: true,
                liveReload: configuration.liveReload,
                modes: ['dev']
            };
            debug('Running Universal Container with config:');
            debug(config);
            fileUtils_1.removeFile(config.outputDir);
            debug('cleared outputDirectory');
            await this.copyAssets(project, config.outputDir);
            const proxyConfig = {
                apiEndpoint: configuration.endpoint,
                recordApiCalls: false,
                onProxyReq: configuration.onProxyReq,
                pathRewrite: this.pathRewrite(configuration.api_version || DEFAULT_API_VERSION)
            };
            const server = await talonServerCopy_1.createServer(config, proxyConfig, connection);
            server.get(`/localdev/${this.nonce}/localdev.json`, (req, res, next) => {
                const componentIndex = new ComponentIndex_1.default(project);
                const json = componentIndex.getProjectMetadata();
                res.json(json);
            });
            server.get(`/localdev/${this.nonce}/localdev.js`, (req, res, next) => {
                const componentIndex = new ComponentIndex_1.default(project);
                const json = componentIndex.getProjectMetadata();
                const LocalDev = {
                    project: json
                };
                res.type('js');
                res.send(`window.LocalDev = ${JSON.stringify(LocalDev)};`);
            });
            server.get(`/localdev/${this.nonce}/show`, (req, res, next) => {
                const file = req.query.file;
                const extension = path_1.default.extname(file);
                const normalizedFile = path_1.default.normalize(file);
                if (normalizedFile.startsWith(path_1.default.normalize(project.modulesSourceDirectory)) &&
                    ALLOWED_SHOW_EXTENSIONS[extension]) {
                    res.sendFile(file);
                }
            });
            this.server = await talonServerCopy_1.startServer(server, '', configuration.port, () => {
                const runtimeDuration = perf_hooks_1.performance.now() - startTime;
                reporter.trackApplicationEnd(runtimeDuration);
            });
            const startDuration = perf_hooks_1.performance.now() - startTime;
            reporter.trackApplicationStart(startDuration, false, version.toString());
        }
        catch (e) {
            reporter.trackApplicationStartException(e);
            throw new Error(`Unable to start LocalDevServer: ${e}`);
        }
    }
    async stop() {
        return new Promise((resolve, reject) => {
            if (this.server) {
                this.server.close(err => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    resolve();
                });
            }
            else {
                resolve();
            }
        });
    }
    get port() {
        if (this.server) {
            const address = this.server.address();
            if (address != null && typeof address !== 'string') {
                return address.port;
            }
        }
    }
    async copyAssets(project, dest) {
        const distPath = path_1.default.join(packageRoot, 'dist');
        const assetsPath = path_1.default.join(dest, 'public', 'assets');
        try {
            fileUtils_1.copyFiles(path_1.default.join(distPath, 'assets', '*'), assetsPath);
        }
        catch (e) {
            throw new Error(`error - unable to copy assets: ${e}`);
        }
        this.watchAssets(project, assetsPath);
    }
    async watchAssets(project, assetDir) {
        let staticDir = project.staticResourcesDirectory;
        if (staticDir !== null && fs_1.default.existsSync(staticDir)) {
            staticDir = path_1.default.join(staticDir, '**', '*');
            await cpx_1.default.copy(staticDir, assetDir);
        }
    }
    pathRewrite(version) {
        return (localPath) => {
            let retVal = localPath;
            if (retVal.startsWith('/api/')) {
                retVal = retVal.substring(4);
            }
            retVal = retVal.replace(/v[\d]*\.0/, `v${version}`);
            return retVal;
        };
    }
}
exports.default = LocalDevServer;
//# sourceMappingURL=LocalDevServer.js.map