"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HotCLI = void 0;
const ppath = __importStar(require("path"));
const fs = __importStar(require("fs"));
const dotenv = __importStar(require("dotenv"));
const commander = __importStar(require("commander"));
const node_fetch_1 = __importDefault(require("node-fetch"));
const node_fetch_2 = require("node-fetch");
const HotStaq_1 = require("./HotStaq");
const HotHTTPServer_1 = require("./HotHTTPServer");
const HotLog_1 = require("./HotLog");
const Hot_1 = require("./Hot");
const HotTesterServer_1 = require("./HotTesterServer");
const HotBuilder_1 = require("./HotBuilder");
const HotStaticBuilder_1 = require("./hott/HotStaticBuilder");
const HotGenerator_1 = require("./HotGenerator");
const HotCreator_1 = require("./HotCreator");
const HotTesterMochaSelenium_1 = require("./HotTesterMochaSelenium");
const HotDBMySQL_1 = require("./schemas/HotDBMySQL");
const HotDBInflux_1 = require("./schemas/HotDBInflux");
const HotDBPostgres_1 = require("./schemas/HotDBPostgres");
const HotIO_1 = require("./HotIO");
const HotAgentAPI_1 = require("./HotAgentAPI");
const HotTesterMocha_1 = require("./HotTesterMocha");
const HotServer_1 = require("./HotServer");
const HotDeployer_1 = require("./HotDeployer");
const HotDB_1 = require("./HotDB");
HotStaq_1.HotStaq.isWeb = false;
/**
 * The CLI that executes HotStaq.
 */
class HotCLI {
    constructor() {
        this.name = "hotstaq";
        this.description = `Copyright(c) 2023, FreeLight, Inc. Under the MIT License.`;
        this.program = null;
        this.VERSION = "";
        this.packagePath = ppath.normalize(`${__dirname}/../../package.json`);
        this.processor = new HotStaq_1.HotStaq();
        this.processor.logger.logLevel = HotLog_1.HotLogLevel.All;
        this.envFile = "";
        this.hotsitePath = "";
        this.globalLogLevel = null;
        this.apis = {};
        this.servers = {
            web: null,
            api: null,
            agent: null
        };
        this.creator = null;
        this.onModuleInstallAction = null;
        this.onModuleBuildAction = null;
        this.onCreateAction = null;
        this.onRunAction = null;
        this.onAgentAction = null;
        this.onGenerateAction = null;
        this.onBuildAction = null;
    }
    /**
     * Start the API server.
     */
    startAPIServer(server, loadedAPI, baseAPIUrl, dbinfo, isAPIOnly) {
        return __awaiter(this, void 0, void 0, function* () {
            let api = null;
            if (loadedAPI.importedAPIClass == null) {
                let foundModulePath = require.resolve(loadedAPI.path, { paths: [process.cwd()] });
                server.logger.verbose(`Loading API JavaScript from: ${foundModulePath}`);
                let apiJS = require(foundModulePath);
                let apiClass = apiJS[loadedAPI.exportedClassName];
                api = new apiClass(baseAPIUrl, server);
                server.logger.verbose(`Loaded API JavaScript from: ${foundModulePath}`);
            }
            else
                api = new loadedAPI.importedAPIClass(baseAPIUrl, server);
            let useDatabase = true;
            server.logger.info(`Loaded API class: ${loadedAPI.exportedClassName}`);
            server.logger.verbose(`Base API URL: ${baseAPIUrl}`);
            server.logger.verbose(`Server Type Set to: ${server.serverType}`);
            this.processor.api = api;
            server.processor.api = api;
            server.api = api;
            if (server.serverType === "api") {
                server.logger.info(`Server is ONLY an API.`);
                server.addRoute("/", (req, res) => __awaiter(this, void 0, void 0, function* () {
                    res.json({ "status": "ok" });
                }));
            }
            if (dbinfo != null) {
                if (dbinfo.type === "none")
                    useDatabase = false;
            }
            if (process.env["DATABASE_DISABLE"] != null) {
                if (process.env["DATABASE_DISABLE"] === "1")
                    useDatabase = false;
            }
            if (useDatabase === false)
                yield server.setAPI(api);
            if ((dbinfo != null) && (useDatabase === true)) {
                let dbClass = null;
                if ((dbinfo.type === "mysql") || (dbinfo.type === "mariadb"))
                    dbClass = HotDBMySQL_1.HotDBMySQL;
                if (dbinfo.type === "influx")
                    dbClass = HotDBInflux_1.HotDBInflux;
                if (dbinfo.type === "postgres")
                    dbClass = HotDBPostgres_1.HotDBPostgres;
                if (dbClass == null)
                    throw new Error(`Unable to use database type ${dbinfo.type}, no class available.`);
                api.db = new dbClass();
                if (dbinfo.type === "mariadb")
                    api.db.type = HotDB_1.HotDBType.MariaDB;
                yield server.setAPI(api);
                if (dbinfo.username === "")
                    throw new Error(`No database username provided!`);
                if (dbinfo.password === "")
                    throw new Error(`No database password provided!`);
                server.logger.verbose(`Connecting to ${dbinfo.type} database "${dbinfo.database}" on host ${dbinfo.server}:${dbinfo.port}`);
                yield api.db.connect(dbinfo);
                server.logger.verbose(`Connected to ${dbinfo.type} database "${dbinfo.database}" on host ${dbinfo.server}:${dbinfo.port}`);
            }
            return (api);
        });
    }
    /**
     * Get a key/value pair from a string.
     */
    getKeyValuePair(str) {
        let pos = str.indexOf("=");
        let key = "";
        let value = "";
        if (pos > -1) {
            key = str.substr(0, pos);
            value = str.substr(pos + 1);
        }
        return ({ key: key, value: value });
    }
    /**
     * Handle any build commands.
     */
    handleBuildCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let builder = null;
            let createHotBuilder = () => {
                if (builder == null)
                    builder = new HotBuilder_1.HotBuilder(this.processor.logger);
            };
            // v0.9.0 static-build opts; populated via --static, --strict, --out, etc.
            // and consumed at action-time to decide SSR vs static path.
            const staticOpts = {};
            let staticMode = false;
            const buildCmd = new commander.Command("build");
            buildCmd.description(`Build commands.`);
            buildCmd.action(() => {
                this.onBuildAction = () => __awaiter(this, void 0, void 0, function* () {
                    if (this.hotsitePath === "")
                        throw new Error(`When building, you must specify a HotSite.json!`);
                    yield this.processor.loadHotSite(this.hotsitePath);
                    yield this.processor.processHotSite();
                    if (staticMode) {
                        staticOpts.logger = this.processor.logger;
                        const staticBuilder = new HotStaticBuilder_1.HotStaticBuilder(this.processor.hotSite, staticOpts);
                        yield staticBuilder.build();
                        return;
                    }
                    createHotBuilder();
                    builder.hotsites = [this.processor.hotSite];
                    yield builder.build();
                });
            });
            buildCmd.option("--static", "Emit a static nginx-servable bundle (HS090 v0.9.0) instead of the SSR pipeline.", (arg, previous) => {
                staticMode = true;
            });
            buildCmd.option("--strict", "Fail on compiler warnings (recommended for CI). Only effective with --static.", (arg, previous) => {
                staticOpts.strict = true;
            });
            buildCmd.option("--out <dir>", "Output directory for --static builds. Defaults to ./dist.", (arg, previous) => {
                staticOpts.out = arg;
            });
            buildCmd.option("--mode <mode>", "Build mode for --static: production | development.", (arg, previous) => {
                if (arg !== "production" && arg !== "development")
                    throw new Error(`--mode must be "production" or "development", got ${JSON.stringify(arg)}.`);
                staticOpts.mode = arg;
            });
            buildCmd.option("--public-dir <dir>", "Public directory root for --static (default ./public).", (arg, previous) => {
                staticOpts.publicDir = arg;
            });
            buildCmd.option("--verbose", "Print a per-file size report after --static builds.", (arg, previous) => {
                staticOpts.verbose = true;
            });
            /*buildCmd.option ("--watch, -w", "Watch the associated files and rebuild when changes are detected.",
                (arg: string, previous: any) =>
                {
                    createHotBuilder ();
                    builder.api = true;
                });*/
            /*buildCmd.option ("--api", "Build the web client to be used in a web browser.",
                (arg: string, previous: any) =>
                {
                    createHotBuilder ();
                    builder.api = true;
                });*/
            buildCmd.option("--docker", "Build Dockerfiles from the given HotSite.json. This will be the default option.", (arg, previous) => {
                createHotBuilder();
                builder.dockerFiles = true;
            });
            buildCmd.option("--docker-namespace", "The namespace to tag the built docker image.", (arg, previous) => {
                createHotBuilder();
                builder.dockerNamespace = arg;
            });
            buildCmd.option("--helm", "Build Helm Charts from the given HotSite.json files. THIS IS EXPERIMENTAL AND UNTESTED. GOOD LUCK.", (arg, previous) => {
                createHotBuilder();
                builder.helmChart = true;
            });
            buildCmd.option("--hotstaq-version <version>", `Specify the HotStaq version to use. If not specified, the current version of HotStaq will be used to generate the files.`, (arg, previous) => {
                createHotBuilder();
                builder.hotstaqVersion = arg;
            });
            buildCmd.option("--dont-append-readme", "Do not add the additional docker documentation to the existing README.md.", (arg, previous) => {
                createHotBuilder();
                builder.appendReadMe = true;
            });
            /*buildCmd.option ("--helm-chart", "Build a Kubernetes Helm Chart from the given HotSite.json.",
                (arg: string, previous: any) =>
                {
                    createHotBuilder ();
                    builder.kubernetes = true;
                });*/
            buildCmd.option("--interfaces", "Generates interfaces to what is set with --interfaces-out and generate the specified interfaces that use --interface.", (arg, previous) => {
                createHotBuilder();
                builder.interfaces = true;
            });
            buildCmd.option("--interface <interface_name>", "The name of the interface to generate a IHotParameter JSON for.", (arg, previous) => {
                createHotBuilder();
                builder.interfaceConfig.filesToGenerate.push(arg);
            });
            buildCmd.option("--interfaces-tsconfig <path>", "The path to the tsconfig to load and use.", (arg, previous) => {
                createHotBuilder();
                builder.interfaceConfig.tsconfigPath = arg;
            });
            buildCmd.option("--interfaces-out <path>", "The path to output all the generated route parameters to.", (arg, previous) => {
                createHotBuilder();
                builder.interfaceConfig.outputDir = arg;
            });
            buildCmd.option("--output", "The path to place all files.", (arg, previous) => {
                createHotBuilder();
                builder.outputDir = arg;
            });
            return (buildCmd);
        });
    }
    /**
     * Handle create commands.
     */
    handleCreateCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let createHotCreator = () => {
                if (this.creator == null)
                    this.creator = new HotCreator_1.HotCreator(this.processor.logger, "");
            };
            let copyLibrariesPath = "";
            const createCmd = new commander.Command("create");
            createCmd.description(`Create a new project.`);
            createCmd.arguments("<name>");
            createCmd.action((name, cmdr) => {
                createHotCreator();
                this.creator.name = name;
                this.onCreateAction = () => __awaiter(this, void 0, void 0, function* () {
                    createHotCreator();
                    if (copyLibrariesPath !== "") {
                        yield this.creator.copyLibraries(copyLibrariesPath);
                        return;
                    }
                    if (this.creator.name == null)
                        throw new Error(`You must supply an npm compatible project name!`);
                    this.creator.outputDir = ppath.normalize(`${process.cwd()}/${this.creator.name}/`);
                    yield this.creator.create();
                });
            });
            createCmd.option(`--copy-libraries-to-location <path>`, `Copy the latest HotStaq libraries to a specified location. This will not generate any projects.`, (path, previous) => {
                createHotCreator();
                copyLibrariesPath = path;
            }, "");
            createCmd.option(`--type <type>`, `The type of app to create. Can be (web, web-api, api)`, (type, previous) => {
                createHotCreator();
                this.creator.type = type;
            }, "web-api");
            createCmd.option("--hotstaq-version <version>", `Specify the HotStaq version to use. The version must be NPM version compatible. If not specified, the current version of HotStaq will be used to generate the files.`, (arg, previous) => {
                createHotCreator();
                this.creator.hotstaqVersion = arg;
            });
            createCmd.option(`--code <language>`, `Set the type of code output. Can be (ts, js) Default: ts`, (language, previous) => {
                createHotCreator();
                this.creator.language = language;
            }, "ts");
            createCmd.option(`--output <path>`, `The directory path to place all the files.`, (path, previous) => {
                createHotCreator();
                if ((path === "") || (path === "."))
                    path = process.cwd();
                this.creator.outputDir = path;
            }, "");
            createCmd.option(`--overwrite-cmd-create-init <value>`, `Overwrite the create command for initalizing an app.`, (value, previous) => {
                createHotCreator();
                this.creator.createCommands.init = value;
            }, "");
            createCmd.option(`--dont-transpile`, `Do not transpile. If this setting is used, it's highly recommended to also use --dont-generate-api as well. Using this setting will set --overwrite-cmd-create-transpile to an empty string.`, (value, previous) => {
                createHotCreator();
                this.creator.createCommands.transpileTS = "";
            }, "");
            createCmd.option(`--overwrite-cmd-create-transpile <value>`, `Overwrite the create command for transpiling.`, (value, previous) => {
                createHotCreator();
                this.creator.createCommands.transpileTS = value;
            }, "");
            createCmd.option(`--dont-generate-api`, `Do not generate the api. This sets --overwrite-cmd-generate-api to an empty string.`, (value, previous) => {
                createHotCreator();
                this.creator.createCommands.generateAPI = "";
            }, "");
            createCmd.option(`--overwrite-cmd-generate-api <value>`, `Overwrite the generate command for generating the client API for use on the web.`, (value, previous) => {
                createHotCreator();
                this.creator.createCommands.generateAPI = value;
            }, "");
            createCmd.option(`--overwrite-cmd-npm-build-web-api <value>`, `Overwrite the npm command for building the web api.`, (value, previous) => {
                createHotCreator();
                this.creator.npmCommands.buildWebAPI = value;
            }, "");
            createCmd.option(`--overwrite-cmd-npm-build-web-api-debug <value>`, `Overwrite the npm command for building the debug script for web api.`, (value, previous) => {
                createHotCreator();
                this.creator.npmCommands.buildWebAPIDebug = value;
            }, "");
            createCmd.option(`--overwrite-cmd-npm-develop <value>`, `Overwrite the npm command for building the development script.`, (value, previous) => {
                createHotCreator();
                this.creator.npmCommands.develop = value;
            }, "");
            createCmd.option(`--overwrite-cmd-npm-start <value>`, `Overwrite the npm command for the start script.`, (value, previous) => {
                createHotCreator();
                this.creator.npmCommands.start = value;
            }, "");
            createCmd.option(`--overwrite-cmd-npm-test <value>`, `Overwrite the npm command for the test script.`, (value, previous) => {
                createHotCreator();
                this.creator.npmCommands.test = value;
            }, "");
            return (createCmd);
        });
    }
    /**
     * Handle module commands.
     */
    handleModuleCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            const moduleCmd = new commander.Command("module");
            moduleCmd.description(`Install and build HotStaq modules.`);
            let moduleInstallCmd = yield this.handleModuleInstallCommands();
            moduleCmd.addCommand(moduleInstallCmd);
            let moduleBuildCmd = yield this.handleModuleBuildCommands();
            moduleCmd.addCommand(moduleBuildCmd);
            return (moduleCmd);
        });
    }
    /**
     * Handle module install commands.
     */
    handleModuleInstallCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let installStr = "install";
            let outDir = "";
            let baseUrl = "";
            let cwd = process.cwd();
            const installCmd = new commander.Command("install");
            installCmd.description(`Install dependencies from NPM.`);
            installCmd.arguments("<name...>");
            installCmd.action((names, cmdr) => {
                this.onModuleInstallAction = () => __awaiter(this, void 0, void 0, function* () {
                    if (this.hotsitePath === "")
                        throw new Error(`When installing a dependency, you must specify a HotSite.json!`);
                    yield this.processor.loadHotSite(this.hotsitePath);
                    let hotsite = this.processor.hotSite;
                    if (hotsite.dependencies == null)
                        hotsite.dependencies = { web: {} };
                    for (let iIdx = 0; iIdx < names.length; iIdx++) {
                        let name = names[iIdx];
                        let realName = HotBuilder_1.HotBuilder.getNameFromNPMName(name);
                        let buildOptions = {
                            installType: installStr,
                            name: name,
                            processor: this.processor,
                            hotsite: hotsite,
                            hotsitePath: this.hotsitePath,
                            modulePath: `${cwd}/node_modules/${realName}/`,
                            moduleHotsite: `${cwd}/node_modules/${realName}/HotSite`,
                            outDir: outDir,
                            baseUrl: baseUrl,
                            cwd: cwd
                        };
                        yield HotBuilder_1.HotBuilder.installModule(buildOptions);
                        yield HotBuilder_1.HotBuilder.buildModule(buildOptions);
                    }
                });
            });
            installCmd.option(`--out <value>`, `Output the public files into a specific directory.`, (value, previous) => {
                outDir = value;
            }, `${cwd}/public/hotstaq_modules/MODULE_NAME/`);
            installCmd.option(`--base-url <value>`, `The base url to use when accessing the files from the web. Typically just needs to be a relative directory.`, (value, previous) => {
                baseUrl = value;
            }, "./hotstaq_modules/MODULE_NAME/");
            installCmd.option(`--use-link`, `Link a module instead of installing it.`, (value, previous) => {
                installStr = "link";
            }, "");
            return (installCmd);
        });
    }
    /**
     * Handle module build commands.
     */
    handleModuleBuildCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let buildStr = "build";
            let baseUrl = "";
            let cwd = process.cwd();
            const buildCmd = new commander.Command("build");
            buildCmd.description(`Build a HotStaq module.`);
            buildCmd.arguments("[path]");
            buildCmd.action((buildPath, cmdr) => {
                this.onModuleBuildAction = () => __awaiter(this, void 0, void 0, function* () {
                    let outDir = "";
                    if (buildPath != null) {
                        if (buildPath !== "")
                            outDir = buildPath;
                    }
                    if (this.hotsitePath === "")
                        throw new Error(`When installing a dependency, you must specify a HotSite.json!`);
                    yield this.processor.loadHotSite(this.hotsitePath);
                    let hotsite = this.processor.hotSite;
                    if (hotsite.dependencies == null)
                        hotsite.dependencies = { web: {} };
                    const pkgObjStr = yield HotIO_1.HotIO.readTextFile(`${cwd}/package.json`);
                    const pkgObj = JSON.parse(pkgObjStr);
                    const name = pkgObj.name;
                    if (hotsite.name !== name)
                        this.processor.logger.warning(`WARNING: Hotsite name ${hotsite.name} does not match package.json name ${name}!`);
                    let buildOptions = {
                        buildType: buildStr,
                        name: name,
                        processor: this.processor,
                        hotsite: hotsite,
                        hotsitePath: this.hotsitePath,
                        modulePath: cwd,
                        moduleHotsite: `${cwd}/HotSite`,
                        outDir: outDir,
                        baseUrl: baseUrl,
                        cwd: cwd
                    };
                    yield HotBuilder_1.HotBuilder.buildModule(buildOptions);
                });
            });
            buildCmd.option(`--base-url <value>`, `The base url to use when accessing the files from the web. Typically just needs to be a relative directory.`, (value, previous) => {
                baseUrl = value;
            }, "./hotstaq_modules/MODULE_NAME/");
            return (buildCmd);
        });
    }
    /**
     * Load the APIs from the processor.
     */
    loadAPIs(processor) {
        let apis = {};
        if (processor.hotSite != null) {
            if (processor.hotSite.apis != null) {
                for (let key in processor.hotSite.apis) {
                    let tempapi = processor.hotSite.apis[key];
                    if (tempapi.libraryName != null) {
                        let path = tempapi.filepath;
                        let apiToLoad = {
                            importedAPIClass: null,
                            exportedClassName: tempapi.apiName,
                            path: path
                        };
                        apis[key] = apiToLoad;
                    }
                }
            }
        }
        return (apis);
    }
    /**
     * Handle run commands.
     *
     * @param cmdName The name of the command to use. Can be:
     * * run
     * * start
     */
    handleRunCommands(cmdName) {
        return __awaiter(this, void 0, void 0, function* () {
            this.servers.web = new HotHTTPServer_1.HotHTTPServer(this.processor);
            this.servers.api = new HotHTTPServer_1.HotHTTPServer(this.processor);
            let serverType = "web";
            let globalApi = "";
            let baseWebUrl = "";
            let baseAPIUrl = "";
            let runWebTestMap = false;
            let runAPITestMap = false;
            let listAPIRoutes = false;
            let disableFileLoading = false;
            let skipSecretFiles = true;
            let dontLoadAPIFiles = false;
            let swaggerUIFilepath = "";
            let swaggerUIRoute = "/swagger";
            let mcpEnabled = false;
            let mcpRoute = "/mcp";
            let errorHandlingResponseCode = 500;
            let cors = {
                origin: "*",
                allowedHeaders: []
            };
            let rateLimiter = {
                enabled: null,
                windowLength: 60000,
                limit: 500,
                store: null
            };
            let testerSettings = {
                tester: "",
                address: "127.0.0.1",
                timeout: 10000,
                browser: "chrome",
                openDevTools: false,
                disableGPUAndSandbox: false,
                disableDevShmUsage: false,
                headless: false,
                remoteServer: "",
                windowWidth: null,
                windowHeight: null,
                http: 8182,
                https: 4143,
                shutdownAfterTests: true,
                commandDelay: 20,
                deployTester: true
            };
            let dbinfo = null;
            let setupDB = () => {
                if (dbinfo != null)
                    return;
                dbinfo = {
                    "type": (process.env["DATABASE_TYPE"] || "mysql"),
                    "server": process.env["DATABASE_SERVER"] || "127.0.0.1",
                    "username": process.env["DATABASE_USERNAME"] || "",
                    "password": process.env["DATABASE_PASSWORD"] || "",
                    "org": process.env["DATABASE_ORG"] || "",
                    "token": process.env["DATABASE_TOKEN"] || "",
                    "port": 3306,
                    "database": process.env["DATABASE_SCHEMA"] || ""
                };
                if (process.env["DATABASE_PORT"] != null) {
                    try {
                        dbinfo.port = parseInt(process.env["DATABASE_PORT"]);
                    }
                    catch (ex) {
                        throw new Error(`Unable to parse db port ${process.env["DATABASE_PORT"]}`);
                    }
                }
            };
            const runCmd = new commander.Command(cmdName);
            runCmd.description(`Run commands.`);
            runCmd.action(() => {
                this.onRunAction = () => __awaiter(this, void 0, void 0, function* () {
                    let runWebServer = false;
                    let runAPIServer = false;
                    let testerServer = null;
                    let tester = null;
                    if (this.processor.mode === Hot_1.DeveloperMode.Development) {
                        if (testerSettings.deployTester === true) {
                            if (baseWebUrl === "")
                                baseWebUrl = `http://127.0.0.1:${this.servers.web.ports.http}`;
                            let serverStarter = yield HotTesterServer_1.HotTesterServer.startServer(`http://${testerSettings.address}:${testerSettings.http}`, testerSettings.http, testerSettings.https, this.processor);
                            testerServer = serverStarter.server;
                            if (this.globalLogLevel != null)
                                testerServer.logger.logLevel = this.globalLogLevel;
                            if (runWebTestMap === true) {
                                this.servers.web.type = HotServer_1.HotServerType.WebTesting;
                                this.servers.api.type = HotServer_1.HotServerType.WebTesting;
                            }
                            if (runAPITestMap === true) {
                                this.servers.web.type = HotServer_1.HotServerType.APITesting;
                                this.servers.api.type = HotServer_1.HotServerType.APITesting;
                            }
                            if (testerSettings.tester === "") {
                                if (runWebTestMap === true)
                                    testerSettings.tester = "HotTesterMochaSelenium";
                                if (runAPITestMap === true)
                                    testerSettings.tester = "HotTesterMocha";
                            }
                            if (testerSettings.tester === "HotTesterMocha") {
                                let mochaTester = new HotTesterMocha_1.HotTesterMocha(this.processor, "HotTesterMocha", baseWebUrl);
                                tester = mochaTester;
                            }
                            if (testerSettings.tester === "HotTesterMochaSelenium") {
                                let mochaSeleniumTester = new HotTesterMochaSelenium_1.HotTesterMochaSelenium(this.processor, "HotTesterMochaSelenium", baseWebUrl);
                                mochaSeleniumTester.driver.browser = testerSettings.browser;
                                mochaSeleniumTester.driver.openDevTools = testerSettings.openDevTools;
                                mochaSeleniumTester.driver.disableGPUAndSandbox = testerSettings.disableGPUAndSandbox;
                                mochaSeleniumTester.driver.disableDevShmUsage = testerSettings.disableDevShmUsage;
                                mochaSeleniumTester.driver.headless = testerSettings.headless;
                                mochaSeleniumTester.driver.remoteServer = testerSettings.remoteServer;
                                if ((testerSettings.windowWidth != null) || (testerSettings.windowHeight != null)) {
                                    if (mochaSeleniumTester.driver.windowSize == null) {
                                        mochaSeleniumTester.driver.windowSize = {
                                            width: 1920,
                                            height: 1080
                                        };
                                    }
                                }
                                if (testerSettings.windowWidth != null)
                                    mochaSeleniumTester.driver.windowSize.width = testerSettings.windowWidth;
                                if (testerSettings.windowHeight != null)
                                    mochaSeleniumTester.driver.windowSize.height = testerSettings.windowHeight;
                                tester = mochaSeleniumTester;
                            }
                            if (tester != null) {
                                tester.timeout = testerSettings.timeout;
                                tester.driver.commandDelay = testerSettings.commandDelay;
                                testerServer.addTester(tester);
                                this.processor.addTester(tester);
                            }
                            else
                                this.processor.logger.warning("Warning: No tester set!");
                        }
                        else
                            this.processor.logger.warning("No tester being deployed.");
                        this.processor.logger.info("RUNNING IN DEVELOPMENT MODE. DO NOT RUN THIS MODE IN PRODUCTION.");
                    }
                    if (this.hotsitePath !== "") {
                        yield this.processor.loadHotSite(this.hotsitePath);
                        if (disableFileLoading === true)
                            this.processor.hotSite.disableFileLoading = disableFileLoading;
                        if (skipSecretFiles === false) {
                            if (this.processor.hotSite.server == null)
                                this.processor.hotSite.server = {};
                            this.processor.hotSite.server.serveSecretFiles = true;
                        }
                        if (this.processor.hotSite.server == null)
                            this.processor.hotSite.server = {};
                        if (this.processor.hotSite.server.ports == null)
                            this.processor.hotSite.server.ports = {};
                        if (this.servers.web != null) {
                            if (this.processor.hotSite.server.ports.http == null)
                                this.processor.hotSite.server.ports.http = this.servers.web.ports.http;
                            if (this.processor.hotSite.server.ports.https == null)
                                this.processor.hotSite.server.ports.https = this.servers.web.ports.https;
                        }
                        if (this.servers.api != null) {
                            this.processor.hotSite.server.ports.http = this.servers.api.ports.http;
                            this.processor.hotSite.server.ports.https = this.servers.api.ports.https;
                        }
                        // Go through each API and replace the base url with the base url set in the cli.
                        if (this.processor.hotSite.apis != null) {
                            for (let key in this.processor.hotSite.apis) {
                                let tempApi = this.processor.hotSite.apis[key];
                                tempApi.url = baseAPIUrl;
                            }
                        }
                        yield this.processor.processHotSite(tester);
                        if (dontLoadAPIFiles === false)
                            this.apis = this.loadAPIs(this.processor);
                    }
                    // Setup the DB if it hasn't already been setup.
                    if (process.env["DATABASE_TYPE"] != null) {
                        setupDB();
                        dbinfo.type = process.env["DATABASE_TYPE"];
                    }
                    if (process.env["DATABASE_SERVER"] != null) {
                        setupDB();
                        dbinfo.server = process.env["DATABASE_SERVER"];
                    }
                    if (process.env["DATABASE_USERNAME"] != null) {
                        setupDB();
                        dbinfo.username = process.env["DATABASE_USERNAME"];
                    }
                    if (process.env["DATABASE_PASSWORD"] != null) {
                        setupDB();
                        dbinfo.password = process.env["DATABASE_PASSWORD"];
                    }
                    if (process.env["DATABASE_ORG"] != null) {
                        setupDB();
                        dbinfo.org = process.env["DATABASE_ORG"];
                    }
                    if (process.env["DATABASE_TOKEN"] != null) {
                        setupDB();
                        dbinfo.token = process.env["DATABASE_TOKEN"];
                    }
                    if (process.env["DATABASE_PORT"] != null) {
                        setupDB();
                        try {
                            dbinfo.port = parseInt(process.env["DATABASE_PORT"]);
                        }
                        catch (ex) {
                            throw new Error(`Unable to parse db port ${process.env["DATABASE_PORT"]}`);
                        }
                    }
                    if (process.env["DATABASE_SCHEMA"] != null) {
                        setupDB();
                        dbinfo.database = process.env["DATABASE_SCHEMA"];
                    }
                    let sslObj = null;
                    if ((process.env["DATABASE_SSL_REJECT_UNAUTHORIZED"] != null) ||
                        (process.env["DATABASE_SSL_CA"] != null) ||
                        (process.env["DATABASE_SSL_KEY"] != null) ||
                        (process.env["DATABASE_SSL_CERT"] != null)) {
                        setupDB();
                        sslObj = {};
                    }
                    if (process.env["DATABASE_SSL_REJECT_UNAUTHORIZED"] != null) {
                        if (process.env["DATABASE_SSL_REJECT_UNAUTHORIZED"] === "0")
                            sslObj.rejectUnauthorized = false;
                    }
                    if (process.env["DATABASE_SSL_CA"] != null) {
                        if (process.env["DATABASE_SSL_CA"] !== "")
                            sslObj.ca = process.env["DATABASE_SSL_CA"];
                    }
                    if (process.env["DATABASE_SSL_KEY"] != null) {
                        if (process.env["DATABASE_SSL_KEY"] !== "")
                            sslObj.key = process.env["DATABASE_SSL_KEY"];
                    }
                    if (process.env["DATABASE_SSL_CERT"] != null) {
                        if (process.env["DATABASE_SSL_CERT"] !== "")
                            sslObj.cert = process.env["DATABASE_SSL_CERT"];
                    }
                    if (sslObj != null)
                        dbinfo.ssl = sslObj;
                    if (baseWebUrl === "") {
                        let foundBaseUrl = HotStaq_1.HotStaq.getValueFromHotSiteObj(this.processor.hotSite, ["server", "url"]);
                        if (foundBaseUrl != null)
                            baseWebUrl = foundBaseUrl;
                    }
                    if (baseWebUrl === "")
                        baseWebUrl = `http://127.0.0.1:${this.servers.web.ports.http}`;
                    if ((serverType === "web") || (serverType === "web-api")) {
                        if (this.processor.hotSite != null) {
                            if (this.processor.hotSite.server != null)
                                this.processor.hotSite.server.url = baseWebUrl;
                        }
                        runWebServer = true;
                    }
                    if (globalApi !== "")
                        this.processor.hotSite.server.globalApi = globalApi;
                    if (serverType === "api") {
                        if (rateLimiter.enabled != null)
                            rateLimiter.enabled = true;
                    }
                    if ((serverType === "api") || (serverType === "web-api")) {
                        runAPIServer = true;
                        if (cors.allowedHeaders.length === 0)
                            cors.allowedHeaders = ["Origin", "X-Requested-With", "Content-Type", "Accept"];
                        this.servers.api.cors.origin = cors.origin;
                        this.servers.api.cors.allowedHeaders = cors.allowedHeaders;
                        this.servers.api.rateLimiter.enabled = rateLimiter.enabled;
                        this.servers.api.rateLimiter.windowLength = rateLimiter.windowLength;
                        this.servers.api.rateLimiter.limit = rateLimiter.limit;
                        this.servers.api.errorHandlingResponseCode = errorHandlingResponseCode;
                        if (rateLimiter.store != null) {
                            this.servers.api.rateLimiter.store.redisConfig = {
                                host: rateLimiter.store.host
                            };
                            if (rateLimiter.store.port != null)
                                this.servers.api.rateLimiter.store.redisConfig.port = rateLimiter.store.port;
                            if (rateLimiter.store.username != null)
                                this.servers.api.rateLimiter.store.redisConfig.username = rateLimiter.store.username;
                            if (rateLimiter.store.password != null)
                                this.servers.api.rateLimiter.store.redisConfig.password = rateLimiter.store.password;
                        }
                        if (swaggerUIFilepath !== "") {
                            if (serverType === "web-api") {
                                this.servers.web.swaggerUI.filepath = swaggerUIFilepath;
                                this.servers.web.swaggerUI.route = swaggerUIRoute;
                            }
                            this.servers.api.swaggerUI.filepath = swaggerUIFilepath;
                            this.servers.api.swaggerUI.route = swaggerUIRoute;
                        }
                        if (mcpEnabled) {
                            if (serverType === "web-api") {
                                this.servers.web.mcpServer.enabled = true;
                                this.servers.web.mcpServer.route = mcpRoute;
                            }
                            this.servers.api.mcpServer.enabled = true;
                            this.servers.api.mcpServer.route = mcpRoute;
                        }
                    }
                    if (dbinfo != null)
                        this.processor.logger.verbose(`Connecting to ${dbinfo.type} database at ${dbinfo.server}:${dbinfo.port} using schema ${dbinfo.database}`);
                    /// @fixme Allow for multiple APIs to be loaded, and have their 
                    /// servers start in the future.
                    let getBaseUrlFromHotSite = (loadAPI, baseUrl = "") => {
                        let foundAPIUrl = baseUrl;
                        // Attempt to find the base url from the HotSite's API.
                        if (this.processor.hotSite != null) {
                            if (this.processor.hotSite.apis != null) {
                                for (let key in this.processor.hotSite.apis) {
                                    let tempAPI = this.processor.hotSite.apis[key];
                                    if (tempAPI.apiName != null) {
                                        if (tempAPI.apiName === loadAPI.exportedClassName) {
                                            if (tempAPI.url != null)
                                                foundAPIUrl = tempAPI.url;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        return (foundAPIUrl);
                    };
                    let loadAPIServer = (serverTypeDisplayName, server) => __awaiter(this, void 0, void 0, function* () {
                        if (Object.keys(this.apis).length < 1)
                            throw new Error(`No APIs are loaded! Try using --api-load`);
                        for (let key in this.apis) {
                            let loadAPI = this.apis[key];
                            let isAPIOnly = true;
                            if (baseAPIUrl === "")
                                baseAPIUrl = getBaseUrlFromHotSite(loadAPI);
                            if (baseAPIUrl === "")
                                baseAPIUrl = `http://127.0.0.1:${server.ports.http}`;
                            if ((serverType === "web") || (serverType === "web-api"))
                                isAPIOnly = false;
                            if (this.globalLogLevel != null)
                                server.logger.logLevel = this.globalLogLevel;
                            server.serverType = serverType;
                            // Only run the api server.
                            yield this.startAPIServer(server, loadAPI, baseAPIUrl, dbinfo, isAPIOnly);
                            // Change the name to a friendly display name.
                            server.serverType = serverTypeDisplayName;
                        }
                    });
                    let listenOnAPIServer = (server) => __awaiter(this, void 0, void 0, function* () {
                        if (Object.keys(this.apis).length < 1)
                            throw new Error(`No APIs are loaded! Try using --api-load`);
                        yield server.listen();
                    });
                    let loadAndStartAPIServer = (serverType, server) => __awaiter(this, void 0, void 0, function* () {
                        yield loadAPIServer(serverType, server);
                        yield listenOnAPIServer(server);
                    });
                    if (serverType === "api")
                        yield loadAndStartAPIServer("API Server", this.servers.api);
                    if (runWebServer === true) {
                        if (runAPIServer === true)
                            yield loadAPIServer("Web-API Server", this.servers.web);
                        else
                            this.servers.web.serverType = "Web Server";
                        if (this.globalLogLevel != null)
                            this.servers.web.logger.logLevel = this.globalLogLevel;
                        yield this.servers.web.listen();
                    }
                    if (listAPIRoutes === true) {
                        let servers = [this.servers.api, testerServer];
                        for (let iIdx = 0; iIdx < servers.length; iIdx++) {
                            let server = servers[iIdx];
                            if (server == null)
                                continue;
                            if (server.api == null)
                                continue;
                            for (let key2 in server.api.routes) {
                                let route = server.api.routes[key2];
                                let routeName = route.route;
                                for (let iJdx = 0; iJdx < route.methods.length; iJdx++) {
                                    let method = route.methods[iJdx];
                                    let methodName = method.name;
                                    let path = `/${route.version}/${routeName}/${methodName}`;
                                    server.logger.info(`Route ${method.type.toString()}: ${path}`);
                                }
                            }
                        }
                    }
                    if (runWebTestMap === true) {
                        if (testerServer == null)
                            throw new Error(`Unable to execute tests! Is --development-mode missing?`);
                        if (serverType === "api")
                            throw new Error(`In order to execute web tests, you must set the server type to either web or web-api.`);
                        this.processor.logger.info(`Executing web tests...`);
                        yield testerServer.executeAllWebTests(testerSettings.tester);
                    }
                    if (runAPITestMap === true) {
                        if (testerServer == null)
                            throw new Error(`Unable to execute tests! Is --development-mode missing?`);
                        if (serverType === "web")
                            throw new Error(`In order to execute API tests, you must set the server type to either api or web-api.`);
                        this.processor.logger.info(`Executing api tests...`);
                        yield testerServer.executeAllAPITests(testerSettings.tester);
                    }
                    if ((runWebTestMap === true) ||
                        (runAPITestMap === true)) {
                        if (testerSettings.shutdownAfterTests === true) {
                            if (testerServer != null) {
                                yield testerServer.shutdown();
                                testerServer = null;
                            }
                            if (this.servers.web != null) {
                                yield this.servers.web.shutdown();
                                this.servers.web = null;
                            }
                            if (this.servers.api != null) {
                                yield this.servers.api.shutdown();
                                this.servers.api = null;
                            }
                            /// @todo Remove this once the shutdown process is fixed.
                            process.exit(tester.numFailures);
                        }
                    }
                });
            });
            runCmd.option(`--list-api-routes`, `List the available API routes on startup.`, (arg, previous) => {
                listAPIRoutes = true;
            });
            runCmd.option(`--disable-file-loading`, `Disable file caching and loading.`, (arg, previous) => {
                disableFileLoading = true;
            });
            runCmd.option(`--serve-secret-files`, `Allows secret files to be served. NOT RECOMMENDED.`, (arg, previous) => {
                skipSecretFiles = false;
            });
            runCmd.option(`--dont-load-apis-from-hotsite`, `Do not load APIs from the HotSite.`, (arg, previous) => {
                dontLoadAPIFiles = true;
            });
            runCmd.option(`--swagger-ui <yaml_filepath>`, `If set to a JSON or YAML file, Swagger UI will run on the route /swagger. This will only work if the server type is set to web-api or api.`, (filepath, previous) => {
                swaggerUIFilepath = filepath;
            }, "");
            runCmd.option(`--swagger-ui-route <route>`, `If --swagger-ui is used, you can change the default name of the route used.`, (route, previous) => {
                swaggerUIRoute = route;
            }, "/swagger");
            runCmd.option(`--mcp`, `Enable the MCP (Model Context Protocol) server. Can also be enabled via MCP_SERVER=1 env var.`, () => {
                mcpEnabled = true;
            });
            if (process.env["MCP_SERVER"] === "1" || process.env["MCP_SERVER"] === "true")
                mcpEnabled = true;
            runCmd.option(`--mcp-route <route>`, `The route to expose the MCP server on. Default: /mcp. Can also be set via MCP_ROUTE env var.`, (route, previous) => {
                mcpRoute = route;
            }, "/mcp");
            if (process.env["MCP_ROUTE"] != null && process.env["MCP_ROUTE"] !== "")
                mcpRoute = process.env["MCP_ROUTE"];
            runCmd.option(`--dont-deploy-tester`, `If set, this will not deploy a tester. If this is enabled this will cause automated tests to fail.`, (arg, previous) => {
                testerSettings.deployTester = false;
            });
            runCmd.option(`--tester-http-port <port>`, `Set the tester HTTP port`, (port, previous) => {
                try {
                    const tempPort = parseInt(port);
                    testerSettings.http = tempPort;
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse tester http port ${port}`);
                }
            }, testerSettings.http);
            runCmd.option(`--tester-https-port <port>`, `Set the tester HTTPS port`, (port, previous) => {
                if (port == null)
                    return;
                if (port === "")
                    return;
                try {
                    const tempPort = parseInt(port);
                    testerSettings.https = tempPort;
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse tester https port ${port}`);
                }
            }, testerSettings.https);
            runCmd.option(`--tester-type <tester>`, `Set the tester to use. Can be: HotTesterMocha,HotTesterMochaSelenium`, (tester, previous) => {
                testerSettings.tester = tester;
            }, "");
            runCmd.option(`--tester-dont-shutdown`, `Do not shutdown after the tests have been completed.`, (value, previous) => {
                testerSettings.shutdownAfterTests = false;
            }, "");
            runCmd.option(`--tester-test-timeout <value>`, `Set the timeout for each test that executes. Set to 0 to disable timeouts.`, (value, previous) => {
                try {
                    testerSettings.timeout = parseInt(value);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse --tester-test-timeout ${value}`);
                }
            }, "10000");
            runCmd.option(`--tester-command-delay <value>`, `Set the command delay for each command that executes.`, (value, previous) => {
                try {
                    testerSettings.commandDelay = parseInt(value);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse --tester-command-delay ${value}`);
                }
            }, "10000");
            runCmd.option(`--tester-address <address>`, `Set the tester address to listen on.`, (address, previous) => {
                testerSettings.address = address;
            }, "127.0.0.1");
            runCmd.option(`--tester-browser <browser>`, `Set the tester browser to use. Can only be used with tester type: HotTesterMochaSelenium`, (browser, previous) => {
                testerSettings.browser = browser;
            }, "chrome");
            runCmd.option(`--tester-open-dev-tools`, `Open the browsers dev tools on start. Can only be used with tester type: HotTesterMochaSelenium`, (value, previous) => {
                testerSettings.openDevTools = true;
            }, "false");
            runCmd.option(`--tester-disable-gpu-sandbox`, `Disable GPU and Sandbox. Useful for executing in headless environments. Can only be used with tester type: HotTesterMochaSelenium`, (value, previous) => {
                testerSettings.disableGPUAndSandbox = true;
            }, "false");
            runCmd.option(`--tester-disable-dev-shm-usage`, `Disable shared memory usage in the launched browser. Useful for executing in headless environments. Can only be used with tester type: HotTesterMochaSelenium`, (value, previous) => {
                testerSettings.disableDevShmUsage = true;
            }, "false");
            runCmd.option(`--tester-window-width <number>`, `Set the width of the brower's window. Can only be used with tester type: HotTesterMochaSelenium`, (value, previous) => {
                try {
                    const tempValue = parseInt(value);
                    testerSettings.windowWidth = tempValue;
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse window width ${value}`);
                }
            }, "");
            runCmd.option(`--tester-window-height <number>`, `Set the height of the brower's window. Can only be used with tester type: HotTesterMochaSelenium`, (value, previous) => {
                try {
                    const tempValue = parseInt(value);
                    testerSettings.windowHeight = tempValue;
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse window height ${value}`);
                }
            }, "");
            runCmd.option(`--tester-headless`, `Make the browser headless. Can only be used with tester type: HotTesterMochaSelenium`, (value, previous) => {
                testerSettings.headless = true;
            }, "false");
            runCmd.option(`--tester-remote-server <remote_server>`, `Set the remote Selenium server to use for testing. Example: "http://localhost:4444" Can only be used with tester type: HotTesterMochaSelenium`, (remoteServer, previous) => {
                testerSettings.remoteServer = remoteServer;
            }, "");
            runCmd.option(`--ws, --accept-websocket-connections`, `This will allow the all servers to accept websocket connections.`, (remoteServer, previous) => {
                this.servers.web.useWebsocketServer = true;
                this.servers.api.useWebsocketServer = true;
            }, "");
            runCmd.option(`--error-handling-response-code`, `The status code to respond with when an API error occurs.`, (value, previous) => {
                try {
                    errorHandlingResponseCode = parseInt(value);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse error handling response code ${value}`);
                }
            }, "500");
            const serverTypes = ["web", "api"];
            for (let iIdx = 0; iIdx < serverTypes.length; iIdx++) {
                let currentServerType = serverTypes[iIdx];
                let httpPort = 5000;
                let httpsPort = 443;
                if (currentServerType === "api") {
                    httpPort = 6001;
                    httpsPort = 444;
                }
                runCmd.option(`--${currentServerType}-base-url <url>`, `Set the base ${currentServerType} server url.`, (url, previous) => {
                    if (currentServerType === "web")
                        baseWebUrl = url;
                    else
                        baseAPIUrl = url;
                }, "");
                if (currentServerType === "api") {
                    runCmd.option(`--${currentServerType}-port <port>`, `Set the ${currentServerType} HTTP port`, (port, previous) => {
                        try {
                            const tempPort = parseInt(port);
                            // @ts-ignore
                            if (currentServerType === "web")
                                this.servers.web.ports.http = tempPort;
                            else
                                this.servers.api.ports.http = tempPort;
                        }
                        catch (ex) {
                            this.processor.logger.error(`Unable to parse ${currentServerType} http port ${port}`);
                        }
                    }, httpPort);
                }
                runCmd.option(`--${currentServerType}-http-port <port>`, `Set the ${currentServerType} HTTP port`, (port, previous) => {
                    try {
                        const tempPort = parseInt(port);
                        if (currentServerType === "web")
                            this.servers.web.ports.http = tempPort;
                        else
                            this.servers.api.ports.http = tempPort;
                    }
                    catch (ex) {
                        this.processor.logger.error(`Unable to parse ${currentServerType} http port ${port}`);
                    }
                }, httpPort);
                runCmd.option(`--${currentServerType}-https-port [port]`, `Set the ${currentServerType} HTTPS port`, (port, previous) => {
                    if (port == null)
                        return;
                    if (port === "")
                        return;
                    try {
                        const tempPort = parseInt(port);
                        if (currentServerType === "web")
                            this.servers.web.ports.https = tempPort;
                        else
                            this.servers.api.ports.https = tempPort;
                    }
                    catch (ex) {
                        this.processor.logger.error(`Unable to parse ${currentServerType} https port ${port}`);
                    }
                }, httpsPort);
                runCmd.option(`--${currentServerType}-dont-redirect-http-to-https`, `Do not redirect ${currentServerType} HTTP traffic to HTTPS`, (port, previous) => {
                    if (currentServerType === "web")
                        this.servers.web.redirectHTTPtoHTTPS = false;
                    else
                        this.servers.api.redirectHTTPtoHTTPS = false;
                });
                runCmd.option(`--${currentServerType}-listen-address <address>`, `Set the ${currentServerType} listen address`, (address, previous) => {
                    if (currentServerType === "web")
                        this.servers.web.listenAddress = address;
                    else
                        this.servers.api.listenAddress = address;
                }, "0.0.0.0");
                runCmd.option(`--${currentServerType}-ssl-cert <path>`, `Set the path to the SSL cert for the ${currentServerType} server`, (cert, previous) => {
                    if (currentServerType === "web")
                        this.servers.web.ssl.cert = cert;
                    else
                        this.servers.api.ssl.cert = cert;
                }, "");
                runCmd.option(`--${currentServerType}-ssl-key <path>`, `Set the path to the SSL key for the ${currentServerType} server`, (key, previous) => {
                    if (currentServerType === "web")
                        this.servers.web.ssl.key = key;
                    else
                        this.servers.api.ssl.key = key;
                }, "");
                runCmd.option(`--${currentServerType}-ssl-ca <path>`, `Set the path to the SSL CA for the ${currentServerType} server`, (ca, previous) => {
                    if (currentServerType === "web")
                        this.servers.web.ssl.ca = ca;
                    else
                        this.servers.api.ssl.ca = ca;
                }, "");
                runCmd.option(`--${currentServerType}-log-level <level>`, `Set the logging level for the ${currentServerType} server. Can be (info,warning,error,all,none)`, (logLevel, previous) => {
                    let tempServer = null;
                    if (logLevel === "")
                        return;
                    if (currentServerType === "web")
                        tempServer = this.servers.web;
                    else
                        tempServer = this.servers.api;
                    if (logLevel === "info")
                        tempServer.logger.logLevel = HotLog_1.HotLogLevel.Info;
                    if (logLevel === "warning")
                        tempServer.logger.logLevel = HotLog_1.HotLogLevel.Warning;
                    if (logLevel === "error")
                        tempServer.logger.logLevel = HotLog_1.HotLogLevel.Error;
                    if (logLevel === "verbose")
                        tempServer.logger.logLevel = HotLog_1.HotLogLevel.Verbose;
                    if (logLevel === "all")
                        tempServer.logger.logLevel = HotLog_1.HotLogLevel.All;
                    if (logLevel === "none")
                        tempServer.logger.logLevel = HotLog_1.HotLogLevel.None;
                }, "");
                runCmd.option(`--${currentServerType}-test`, `Execute all tests specified in HotSite.json. Must be used with --development-mode.`, (map, previous) => {
                    if (currentServerType === "web")
                        runWebTestMap = true;
                    else
                        runAPITestMap = true;
                });
                if (currentServerType === "web") {
                    runCmd.option(`--${currentServerType}-route <route_and_path>`, `Add a static route in "key=path" format. Example: --${currentServerType}-route "/=/var/www"`, (routeAndPath, previous) => {
                        let keyValuePair = this.getKeyValuePair(routeAndPath);
                        const route = keyValuePair.key;
                        const path = keyValuePair.value;
                        this.servers.web.addStaticRoute(route, path);
                    });
                    runCmd.option(`--${currentServerType}-serve-file-extensions`, "Serve files extensions, must be passed as a JSON array.", (arg, previous) => {
                        this.servers.web.serveFileExtensions = JSON.parse(arg);
                    }, JSON.stringify(HotHTTPServer_1.HotHTTPServer.getDefaultServableExtensions()));
                    runCmd.option(`--${currentServerType}-js-url <url>`, "The url to the HotStaq JS", (url, previous) => {
                        this.servers.web.hottFilesAssociatedInfo.jsSrcPath = url;
                    });
                }
                if (currentServerType === "api") {
                    runCmd.option(`--${currentServerType}-load <exported_name_and_path>`, `Load an API for use in "exported_name=path_to_js_file" format. Example: --${currentServerType}-load "FreeLightAPI=/app/FreeLight/build/src/FreeLightAPI.js"`, (exported_name_and_path, previous) => {
                        let keyValuePair = this.getKeyValuePair(exported_name_and_path);
                        const exportedClassName = keyValuePair.key;
                        const path = keyValuePair.value;
                        this.apis[exportedClassName] = { importedAPIClass: null, exportedClassName: exportedClassName, path: path };
                    });
                }
            }
            runCmd.option(`--server-type <type>`, `Set the type of server. Can be (web, api, web-api)`, (type, previous) => {
                serverType = type;
            }, "web");
            runCmd.option(`--rate-limiter <enabled>`, `Enable or disable the rate limiter. If the server-type is set to API, this will be enabled by default. Can be (true, false)`, (type, previous) => {
                rateLimiter.enabled = false;
                if (type === "true")
                    rateLimiter.enabled = true;
            }, "true");
            runCmd.option(`--rate-limiter-window <length>`, `The number of milliseconds to remember requests for. Default: 60000`, (value, previous) => {
                try {
                    rateLimiter.windowLength = parseInt(value);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse rate-limiter-window ${value}`);
                }
            }, "60000");
            runCmd.option(`--rate-limiter-limit <length>`, `The number of requests allowed per window. Default: 500`, (value, previous) => {
                try {
                    rateLimiter.limit = parseInt(value);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse rate-limiter-limit ${value}`);
                }
            }, "500");
            runCmd.option(`--rate-limiter-redis-host <host>`, `Use Redis to store rate limiter data, this will set the redis host to connect to. This must be set if a rate limiter store is being used.`, (value, previous) => {
                rateLimiter.store = {
                    host: value
                };
            }, "localhost");
            runCmd.option(`--rate-limiter-redis-port <port>`, `Will set the Redis port to use for the rate limiter store.`, (value, previous) => {
                try {
                    rateLimiter.store.port = parseInt(value);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse rate-limiter-redis-port ${value}`);
                }
            }, "6379");
            runCmd.option(`--rate-limiter-redis-username <username>`, `Will set the Redis username to use for the rate limiter store.`, (value, previous) => {
                rateLimiter.store.username = value;
            });
            runCmd.option(`--rate-limiter-redis-password <password>`, `Will set the Redis password to use for the rate limiter store.`, (value, previous) => {
                rateLimiter.store.password = value;
            });
            runCmd.option(`--cors-origin <value>`, `The cors origin(s) to set comma separated if necessary. Default: *`, (value, previous) => {
                cors.origin = value;
            }, "*");
            runCmd.option(`--cors-allowed-header <value>`, `The cors allowed header to set, this can be set multiple times. Default: ["Origin", "X-Requested-With", "Content-Type", "Accept"]`, (value, previous) => {
                cors.allowedHeaders.push(value);
            });
            runCmd.option(`--global-api <api_name>`, `Set the global api to be used across all pages.`, (api_name, previous) => {
                globalApi = api_name;
            }, "");
            runCmd.option("--db-type <type>", "The type of database to use. Can be (none, mysql, mariadb, postgres, influx)", (type, previous) => {
                setupDB();
                dbinfo.type = type;
            }, "mysql");
            runCmd.option("--db-server <address>", "The address to the database", (address, previous) => {
                setupDB();
                dbinfo.server = address;
            }, "127.0.0.1");
            runCmd.option("--db-username <username>", "The database's username", (username, previous) => {
                setupDB();
                dbinfo.username = username;
            });
            runCmd.option("--db-password <password>", "The database's password. This is insecure to use on the command line!", (password, previous) => {
                setupDB();
                dbinfo.password = password;
            });
            runCmd.option("--db-token <password>", "The database's token. This is insecure to use on the command line!", (token, previous) => {
                setupDB();
                dbinfo.token = token;
            });
            runCmd.option("--db-port <port>", "The database's port", (port, previous) => {
                setupDB();
                try {
                    dbinfo.port = parseInt(port);
                }
                catch (ex) {
                    this.processor.logger.error(`Unable to parse db port ${port}`);
                }
            }, "3306");
            runCmd.option("--db-database <schema>", "The database's schema to select", (schema, previous) => {
                setupDB();
                dbinfo.database = schema;
            });
            runCmd.option("--db-ssl-accept-unauthorized-certs", "Accept database SSL connections with unauthorized certificates.", (schema, previous) => {
                setupDB();
                dbinfo.ssl.rejectUnauthorized = false;
            });
            runCmd.option("--db-ssl-ca", "The path to the ssl ca certificate.", (path, previous) => {
                setupDB();
                dbinfo.ssl.ca = path;
            });
            runCmd.option("--db-ssl-key", "The path to the ssl key certificate.", (path, previous) => {
                setupDB();
                dbinfo.ssl.key = path;
            });
            runCmd.option("--db-ssl-cert", "The path to the ssl certificate.", (path, previous) => {
                setupDB();
                dbinfo.ssl.cert = path;
            });
            return (runCmd);
        });
    }
    /**
     * Handle any agent commands.
     */
    handleAgentCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let baseAPIUrl = "";
            let agentKey = "";
            let agentSecret = "";
            let commands = {};
            let listenAddr = "0.0.0.0";
            let port = 5468;
            const agentCmd = new commander.Command("agent");
            agentCmd.description(`Listen for commands on a port.`);
            agentCmd.action(() => {
                this.onAgentAction = () => __awaiter(this, void 0, void 0, function* () {
                    let processor = new HotStaq_1.HotStaq();
                    processor.logger.logLevel = HotLog_1.HotLogLevel.Verbose;
                    this.servers.agent = new HotHTTPServer_1.HotHTTPServer(processor);
                    let api = new HotAgentAPI_1.HotAgentAPI(baseAPIUrl, this.servers.agent);
                    api.key = agentKey;
                    api.secret = agentSecret;
                    this.servers.agent.listenAddress = listenAddr;
                    this.servers.agent.ports.http = port;
                    this.servers.agent.processor.api = api;
                    this.servers.agent.api = api;
                    yield this.servers.agent.setAPI(api);
                    yield this.servers.agent.listen();
                });
            });
            agentCmd.option("--base-api-url <value>", "The key that must be given in order to execute the commands.", (value, previous) => {
                baseAPIUrl = value;
            });
            agentCmd.option("--key <key>", "The key that must be given in order to execute the commands.", (value, previous) => {
                agentKey = value;
            });
            agentCmd.option("--secret <secret>", "The secret key that must be given in order to execute the commands.", (value, previous) => {
                agentSecret = value;
            });
            agentCmd.option("--file <key_filepath>", "The key and the associated NodeJS file to execute (key=path).", (value, previous) => {
                let key = "";
                let filepath = "";
                let pos = key.indexOf("=");
                if (pos < 0)
                    throw new Error(`key_filepath must be in the format (key=path)`);
                key = value.substr(0, pos);
                filepath = value.substr(pos + 1);
                commands[key] = filepath;
            });
            agentCmd.option("--listen-addr <addr>", "The address to listen on.", (value, previous) => {
                listenAddr = value;
            });
            agentCmd.option("--listen-port <port>", "The port to listen on.", (value, previous) => {
                try {
                    port = parseInt(value);
                }
                catch (ex) {
                    throw new Error(`Unable to parse port ${value}`);
                }
            });
            return (agentCmd);
        });
    }
    /**
     * Handle any healthcheck commands.
     */
    handleHealthcheckCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let timeout = 10000;
            let headers = new node_fetch_2.Headers();
            const healthcheckCmd = new commander.Command("healthcheck");
            healthcheckCmd.description(`Execute a healthcheck. Will exit with error code 1 if an HTTP status other than 200 returns.`);
            healthcheckCmd.arguments("<url>");
            healthcheckCmd.action((url, cmdr) => {
                this.onHealthcheckAction = () => __awaiter(this, void 0, void 0, function* () {
                    try {
                        const controller = new AbortController();
                        let signalTimeout = setTimeout(() => {
                            this.processor.logger.error(`Error: Timeout`);
                            controller.abort();
                            process.exit(1);
                        }, timeout);
                        this.processor.logger.verbose(`Starting healthcheck at ${url}`);
                        let res = yield (0, node_fetch_1.default)(url, {
                            "signal": controller.signal,
                            "headers": headers
                        });
                        clearTimeout(signalTimeout);
                        if (res.status !== 200) {
                            this.processor.logger.error(`Error: Received ${res.status}`);
                            process.exit(1);
                        }
                        // Do not output the responses from the healthcheck. The responses 
                        // could still be used to launch an attack. Exiting with a 0 indicates 
                        // that the healthcheck was successful.
                        process.exit(0);
                    }
                    catch (ex) {
                        this.processor.logger.error(`Error: ${ex.message}`);
                        process.exit(1);
                    }
                });
            });
            healthcheckCmd.option("--timeout <value>", "The number of milliseconds before timing out.", (value, previous) => {
                timeout = parseInt(value);
            });
            healthcheckCmd.option("--header <value>", `The key/value to add to the HTTP GET request before sending, in the form key=value. Example: --header "Content-Type=text/html; charset=utf-8"`, (value, previous) => {
                let theSplits = value.split("=");
                let key = theSplits[0];
                let value2 = theSplits[1];
                headers.append(key, value2);
            });
            return (healthcheckCmd);
        });
    }
    /**
     * Handle any generate commands.
     */
    handleGenerateCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            let generator = null;
            let generateType = "api";
            let createHotGenerator = () => {
                if (generator == null)
                    generator = new HotGenerator_1.HotGenerator(this.processor.logger);
            };
            const generateCmd = new commander.Command("generate");
            generateCmd.description(`API Generation commands.`);
            generateCmd.action(() => {
                this.onGenerateAction = () => __awaiter(this, void 0, void 0, function* () {
                    createHotGenerator();
                    if (this.hotsitePath === "")
                        throw new Error(`When building, you must specify a HotSite.json!`);
                    let apis = {};
                    if (this.hotsitePath !== "") {
                        yield this.processor.loadHotSite(this.hotsitePath);
                        yield this.processor.processHotSite();
                        apis = this.loadAPIs(this.processor);
                    }
                    generator.hotsites = [this.processor.hotSite];
                    if (generateType === "api")
                        yield generator.generateAPI(this.processor, apis);
                    if (generateType === "api-documentation") {
                        if (generator.generateType === "javascript")
                            generator.generateType = "openapi-3.0.0-yaml";
                        yield generator.generateAPIDocumentation(this.processor, apis);
                    }
                });
            });
            generateCmd.option("--api", "Generate an API to use.", (arg, previous) => {
                createHotGenerator();
                generateType = "api";
            });
            generateCmd.option("--api-documentation", "Generate API documentation to use.", (arg, previous) => {
                createHotGenerator();
                generateType = "api-documentation";
            });
            generateCmd.option("--tsconfig <path>", "Specify the tsconfig.json file to use.", (arg, previous) => {
                createHotGenerator();
                generator.tsconfigPath = arg;
            });
            generateCmd.option("--optimize", "Optimize the compiled JavaScript using the Google Closure Compiler.", (arg, previous) => {
                createHotGenerator();
                generator.optimizeJS = true;
            });
            generateCmd.option("--skip-route", "Skip a particular route and continue to the next.", (arg, previous) => {
                createHotGenerator();
                generator.skipRoutes.push(arg);
            });
            generateCmd.option("--generate-type <type>", "The type of output to generate. Can be: javascript,openapi-3.0.0-json,openapi-3.0.0-yaml,asyncapi-2.6.0-json,asyncapi-2.6.0-yaml", (arg, previous) => {
                createHotGenerator();
                generator.generateType = arg;
                if ((generator.generateType === "openapi-3.0.0-json") ||
                    (generator.generateType === "openapi-3.0.0-yaml") ||
                    (generator.generateType === "asyncapi-2.6.0-json") ||
                    (generator.generateType === "asyncapi-2.6.0-yaml")) {
                    generateType = "api-documentation";
                }
            });
            generateCmd.option("--output <path>", "The directory path to place all files.", (arg, previous) => {
                createHotGenerator();
                generator.outputDir = arg;
            });
            generateCmd.option("--copy-to <path>", "The directory to copy all built files to.", (arg, previous) => {
                createHotGenerator();
                generator.copyTo = arg;
            });
            return (generateCmd);
        });
    }
    /**
     * Handle any deployment commands.
     */
    handleDeployCommands() {
        return __awaiter(this, void 0, void 0, function* () {
            const deployCmd = new commander.Command("deploy");
            deployCmd.description(`Deploy your application.`);
            deployCmd.action(() => {
                this.onDeployAction = () => __awaiter(this, void 0, void 0, function* () {
                    if (this.hotsitePath === "")
                        throw new Error(`When building, you must specify a HotSite.json!`);
                    yield this.processor.loadHotSite(this.hotsitePath);
                    yield this.processor.processHotSite();
                    let deployer = new HotDeployer_1.HotDeployer(this.processor.logger);
                    yield deployer.deploy();
                });
            });
            return (deployCmd);
        });
    }
    /**
     * Setup the CLI app.
     */
    setup() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            let command = null;
            let createCmd = null;
            let moduleCmd = null;
            let runCmd = null;
            let buildCmd = null;
            let generateCmd = null;
            let agentCmd = null;
            let healthcheckCmd = null;
            try {
                if ((yield HotIO_1.HotIO.exists(this.packagePath)) === false) {
                    this.packagePath = ppath.normalize(`${process.cwd()}/package.json`);
                    if ((yield HotIO_1.HotIO.exists(this.packagePath)) === false) {
                        console.error(`Unable to find path to HotStaq!`);
                        return;
                    }
                }
                let packageJSON = JSON.parse(fs.readFileSync(this.packagePath).toString());
                this.VERSION = packageJSON.version;
                dotenv.config();
                // Accept either LOG_LEVEL or LOGGING_LEVEL — every existing CI
                // config in the FreeLight org uses LOG_LEVEL, but the legacy
                // internal name is LOGGING_LEVEL. Rather than rewrite every
                // .env, accept both with LOG_LEVEL winning when both are set
                // (it's the more common form).
                const logLevelRaw = (_a = process.env["LOG_LEVEL"]) !== null && _a !== void 0 ? _a : process.env["LOGGING_LEVEL"];
                if (logLevelRaw != null) {
                    const logLevel = logLevelRaw.toLowerCase();
                    if (logLevel === "info")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Info;
                    if (logLevel === "warning" || logLevel === "warn")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Warning;
                    if (logLevel === "error")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Error;
                    if (logLevel === "verbose" || logLevel === "debug")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Verbose;
                    if (logLevel === "all")
                        this.globalLogLevel = HotLog_1.HotLogLevel.All;
                    if (logLevel === "none" || logLevel === "silent")
                        this.globalLogLevel = HotLog_1.HotLogLevel.None;
                }
                this.program = new commander.Command(this.name);
                this.program.description(this.description);
                command = this.program.version(this.VERSION);
                let hotsiteExists = false;
                let foundHotsitePath = "";
                /// @fixme Temporary hack to find a HotSite.json file. Come up with a better 
                /// solution for this.
                if ((yield HotIO_1.HotIO.exists("./HotSite.json")) === true) {
                    hotsiteExists = true;
                    foundHotsitePath = ppath.normalize("./HotSite.json");
                }
                if (hotsiteExists === false) {
                    if ((yield HotIO_1.HotIO.exists("./HotSite.yaml")) === true) {
                        hotsiteExists = true;
                        foundHotsitePath = ppath.normalize("./HotSite.yaml");
                    }
                }
                if (hotsiteExists === false) {
                    if ((yield HotIO_1.HotIO.exists("./hotsite.json")) === true) {
                        hotsiteExists = true;
                        foundHotsitePath = ppath.normalize("./hotsite.json");
                    }
                }
                if (hotsiteExists === false) {
                    if ((yield HotIO_1.HotIO.exists("./HOTSITE.json")) === true) {
                        hotsiteExists = true;
                        foundHotsitePath = ppath.normalize("./HOTSITE.json");
                    }
                }
                if (hotsiteExists === true)
                    this.hotsitePath = foundHotsitePath;
                command.option("--cwd <path>", "Set the current working directory to use.", (path, previous) => {
                    process.chdir(path);
                });
                command.option("--env-file <path>", "Set the path to the .env file to load.", (path, previous) => {
                    this.envFile = path;
                });
                command.option("-o, --hotsite <path>", "Specify the HotSite.json to use. This will look in the current directory to find one first.", (path, previous) => {
                    this.hotsitePath = path;
                }, foundHotsitePath);
                command.option("--not-hot", "Do not use a HotSite.json.", (path, previous) => {
                    this.hotsitePath = "";
                });
                command.option("--verbose", "Set the logging level to verbose.", (logLevel, previous) => {
                    this.globalLogLevel = HotLog_1.HotLogLevel.Verbose;
                });
                command.option("--show-responses", "If set to true, all responses from each request will be shown.", (logLevel, previous) => {
                    this.processor.logger.showResponses = true;
                });
                command.option("-l, --log-level <level>", "Set the logging level. Can be (info,warning,error,verbose,all,none)", (logLevel, previous) => {
                    if (logLevel === "info")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Info;
                    if (logLevel === "warning")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Warning;
                    if (logLevel === "error")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Error;
                    if (logLevel === "verbose")
                        this.globalLogLevel = HotLog_1.HotLogLevel.Verbose;
                    if (logLevel === "all")
                        this.globalLogLevel = HotLog_1.HotLogLevel.All;
                    if (logLevel === "none")
                        this.globalLogLevel = HotLog_1.HotLogLevel.None;
                }, "all");
                command.option("--dev, --development-mode", "Set to execute in development mode. This will allow for testing data to be collected and executed", (value, previous) => {
                    this.processor.mode = Hot_1.DeveloperMode.Development;
                });
                command.option("--start-delay <value>", "Set a start delay to use when starting the server. This is useful when debugging and you want to attach a debugger to the process.", (value, previous) => {
                    try {
                        const tempValue = parseInt(value);
                        this.processor.startDelay = tempValue;
                    }
                    catch (ex) {
                        this.processor.logger.error(`Unable to parse start delay ${value}`);
                    }
                });
                let createCmd = yield this.handleCreateCommands();
                command.addCommand(createCmd);
                let moduleCmd = yield this.handleModuleCommands();
                command.addCommand(moduleCmd);
                let runCmd = yield this.handleRunCommands("run");
                command.addCommand(runCmd);
                runCmd = yield this.handleRunCommands("start");
                command.addCommand(runCmd);
                let buildCmd = yield this.handleBuildCommands();
                command.addCommand(buildCmd);
                let generateCmd = yield this.handleGenerateCommands();
                command.addCommand(generateCmd);
                //let deployCmd: commander.Command = await this.handleDeployCommands ();
                //command.addCommand (deployCmd);
                let agentCmd = yield this.handleAgentCommands();
                command.addCommand(agentCmd);
                let healthcheckCmd = yield this.handleHealthcheckCommands();
                command.addCommand(healthcheckCmd);
            }
            catch (ex) {
                this.processor.logger.error(ex.stack);
            }
            return ({
                program: this.program,
                mainCommand: command,
                createCmd: createCmd,
                moduleCmd: moduleCmd,
                runCmd: runCmd,
                generateCmd: generateCmd,
                buildCmd: buildCmd,
                agentCmd: agentCmd,
                healthcheckCmd: healthcheckCmd
            });
        });
    }
    /**
     * Add an existing API thats already been imported.
     */
    addAPI(exportedClassName, importedClass) {
        this.apis[exportedClassName] = { importedAPIClass: importedClass, exportedClassName: exportedClassName, path: "" };
    }
    /**
     * Parse the CLI arguments and start the CLI app.
     */
    start(args) {
        return __awaiter(this, void 0, void 0, function* () {
            if (args.length > 2)
                this.program.parse(args);
            if (this.envFile !== "") {
                this.envFile = ppath.normalize(this.envFile);
                if ((yield HotIO_1.HotIO.exists(this.envFile)) === true) {
                    const content = yield HotIO_1.HotIO.readTextFile(this.envFile);
                    let envVars = dotenv.parse(content);
                    for (let key in envVars) {
                        const value = envVars[key];
                        if (value != null)
                            process.env[key] = value;
                    }
                }
            }
            if (this.globalLogLevel != null)
                this.processor.logger.logLevel = this.globalLogLevel;
            if (this.onModuleInstallAction != null)
                yield this.onModuleInstallAction();
            if (this.onModuleBuildAction != null)
                yield this.onModuleBuildAction();
            if (this.onCreateAction != null)
                yield this.onCreateAction();
            if (this.onRunAction != null)
                yield this.onRunAction();
            if (this.onBuildAction != null)
                yield this.onBuildAction();
            if (this.onGenerateAction != null)
                yield this.onGenerateAction();
            if (this.onAgentAction != null)
                yield this.onAgentAction();
            if (this.onHealthcheckAction != null)
                yield this.onHealthcheckAction();
        });
    }
}
exports.HotCLI = HotCLI;
//# sourceMappingURL=HotCLI.js.map