/** * QCObjects CLI 2.5 * ________________ * * Author: Jean Machuca * * Cross Browser Javascript Framework for MVC Patterns * QuickCorp/QCObjects is licensed under the * GNU Lesser General Public License v3.0 * [LICENSE] (https://github.com/QuickCorp/QCObjects/blob/master/LICENSE.txt) * * Permissions of this copyleft license are conditioned on making available * complete source code of licensed works and modifications under the same * license or the GNU GPLv3. Copyright and license notices must be preserved. * Contributors provide an express grant of patent rights. However, a larger * work using the licensed work through interfaces provided by the licensed * work may be distributed under different terms and without source code for * the larger work. * * Copyright (C) 2015 Jean Machuca, * * Everyone is permitted to copy and distribute verbatim copies of this * license document, but changing it is not allowed. */ /*eslint no-unused-vars: "off"*/ /*eslint no-redeclare: "off"*/ /*eslint no-empty: "off"*/ /*eslint strict: "off"*/ /*eslint no-mixed-operators: "off"*/ /*eslint no-undef: "off"*/ "use strict"; import "qcobjects"; import {readFileSync} from "node:fs"; import path from "node:path"; import fs from "node:fs"; import { CONFIG, global, logger, _Crypt, findPackageNodePath, Export, _DataStringify, Processor } from "qcobjects"; export const __get_version__ = () => { const absolutePath = path.resolve(__dirname, "./"); const package_config_path = path.resolve(process.cwd(), "package.json"); const qcobjects_pkg_config_path = `${findPackageNodePath("qcobjects/package.json")}/qcobjects/package.json`; const qcobjects_sdk_pkg_config_path = `${findPackageNodePath("qcobjects-sdk/package.json")}/qcobjects-sdk/package.json`; const readVersionFile = (filePath:string) => { try { return fs.readFileSync(filePath).toString(); } catch (error:any) { logger.debug(`Error reading file at ${filePath}:`, error.message); return JSON.stringify({ version: "0.0.0" }); } }; const package_config_text = readVersionFile(package_config_path); const qcobjects_pkg_config_text = readVersionFile(qcobjects_pkg_config_path); const qcobjects_sdk_pkg_config_text = readVersionFile(qcobjects_sdk_pkg_config_path); const package_config = JSON.parse(package_config_text); const qcobjects_pkg_config = JSON.parse(qcobjects_pkg_config_text); const qcobjects_sdk_pkg_config = JSON.parse(qcobjects_sdk_pkg_config_text); return { "qcobjects": qcobjects_pkg_config.version, "sdk": qcobjects_sdk_pkg_config.version, "cli": package_config.version }; }; export const __get_version_string__ = () => { const version = __get_version__(); return "QCObjects: v" + version.qcobjects + ", SDK: v" + version.sdk + ", CLI: v" + version.cli; }; export const getProjectPath = () => { return CONFIG.get("projectPath", `${process.cwd()}/`); }; Export(__get_version__); Export(__get_version_string__); Export(getProjectPath); const __load_default_settings__ = () => { // Temporary $ENV(VAR,default) override until qcobjects core ships it function ENV(_component: any, arg: string) { if (typeof process === "undefined") { return ""; } const commaIndex = arg.indexOf(","); if (commaIndex === -1) { return process.env[arg.trim()] ?? ""; } const varName = arg.substring(0, commaIndex).trim(); const defaultValue = arg.substring(commaIndex + 1).trim(); return process.env[varName] ?? defaultValue; } Processor.setProcessor(ENV); CONFIG.set("domain", "$ENV(DOMAIN,localhost)"); CONFIG.set("certificate_provider", "$ENV(CERTIFICATE_PROVIDER,self_signed)"); CONFIG.set("devmode", "$ENV(DEVMODE,info)"); CONFIG.set("autodiscover", true); CONFIG.set("autodiscover_commands", true); CONFIG.set("autodiscover_handlers", true); CONFIG.set("documentRoot", "$config(projectPath)public/"); CONFIG.set("documentRootFileIndex", "index.html"); CONFIG.set("cacheControl", "max-age=31536000"); CONFIG.set("relativeImportPath", "js/packages/"); CONFIG.set("serverPortHTTP", "8080"); CONFIG.set("serverPortHTTPS", "8443"); CONFIG.set("useLocalSDK", true); CONFIG.set("useLegacyHTTP", false); CONFIG.set("private-key-pem", "$config(domain)-privkey.pem"); CONFIG.set("private-cert-pem", "$config(domain)-cert.pem"); CONFIG.set("enableShellCommands", true); CONFIG.set("OPENAI_API_KEY", "$ENV(OPENAI_API_KEY,)"); // Set backend configuration const backend = { db_engine: { name: "$ENV(ENGINE_NAME,)", databaseName: "$ENV(DATABASE_NAME,)" }, auth: { enabled: true, defaultUser: "$ENV(DEFAULT_USER,)", defaultPasswd: "$ENV(DEFAULT_PASSWORD,)", microsoftapikey: "$ENV(MICROSOFT_API_KEY,)", googleapikey: "$ENV(GOOGLE_API_KEY,)" }, routes: [ ] }; CONFIG.set("backend", backend); // Set package configuration const packageConfig = { source: { backend: "backend", frontend: "src" }, build: "build", dist: "dist" }; CONFIG.set("package", packageConfig); CONFIG.set("useConfigService", false); // this is only true useful for client web side CONFIG.set("projectPath", `${process.cwd()}/`); CONFIG.set("allowHTTP1", true); CONFIG.set("useTemplate", false); CONFIG.set("useLegacyHTTP", false); const setDevMode = (devmode: string) => { if (typeof devmode !== "undefined") { switch (true) { case devmode == "debug": logger.debugEnabled = true; logger.warnEnabled = true; logger.infoEnabled = true; break; case devmode == "warn": logger.debugEnabled = false; logger.warnEnabled = true; logger.infoEnabled = true; break; case devmode == "info": logger.debugEnabled = false; logger.warnEnabled = false; logger.infoEnabled = true; break; default: logger.debugEnabled = false; logger.warnEnabled = false; logger.infoEnabled = false; break; } } else { logger.debugEnabled = false; logger.warnEnabled = false; logger.infoEnabled = false; } }; try { const loadConfig = () => { const configPath = path.resolve(CONFIG.get("projectPath"),"config.json"); const configText = readFileSync(configPath).toString(); const configJson = JSON.parse(configText); return configJson; }; var _config = loadConfig(); logger.debug("Loading settings from your config.json"); const _secretKey = (Object.hasOwn(_config, "domain")) ? (_config["domain"]) : ("_secret_"); if (Object.hasOwn(_config, "__encoded__")) { _config = JSON.parse(_Crypt.decrypt(_config.__encoded__, _secretKey)); } for (var k in _config) { CONFIG.set(k, _config[k]); } setDevMode(CONFIG.get("devmode", "")); if (typeof CONFIG.get("backend") !== "undefined") { global.set("backendAvailable", true); } if (typeof CONFIG.get("basePath") !== "undefined") { logger.debug(`Changing the current directory: ${process.cwd()}`); try { process.chdir(CONFIG.get("basePath")); logger.debug(`New directory: ${process.cwd()}`); } catch (err: any) { logger.warn(`It was impossible to change the current chdir: ${err}`); } } } catch (e:any) { logger.debug(e); logger.debug("Something went wrong trying to load config.json file in your project"); } (async function () { const projectPath = getProjectPath(); const loadDefaultRoutes = async () => { return await new Promise((resolve, reject) => { const sdkPath = path.resolve(findPackageNodePath("qcobjects-sdk"), "qcobjects-sdk"); const qcobjectsPath = path.resolve(findPackageNodePath("qcobjects"), "qcobjects"); let backend = CONFIG.get("backend"); if (typeof backend === "undefined") { backend = {}; } if (typeof backend.routes === "undefined") { backend.routes = []; } backend.routes = backend.routes.concat([{ "name": "QCObjects.js", "description": "Redirection of QCObjects.js", "path": "^/QCObjects.js$", "microservice": "com.qcobjects.backend.microservice.static", "redirect_to": path.resolve(qcobjectsPath, "src", "QCObjects.js"), "responseHeaders": {}, "cors": { "allow_origins": "*" } }, { "name": "QCObjects-SDK.js", "description": "Redirection of QCObjects SDK", "path": "^/js/packages/QCObjects-SDK.js$", "microservice": "com.qcobjects.backend.microservice.static", "redirect_to": path.resolve(sdkPath, "src/QCObjects-SDK.js"), "responseHeaders": {}, "cors": { "allow_origins": "*" } }, { "name": "QCObjects-SDK Components", "description": "Redirection of QCObjects SDK", "path": "^/qcobjects-sdk/(.*)$", "microservice": "com.qcobjects.backend.microservice.static", "redirect_to": path.resolve(sdkPath, "$1"), "responseHeaders": {}, "cors": { "allow_origins": "*" } } ]); CONFIG.set("backend", backend); resolve(); }); }; await loadDefaultRoutes(); })() .then(() => logger.info("Default routes loaded")) .catch((e: any) => { logger.warn(`An error ocurred loading default settings: ${e}`); }); (function () { /* Auto Discover dependencies (lib, handlers, commands) */ const projectPath = CONFIG.get("projectPath", `${process.cwd()}/`); logger.debug(`CONFIG.projectPath is set to ${projectPath}`); const findPath = (p: string) => { const packagePath = path.resolve(findPackageNodePath(p), p); return packagePath; }; const getPackageJSON = (p: string) => { let _json; try { const packagePath = findPath(p); if (typeof packagePath !== "undefined") { _json = JSON.parse(fs.readFileSync(path.resolve(`${packagePath}`, "./package.json")).toString()); } else { _json = {}; } } catch (e: any) { logger.debug(`It was impossible to get the package.json from ${p}: ${e}`); _json = {}; } return _json; }; const hasKeyword = (() => { let keywords: { [key: string]: string[] } = {}; return (p: string, keyword: string) => { if (typeof keywords === "undefined") { keywords = {}; } try { console.log("getting keywords for: ", p); if (typeof keywords[p] === "undefined") { keywords[p] = getPackageJSON(p).keywords; } } catch (e) { throw Error(`Something went wrong when trying to get the keywords of ${p}`); } return typeof keywords[p] !== "undefined" && keywords[p].includes(keyword); }; })(); const setBackendValue = (name: string, value: any) => { const backend = CONFIG.get("backend", {}); if (typeof value !== "undefined") { backend[name] = value; } CONFIG.set("backend", backend); }; const dependencies = (() => { let deps: string[] = []; return () => { if (typeof deps === "undefined") { deps = Object.keys(JSON.parse(fs.readFileSync(path.resolve(`${projectPath}`, "./package.json")).toString()).dependencies); setBackendValue("dependencies", deps); } return deps; }; })(); const devDependencies = (() => { let deps: string[] = []; return () => { if (typeof deps === "undefined") { deps = Object.keys(JSON.parse(fs.readFileSync(path.resolve(`${projectPath}`, "./package.json")).toString()).devDependencies); setBackendValue("devDependencies", deps); } return deps; }; })(); const loadLibs = () => { let _ret_; if (CONFIG.get("autodiscover", false) || CONFIG.get("autodiscover_libs", false)) { const libs = dependencies().filter((p) => hasKeyword(p, "qcobjects-lib")); setBackendValue("libs", libs); if (libs.length > 0) { logger.debug(`Plugin Libs found: ${libs.join(",")}`); _ret_ = Promise.all(libs.map(async (p) => { return await import(findPath(p)); })).then(() => logger.info("Libs loaded")); } else { logger.debug("No Plugin Libs found."); _ret_ = Promise.resolve(); } } else { logger.debug("To load libs, set autodiscover_libs to true in your config.json"); _ret_ = Promise.resolve(); } return _ret_; }; const loadHandlers = () => { let _ret_; if (CONFIG.get("autodiscover", false) || CONFIG.get("autodiscover_handlers", false)) { const handlers = dependencies().filter((p) => hasKeyword(p, "qcobjects-handler")); setBackendValue("handlers", handlers); if (handlers.length > 0) { logger.debug(`Plugin Handlers found: ${handlers.join(",")}`); _ret_ = Promise.all(handlers.map(async (p) => { return await import(findPath(p)); })).then(() => logger.info("Handlers loaded")); } else { logger.debug("No Plugin Handlers found."); _ret_ = Promise.resolve(); } } else { logger.debug("To load handlers, set autodiscover_handlers to true in your config.json"); _ret_ = Promise.resolve(); } return _ret_; }; const loadCommands = () => { let _ret_; logger.debug(`Looking for custom commands as dependencies in: ${projectPath}/package.json`); if (CONFIG.get("autodiscover", false) || CONFIG.get("autodiscover_commands", false)) { const commands = dependencies().filter((p) => hasKeyword(p, "qcobjects-command")); setBackendValue("commands", commands); if (commands.length > 0) { logger.debug(`Plugin Commands found: ${commands.join(",")}`); _ret_ = Promise.all( commands.map(async (p) => { try { return await import(findPath(p)); } catch (error: any) { logger.error(`Failed to load command ${p}: ${error}`); throw error; } }) ).then(() => logger.info("Commands loaded")) .catch(error => { logger.error("Failed to load commands:", error); throw error; }); } else { logger.debug("No Plugin Commands found."); _ret_ = Promise.resolve(); } } else { logger.debug("To load commands, set autodiscover_commands to true in your config.json"); _ret_ = Promise.resolve(); } return _ret_; }; const loadDevCommands = () => { let _ret_; logger.debug(`Looking for custom commands as dev dependencies in: ${projectPath}/package.json`); if (CONFIG.get("autodiscover", false) || CONFIG.get("autodiscover_commands", false)) { const commands = devDependencies().filter((p) => hasKeyword(p, "qcobjects-command")); setBackendValue("devCommands", commands); if (commands.length > 0) { logger.debug(`Dev Plugin Commands found: ${commands.join(",")}`); _ret_ = Promise.all(commands.map(async (p) => { return await import(findPath(p)); })).then(() => logger.info("Commands loaded")); } else { logger.debug("No Plugin Commands found in dev dependencies."); _ret_ = Promise.resolve(); } } else { logger.debug("To load commands, set autodiscover_commands to true in your config.json"); _ret_ = Promise.resolve(); } return _ret_; }; if (CONFIG.get("autodiscover", false) || CONFIG.get("autodiscover_libs", false) || CONFIG.get("autodiscover_handlers", false) || CONFIG.get("autodiscover_commands", false) ) { logger.info("Auto discover is enabled"); } else if (!CONFIG.get("autodiscover", false)) { logger.info("Auto discover is disabled"); logger.debug("To load all dependencies, set autodiscover to true in your config.json"); } else { logger.info("Auto discover is disabled"); } try { logger.debug("Loading Libs..."); loadLibs().catch((e: any) => { logger.warn(`An error ocurred loading libs: ${e}`); }); } catch (e: any) { throw Error(`Something went wrong trying to load libs: ${e.message}`); } try { logger.debug("Loading Handlers..."); loadHandlers().catch((e: any) => { logger.warn(`An error ocurred loading handlers: ${e}`); }); } catch (e: any) { throw Error(`Something went wrong trying to load handler: ${e.message}`); } try { logger.debug("Loading Commands..."); loadCommands().catch((e: any) => { logger.warn(`An error ocurred loading commands: ${e}`); }); } catch (e: any) { throw Error(`Something went wrong trying to load commands: ${e.message}`); } try { logger.debug("Loading Dev Commands..."); loadDevCommands().catch((e: any) => { logger.warn(`An error ocurred loading dev commands: ${e}`); }); } catch (e: any) { throw Error(`Something went wrong trying to load Dev commands: ${e.message}`); } try { const commands = CONFIG.get("backend", { commands: [] }).commands || []; const devCommands = CONFIG.get("backend", { devCommands: [] }).devCommands || []; setBackendValue("plugins", commands.concat(devCommands)); } catch (e: any) { throw Error(`Something went wrong trying to load plugins list: ${e.message}`); } logger.info("Dependencies loaded"); process.once("SIGTERM", () => { console.log("\x1b[33m%s\x1b[0m", "Bye bye!"); process.exit(); }); })(); }; (global as any).__load_default_settings__ = __load_default_settings__; (global as any).__load_default_settings__(); const cleanCache = () => { Object.keys(require.cache).forEach((key) => { delete require.cache[key]; }); }; const __reset_settings__ = () => { cleanCache(); (global as any).__load_default_settings__(); }; (global as any).__reset_settings__ = __reset_settings__;