From f43e3cebded7a0e5ae28272522d385d7bbd65cd5 Mon Sep 17 00:00:00 2001 From: Karsten Hassel Date: Thu, 5 Feb 2026 20:42:25 +0100 Subject: [PATCH] - remove config.js.template (incl. envsub dependency) and allow bash variables in config.js - centralize loadConfig in Utils for use in app and check_config - add functionality to hide secrets in browser (only for node_helper modules), per default off --- cspell.config.json | 5 + eslint.config.mjs | 2 +- index.html | 2 +- js/app.js | 125 +- js/check_config.js | 143 +- js/defaults.js | 1 + js/main.js | 18 +- js/node_helper.js | 16 +- js/server.js | 21 +- js/server_functions.js | 17 +- js/utils.js | 314 +++- package-lock.json | 1302 +---------------- package.json | 1 - ..._variable.js.template => port_variable.js} | 0 14 files changed, 352 insertions(+), 1615 deletions(-) rename tests/configs/{port_variable.js.template => port_variable.js} (100%) diff --git a/cspell.config.json b/cspell.config.json index 33ff5bcb04..564f7d205b 100644 --- a/cspell.config.json +++ b/cspell.config.json @@ -179,6 +179,7 @@ "Lightspeed", "loadingcircle", "locationforecast", + "logg", "lockstring", "lstrip", "Luciella", @@ -285,6 +286,8 @@ "Teeuw", "Teil", "TESTMODE", + "testpass", + "testuser", "thomasrockhu", "thumbslider", "timeformat", @@ -307,6 +310,7 @@ "VEVENT", "vgtu", "Vitest", + "VCALENDAR", "Voelt", "Vorberechnung", "vppencilsharpener", @@ -326,6 +330,7 @@ "winddirection", "windgusts", "windspeed", + "WKST", "Woolridge", "worktree", "Wsymb", diff --git a/eslint.config.mjs b/eslint.config.mjs index d6cdcdc311..b1c90ca6c3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -9,7 +9,7 @@ import stylistic from "@stylistic/eslint-plugin"; import vitest from "@vitest/eslint-plugin"; export default defineConfig([ - globalIgnores(["config/**", "modules/**/*", "js/positions.js"]), + globalIgnores(["config/**", "modules/**/*", "js/positions.js", "tests/configs/port_variable.js"]), { files: ["**/*.js"], languageOptions: { diff --git a/index.html b/index.html index dcd354b776..af9df8560d 100644 --- a/index.html +++ b/index.html @@ -44,7 +44,6 @@ - @@ -52,6 +51,7 @@ + diff --git a/js/app.js b/js/app.js index 3d7e35d101..3de59c316b 100644 --- a/js/app.js +++ b/js/app.js @@ -4,7 +4,6 @@ require("./alias-resolver"); const fs = require("node:fs"); const path = require("node:path"); const Spawn = require("node:child_process").spawn; -const envsub = require("envsub"); const Log = require("logger"); // global absolute root path @@ -15,7 +14,7 @@ const Utils = require(`${__dirname}/utils`); // used to control fetch timeout for node_helpers const { setGlobalDispatcher, Agent } = require("undici"); -const { getEnvVarsAsObj, getConfigFilePath } = require("#server_functions"); +const { getEnvVarsAsObj } = require("#server_functions"); // common timeout value, provide environment override in case const fetch_timeout = process.env.mmFetchTimeout !== undefined ? process.env.mmFetchTimeout : 30000; @@ -59,122 +58,6 @@ function App () { let defaultModules; let env; - /** - * Loads the config file. Combines it with the defaults and returns the config - * @async - * @returns {Promise} the loaded config or the defaults if something goes wrong - */ - async function loadConfig () { - Log.log("Loading config ..."); - const defaults = require(`${__dirname}/defaults`); - if (global.mmTestMode) { - // if we are running in test mode - defaults.address = "0.0.0.0"; - } - - // For this check proposed to TestSuite - // https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8 - const configFilename = getConfigFilePath(); - let templateFile = `${configFilename}.template`; - - // check if templateFile exists - try { - fs.accessSync(templateFile, fs.constants.F_OK); - } catch (err) { - templateFile = null; - Log.log("config template file not exists, no envsubst"); - } - - if (templateFile) { - // save current config.js - try { - if (fs.existsSync(configFilename)) { - fs.copyFileSync(configFilename, `${configFilename}-old`); - } - } catch (err) { - Log.warn(`Could not copy ${configFilename}: ${err.message}`); - } - - // check if config.env exists - const envFiles = []; - const configEnvFile = `${configFilename.substr(0, configFilename.lastIndexOf("."))}.env`; - try { - if (fs.existsSync(configEnvFile)) { - envFiles.push(configEnvFile); - } - } catch (err) { - Log.log(`${configEnvFile} does not exist. ${err.message}`); - } - - let options = { - all: true, - diff: false, - envFiles: envFiles, - protect: false, - syntax: "default", - system: true - }; - - // envsubst variables in templateFile and create new config.js - // naming for envsub must be templateFile and outputFile - const outputFile = configFilename; - try { - await envsub({ templateFile, outputFile, options }); - } catch (err) { - Log.error(`Could not envsubst variables: ${err.message}`); - } - } - - require(`${global.root_path}/js/check_config.js`); - - try { - fs.accessSync(configFilename, fs.constants.F_OK); - const c = require(configFilename); - if (Object.keys(c).length === 0) { - Log.error("WARNING! Config file appears empty, maybe missing module.exports last line?"); - } - checkDeprecatedOptions(c); - return Object.assign(defaults, c); - } catch (e) { - if (e.code === "ENOENT") { - Log.error("WARNING! Could not find config file. Please create one. Starting with default configuration."); - } else if (e instanceof ReferenceError || e instanceof SyntaxError) { - Log.error(`WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: ${e.stack}`); - } else { - Log.error(`WARNING! Could not load config file. Starting with default configuration. Error found: ${e}`); - } - } - - return defaults; - } - - /** - * Checks the config for deprecated options and throws a warning in the logs - * if it encounters one option from the deprecated.js list - * @param {object} userConfig The user config - */ - function checkDeprecatedOptions (userConfig) { - const deprecated = require(`${global.root_path}/js/deprecated`); - - // check for deprecated core options - const deprecatedOptions = deprecated.configs; - const usedDeprecated = deprecatedOptions.filter((option) => userConfig.hasOwnProperty(option)); - if (usedDeprecated.length > 0) { - Log.warn(`WARNING! Your config is using deprecated option(s): ${usedDeprecated.join(", ")}. Check README and Documentation for more up-to-date ways of getting the same functionality.`); - } - - // check for deprecated module options - for (const element of userConfig.modules) { - if (deprecated[element.module] !== undefined && element.config !== undefined) { - const deprecatedModuleOptions = deprecated[element.module]; - const usedDeprecatedModuleOptions = deprecatedModuleOptions.filter((option) => element.config.hasOwnProperty(option)); - if (usedDeprecatedModuleOptions.length > 0) { - Log.warn(`WARNING! Your config for module ${element.module} is using deprecated option(s): ${usedDeprecatedModuleOptions.join(", ")}. Check README and Documentation for more up-to-date ways of getting the same functionality.`); - } - } - } - } - /** * Loads a specific module. * @param {string} module The name of the module (including subpath). @@ -289,7 +172,9 @@ function App () { * @returns {Promise} the config used */ this.start = async function () { - config = await loadConfig(); + const configObj = Utils.loadConfig(); + config = configObj.fullConf; + Utils.checkConfigFile(configObj); global.defaultModulesDir = config.defaultModulesDir; defaultModules = require(`${global.root_path}/${global.defaultModulesDir}/defaultmodules`); @@ -331,7 +216,7 @@ function App () { await loadModules(modules); - httpServer = new Server(config); + httpServer = new Server(configObj); const { app, io } = await httpServer.open(); Log.log("Server started ..."); diff --git a/js/check_config.js b/js/check_config.js index f2c9b2b7a2..3ed042c10b 100644 --- a/js/check_config.js +++ b/js/check_config.js @@ -2,154 +2,13 @@ require("./alias-resolver"); const path = require("node:path"); -const fs = require("node:fs"); -const { styleText } = require("node:util"); -const Ajv = require("ajv"); -const globals = require("globals"); -const { Linter } = require("eslint"); const Log = require("logger"); const rootPath = path.resolve(`${__dirname}/../`); const Utils = require(`${rootPath}/js/utils.js`); -const linter = new Linter({ configType: "flat" }); -const ajv = new Ajv(); - -/** - * Returns a string with path of configuration file. - * Check if set by environment variable MM_CONFIG_FILE - * @returns {string} path and filename of the config file - */ -function getConfigFile () { - // FIXME: This function should be in core. Do you want refactor me ;) ?, be good! - return path.resolve(process.env.MM_CONFIG_FILE || `${rootPath}/config/config.js`); -} - -/** - * Checks the config file using eslint. - */ -function checkConfigFile () { - const configFileName = getConfigFile(); - - // Check if file exists and is accessible - try { - fs.accessSync(configFileName, fs.constants.R_OK); - } catch (error) { - if (error.code === "ENOENT") { - Log.error(`File not found: ${configFileName}`); - } else if (error.code === "EACCES") { - Log.error(`No permission to read config file: ${configFileName}`); - } else { - Log.error(`Cannot access config file: ${configFileName}\n${error.message}`); - } - process.exit(1); - } - - // Validate syntax of the configuration file. - Log.info(`Checking config file ${configFileName} ...`); - - // I'm not sure if all ever is utf-8 - const configFile = fs.readFileSync(configFileName, "utf-8"); - - const errors = linter.verify( - configFile, - { - languageOptions: { - ecmaVersion: "latest", - globals: { - ...globals.browser, - ...globals.node - } - }, - rules: { - "no-sparse-arrays": "error", - "no-undef": "error" - } - }, - configFileName - ); - - if (errors.length === 0) { - Log.info(styleText("green", "Your configuration file doesn't contain syntax errors :)")); - validateModulePositions(configFileName); - } else { - let errorMessage = "Your configuration file contains syntax errors :("; - - for (const error of errors) { - errorMessage += `\nLine ${error.line} column ${error.column}: ${error.message}`; - } - Log.error(errorMessage); - process.exit(1); - } -} - -/** - * - * @param {string} configFileName - The path and filename of the configuration file to validate. - */ -function validateModulePositions (configFileName) { - Log.info("Checking modules structure configuration ..."); - - const positionList = Utils.getModulePositions(); - - // Make Ajv schema configuration of modules config - // Only scan "module" and "position" - const schema = { - type: "object", - properties: { - modules: { - type: "array", - items: { - type: "object", - properties: { - module: { - type: "string" - }, - position: { - type: "string" - } - }, - required: ["module"] - } - } - } - }; - - // Scan all modules - const validate = ajv.compile(schema); - const data = require(configFileName); - - const valid = validate(data); - if (valid) { - Log.info(styleText("green", "Your modules structure configuration doesn't contain errors :)")); - - // Check for unknown positions (warning only, not an error) - if (data.modules) { - for (const [index, module] of data.modules.entries()) { - if (module.position && !positionList.includes(module.position)) { - Log.warn(`Module ${index} ("${module.module}") uses unknown position: "${module.position}"`); - Log.warn(`Known positions are: ${positionList.join(", ")}`); - } - } - } - } else { - const module = validate.errors[0].instancePath.split("/")[2]; - const position = validate.errors[0].instancePath.split("/")[3]; - let errorMessage = "This module configuration contains errors:"; - errorMessage += `\n${JSON.stringify(data.modules[module], null, 2)}`; - if (position) { - errorMessage += `\n${position}: ${validate.errors[0].message}`; - errorMessage += `\n${JSON.stringify(validate.errors[0].params.allowedValues, null, 2).slice(1, -1)}`; - } else { - errorMessage += validate.errors[0].message; - } - Log.error(errorMessage); - process.exit(1); - } -} - try { - checkConfigFile(); + Utils.checkConfigFile(); } catch (error) { const message = error && error.message ? error.message : error; Log.error(`Unexpected error: ${message}`); diff --git a/js/defaults.js b/js/defaults.js index 58e930a38d..16d96f206c 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -21,6 +21,7 @@ const defaults = { customCss: "config/custom.css", foreignModulesDir: "modules", defaultModulesDir: "defaultmodules", + hideConfigSecrets: false, // httpHeaders used by helmet, see https://helmetjs.github.io/. You can add other/more object values by overriding this in config.js, // e.g. you need to add `frameguard: false` for embedding MagicMirror in another website, see https://github.com/MagicMirrorOrg/MagicMirror/issues/2847 httpHeaders: { contentSecurityPolicy: false, crossOriginOpenerPolicy: false, crossOriginEmbedderPolicy: false, crossOriginResourcePolicy: false, originAgentCluster: false }, diff --git a/js/main.js b/js/main.js index 6f7f65f8b2..f5c9e75e5f 100644 --- a/js/main.js +++ b/js/main.js @@ -470,17 +470,15 @@ const MM = (function () { }; /** - * Loads the core config and combines it with the system defaults. + * Loads the core config from the server (already combined with the system defaults). */ - const loadConfig = function () { - // FIXME: Think about how to pass config around without breaking tests - if (typeof config === "undefined") { - config = defaults; - Log.error("Config file is missing! Please create a config file."); - return; + const loadConfig = async function () { + try { + const res = await fetch(new URL("config/", `${location.origin}${config.basePath}`)); + config = JSON.parse(await res.text()); + } catch (error) { + Log.error("Unable to retrieve config", error); } - - config = Object.assign({}, defaults, config); }; /** @@ -582,7 +580,7 @@ const MM = (function () { */ async init () { Log.info("Initializing MagicMirror²."); - loadConfig(); + await loadConfig(); Log.setLogLevel(config.logLevel); diff --git a/js/node_helper.js b/js/node_helper.js index cbe30edda0..952db968c6 100644 --- a/js/node_helper.js +++ b/js/node_helper.js @@ -27,7 +27,7 @@ const NodeHelper = Class.extend({ /** * This method is called when a socket notification arrives. * @param {string} notification The identifier of the notification. - * @param {object} payload The payload of the notification. + * @param {object} payload The payload of the notification. */ socketNotificationReceived (notification, payload) { Log.log(`${this.name} received a socket notification: ${notification} - Payload: ${payload}`); @@ -88,7 +88,19 @@ const NodeHelper = Class.extend({ io.of(this.name).on("connection", (socket) => { // register catch all. socket.onAny((notification, payload) => { - this.socketNotificationReceived(notification, payload); + if (config.hideConfigSecrets && payload && typeof payload === "object") { + try { + const payloadStr = JSON.stringify(payload).replaceAll(/\*\*(SECRET_.*)\*\*/g, (match, group) => { + return process.env[group]; + }); + this.socketNotificationReceived(notification, JSON.parse(payloadStr)); + } catch (e) { + Log.error("Error substituting variables in payload: ", e); + this.socketNotificationReceived(notification, payload); + } + } else { + this.socketNotificationReceived(notification, payload); + } }); }); } diff --git a/js/server.js b/js/server.js index e96a6cc862..3bf892097f 100644 --- a/js/server.js +++ b/js/server.js @@ -6,7 +6,7 @@ const express = require("express"); const helmet = require("helmet"); const socketio = require("socket.io"); const Log = require("logger"); -const { cors, getConfig, getHtml, getVersion, getStartup, getEnvVars } = require("#server_functions"); +const { cors, getHtml, getVersion, getStartup, getEnvVars } = require("#server_functions"); const { ipAccessControl } = require(`${__dirname}/ip_access_control`); @@ -14,10 +14,11 @@ const vendor = require(`${__dirname}/vendor`); /** * Server - * @param {object} config The MM config + * @param {object} configObj The MM config full and redacted * @class */ -function Server (config) { +function Server (configObj) { + const config = configObj.fullConf; const app = express(); const port = process.env.MM_PORT || config.port; const serverSockets = new Set(); @@ -89,6 +90,12 @@ function Server (config) { app.use(helmet(config.httpHeaders)); app.use("/js", express.static(__dirname)); + if (config.hideConfigSecrets) { + app.get("/config/config.env", (req, res) => { + res.status(404).send("\n\n\n\nError\n\n\n
Cannot GET /config/config.env
\n\n"); + }); + } + let directories = ["/config", "/css", "/favicon.svg", "/defaultmodules", "/modules", "/node_modules/animate.css", "/node_modules/@fontsource", "/node_modules/@fortawesome", "/translations", "/tests/configs", "/tests/mocks"]; for (const [key, value] of Object.entries(vendor)) { const dirArr = value.split("/"); @@ -99,6 +106,14 @@ function Server (config) { app.use(directory, express.static(path.resolve(global.root_path + directory))); } + const getConfig = (req, res) => { + if (config.hideConfigSecrets) { + res.send(configObj.redactedConf); + } else { + res.send(configObj.fullConf); + } + }; + app.get("/cors", async (req, res) => await cors(req, res)); app.get("/version", (req, res) => getVersion(req, res)); diff --git a/js/server_functions.js b/js/server_functions.js index aedf6fa43c..85e674d816 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -4,15 +4,6 @@ const Log = require("logger"); const startUp = new Date(); -/** - * Gets the config. - * @param {Request} req - the request - * @param {Response} res - the result - */ -function getConfig (req, res) { - res.send(config); -} - /** * Gets the startup time. * @param {Request} req - the request @@ -118,12 +109,6 @@ function getHtml (req, res) { html = html.replace("#VERSION#", global.version); html = html.replace("#TESTMODE#", global.mmTestMode); - let configFile = "config/config.js"; - if (typeof global.configuration_file !== "undefined") { - configFile = global.configuration_file; - } - html = html.replace("#CONFIG_FILE#", configFile); - res.send(html); } @@ -201,4 +186,4 @@ function getConfigFilePath () { return path.resolve(global.configuration_file || `${global.root_path}/config/config.js`); } -module.exports = { cors, getConfig, getHtml, getVersion, getStartup, getEnvVars, getEnvVarsAsObj, getUserAgent, getConfigFilePath }; +module.exports = { cors, getHtml, getVersion, getStartup, getEnvVars, getEnvVarsAsObj, getUserAgent, getConfigFilePath }; diff --git a/js/utils.js b/js/utils.js index 42a651dcc9..258167afc7 100644 --- a/js/utils.js +++ b/js/utils.js @@ -1,51 +1,289 @@ const fs = require("node:fs"); -const Log = require("logger"); +const { loadEnvFile } = require("node:process"); const modulePositions = []; // will get list from index.html const regionRegEx = /"region ([^"]*)/i; const indexFileName = "index.html"; const discoveredPositionsJSFilename = "js/positions.js"; -module.exports = { - - // return all available module positions - getAvailableModulePositions () { - return modulePositions; - }, - - // return if position is on modulePositions Array (true/false) - moduleHasValidPosition (position) { - if (this.getAvailableModulePositions().indexOf(position) === -1) return false; - return true; - }, - - getModulePositions () { - // if not already discovered - if (modulePositions.length === 0) { - // get the lines of the index.html - const lines = fs.readFileSync(indexFileName).toString().split("\n"); - // loop thru the lines - lines.forEach((line) => { - // run the regex on each line - const results = regionRegEx.exec(line); - // if the regex returned something - if (results && results.length > 0) { - // get the position parts and replace space with underscore - const positionName = results[1].replace(" ", "_"); - // add it to the list only if not already present (avoid duplicates) - if (!modulePositions.includes(positionName)) { - modulePositions.push(positionName); - } +const { styleText } = require("node:util"); +const Log = require("logger"); +const Ajv = require("ajv"); +const globals = require("globals"); +const { Linter } = require("eslint"); +const { getConfigFilePath } = require("#server_functions"); + +const linter = new Linter({ configType: "flat" }); +const ajv = new Ajv(); + +const requireFromString = (src) => { + const m = new module.constructor(); + m._compile(src, ""); + return m.exports; +}; + +// return all available module positions +const getAvailableModulePositions = () => { + return modulePositions; +}; + +// return if position is on modulePositions Array (true/false) +const moduleHasValidPosition = (position) => { + if (getAvailableModulePositions().indexOf(position) === -1) return false; + return true; +}; + +const getModulePositions = () => { + // if not already discovered + if (modulePositions.length === 0) { + // get the lines of the index.html + const lines = fs.readFileSync(indexFileName).toString().split("\n"); + // loop thru the lines + lines.forEach((line) => { + // run the regex on each line + const results = regionRegEx.exec(line); + // if the regex returned something + if (results && results.length > 0) { + // get the position parts and replace space with underscore + const positionName = results[1].replace(" ", "_"); + // add it to the list only if not already present (avoid duplicates) + if (!modulePositions.includes(positionName)) { + modulePositions.push(positionName); + } + } + }); + try { + fs.writeFileSync(discoveredPositionsJSFilename, `const modulePositions=${JSON.stringify(modulePositions)}`); + } + catch (error) { + Log.error("unable to write js/positions.js with the discovered module positions\nmake the MagicMirror/js folder writeable by the user starting MagicMirror"); + } + } + // return the list to the caller + return modulePositions; +}; + +/** + * Checks the config for deprecated options and throws a warning in the logs + * if it encounters one option from the deprecated.js list + * @param {object} userConfig The user config + */ +const checkDeprecatedOptions = (userConfig) => { + const deprecated = require(`${global.root_path}/js/deprecated`); + + // check for deprecated core options + const deprecatedOptions = deprecated.configs; + const usedDeprecated = deprecatedOptions.filter((option) => userConfig.hasOwnProperty(option)); + if (usedDeprecated.length > 0) { + Log.warn(`WARNING! Your config is using deprecated option(s): ${usedDeprecated.join(", ")}. Check README and Documentation for more up-to-date ways of getting the same functionality.`); + } + + // check for deprecated module options + for (const element of userConfig.modules) { + if (deprecated[element.module] !== undefined && element.config !== undefined) { + const deprecatedModuleOptions = deprecated[element.module]; + const usedDeprecatedModuleOptions = deprecatedModuleOptions.filter((option) => element.config.hasOwnProperty(option)); + if (usedDeprecatedModuleOptions.length > 0) { + Log.warn(`WARNING! Your config for module ${element.module} is using deprecated option(s): ${usedDeprecatedModuleOptions.join(", ")}. Check README and Documentation for more up-to-date ways of getting the same functionality.`); + } + } + } +}; + +/** + * Loads the config file. Combines it with the defaults and returns the config + * @returns {object} an object holding full and redacted config + */ +const loadConfig = () => { + Log.log("Loading config ..."); + const defaults = require(`${__dirname}/defaults`); + if (global.mmTestMode) { + // if we are running in test mode + defaults.address = "0.0.0.0"; + } + + // For this check proposed to TestSuite + // https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8 + const configFilename = getConfigFilePath(); + let templateFile = `${configFilename}.template`; + + // check if templateFile exists + try { + fs.accessSync(templateFile, fs.constants.F_OK); + Log.warn("config.js.template files are deprecated and not used anymore. You can use variables inside config.js so copy the template file content into config.js if needed."); + } catch (error) { + // no action + } + + // check if config.env exists + const configEnvFile = `${configFilename.substr(0, configFilename.lastIndexOf("."))}.env`; + try { + if (fs.existsSync(configEnvFile)) { + // load content into process.env + loadEnvFile(configEnvFile); + } + } catch (error) { + Log.log(`${configEnvFile} does not exist. ${error.message}`); + } + + // Load config.js and catch errors if not accessible + try { + let configContent = fs.readFileSync(configFilename, "utf-8"); + let configContentFull = configContent; + let configContentRedacted = configContent; + Object.keys(process.env).forEach((env) => { + configContentFull = configContentFull.replaceAll(`\${${env}}`, process.env[env]); + if (env.startsWith("SECRET_")) { + configContentRedacted = configContentRedacted.replaceAll(`"\${${env}}"`, `"**${env}**"`); + configContentRedacted = configContentRedacted.replaceAll(`\${${env}}`, `"**${env}**"`); + } else { + configContentRedacted = configContentRedacted.replaceAll(`\${${env}}`, process.env[env]); + } + }); + const configObj = { + configFilename: configFilename, + configContentFull: configContentFull, + configContentRedacted: configContentRedacted, + redactedConf: Object.assign({}, defaults, requireFromString(configContentRedacted)), + fullConf: Object.assign({}, defaults, requireFromString(configContentFull)) + }; + + if (Object.keys(configObj.fullConf).length === 0) { + Log.error("WARNING! Config file appears empty, maybe missing module.exports last line?"); + } + checkDeprecatedOptions(configObj.fullConf); + + try { + const cfg = `let config = { basePath: "${configObj.fullConf.basePath}"};`; + fs.writeFileSync(`${global.root_path}/config/basepath.js`, cfg, "utf-8"); + } catch (error) { + Log.error(`Could not write config/basepath.js file: ${error.message}`); + } + + return configObj; + + } catch (error) { + if (error.code === "ENOENT") { + Log.error(`Could not find config file: ${configFilename}`); + } else if (error.code === "EACCES") { + Log.error(`No permission to read config file: ${configFilename}`); + } else { + Log.error(`Cannot access config file: ${configFilename}\n${error.message}`); + } + process.exit(1); + } + return {}; +}; + +/** + * Checks the config file using eslint. + * @param {object} configObject the configuration object + */ +const checkConfigFile = (configObject) => { + let configObj = configObject; + if (!configObj) configObj = loadConfig(); + const configFileName = configObj.configFilename; + + // Validate syntax of the configuration file. + Log.info(`Checking config file ${configFileName} ...`); + + // I'm not sure if all ever is utf-8 + const configFile = configObj.configContentFull; + + const errors = linter.verify( + configFile, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + ...globals.node + } + }, + rules: { + "no-sparse-arrays": "error", + "no-undef": "error" + } + }, + configFileName + ); + + if (errors.length === 0) { + Log.info(styleText("green", "Your configuration file doesn't contain syntax errors :)")); + validateModulePositions(configObj.fullConf); + } else { + let errorMessage = "Your configuration file contains syntax errors :("; + + for (const error of errors) { + errorMessage += `\nLine ${error.line} column ${error.column}: ${error.message}`; + } + Log.error(errorMessage); + process.exit(1); + } +}; + +/** + * + * @param {string} data - The content of the configuration file to validate. + */ +const validateModulePositions = (data) => { + Log.info("Checking modules structure configuration ..."); + + const positionList = getModulePositions(); + + // Make Ajv schema configuration of modules config + // Only scan "module" and "position" + const schema = { + type: "object", + properties: { + modules: { + type: "array", + items: { + type: "object", + properties: { + module: { + type: "string" + }, + position: { + type: "string" + } + }, + required: ["module"] } - }); - try { - fs.writeFileSync(discoveredPositionsJSFilename, `const modulePositions=${JSON.stringify(modulePositions)}`); } - catch (error) { - Log.error("unable to write js/positions.js with the discovered module positions\nmake the MagicMirror/js folder writeable by the user starting MagicMirror"); + } + }; + + // Scan all modules + const validate = ajv.compile(schema); + + const valid = validate(data); + if (valid) { + Log.info(styleText("green", "Your modules structure configuration doesn't contain errors :)")); + + // Check for unknown positions (warning only, not an error) + if (data.modules) { + for (const [index, module] of data.modules.entries()) { + if (module.position && !positionList.includes(module.position)) { + Log.warn(`Module ${index} ("${module.module}") uses unknown position: "${module.position}"`); + Log.warn(`Known positions are: ${positionList.join(", ")}`); + } } } - // return the list to the caller - return modulePositions; + } else { + const module = validate.errors[0].instancePath.split("/")[2]; + const position = validate.errors[0].instancePath.split("/")[3]; + let errorMessage = "This module configuration contains errors:"; + errorMessage += `\n${JSON.stringify(data.modules[module], null, 2)}`; + if (position) { + errorMessage += `\n${position}: ${validate.errors[0].message}`; + errorMessage += `\n${JSON.stringify(validate.errors[0].params.allowedValues, null, 2).slice(1, -1)}`; + } else { + errorMessage += validate.errors[0].message; + } + Log.error(errorMessage); + process.exit(1); } }; + +module.exports = { loadConfig, getModulePositions, moduleHasValidPosition, getAvailableModulePositions, checkConfigFile }; diff --git a/package-lock.json b/package-lock.json index fbb49b0300..e815ee3b5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "animate.css": "^4.1.1", "console-stamp": "^3.1.2", "croner": "^9.1.0", - "envsub": "^4.1.0", "eslint": "^9.39.2", "express": "^5.2.1", "feedme": "^2.0.2", @@ -3895,22 +3894,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array-timsort": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", @@ -3918,27 +3901,6 @@ "dev": true, "license": "MIT" }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -4001,30 +3963,6 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4084,12 +4022,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "license": "MIT" - }, "node_modules/bodec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", @@ -4228,24 +4160,6 @@ "@keyv/serialize": "^1.1.1" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -5109,57 +5023,6 @@ "node": ">=20" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", @@ -5272,6 +5135,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "license": "MIT", + "optional": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -5289,6 +5153,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "license": "MIT", + "optional": true, "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -5381,15 +5246,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -5653,48 +5509,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/envsub": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/envsub/-/envsub-4.1.0.tgz", - "integrity": "sha512-B44hta3xNFu6+zDhOha1TIrZkQHGDO3G5K8D2sJIkm/s3XyQjxWBGp1B+b/Y74Go1PqMP+cp8moPR4JullnD9Q==", - "license": "ISC", - "dependencies": { - "bluebird": "^3.7.2", - "chalk": "^3.0.0", - "commander": "^4.0.1", - "diff": "^4.0.1", - "handlebars": "^4.5.3", - "lodash": "^4.17.15", - "replace-last": "^1.2.6", - "string.prototype.matchall": "^4.0.8" - }, - "bin": { - "envsub": "bin/envsub.js", - "envsubh": "bin/envsubh.js" - } - }, - "node_modules/envsub/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/envsub/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -5705,74 +5519,6 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -5810,38 +5556,6 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -6725,21 +6439,6 @@ } } }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -6796,44 +6495,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/gensequence": { "version": "8.0.8", "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-8.0.8.tgz", @@ -6920,23 +6581,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-tsconfig": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", @@ -7097,6 +6741,7 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "license": "MIT", + "optional": true, "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -7201,39 +6846,6 @@ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7248,6 +6860,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", + "optional": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -7255,21 +6868,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -7282,21 +6880,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/hashery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.4.0.tgz", @@ -7611,24 +7194,10 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "engines": { "node": ">= 12" @@ -7669,23 +7238,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -7693,40 +7245,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -7739,34 +7257,6 @@ "node": ">=8" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -7782,39 +7272,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-decimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", @@ -7835,21 +7292,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-fullwidth-code-point": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", @@ -7866,25 +7308,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -7908,30 +7331,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-node-process": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", @@ -7948,22 +7347,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-path-inside": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", @@ -8013,148 +7396,6 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -9434,15 +8675,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -9668,12 +8900,6 @@ "node": ">= 0.6" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" - }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -9785,30 +9011,11 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "license": "MIT", + "optional": true, "engines": { "node": ">= 0.4" } }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -9881,23 +9088,6 @@ "dev": true, "license": "MIT" }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -10514,15 +9704,6 @@ "node": ">=10" } }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -10864,72 +10045,21 @@ "license": "MIT", "dependencies": { "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + }, + "engines": { + "node": ">=8.10.0" } }, - "node_modules/replace-last": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/replace-last/-/replace-last-1.2.6.tgz", - "integrity": "sha512-Cj+MK38VtNu1S5J73mEZY3ciQb9dJajNq1Q8inP4dn/MhJMjHwoAF3Z3FjspwAEV9pfABl565MQucmrjOkty4g==", - "license": "ISC", + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { - "node": ">= 4.0.0" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/require-directory": { @@ -11222,25 +10352,6 @@ ], "license": "MIT" }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -11248,39 +10359,6 @@ "dev": true, "license": "MIT" }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -11415,52 +10493,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -11944,19 +10976,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/strict-event-emitter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", @@ -11991,89 +11010,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", @@ -12821,80 +11757,6 @@ "node": ">= 0.6" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -12917,37 +11779,6 @@ "dev": true, "license": "MIT" }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/undici": { "version": "7.19.2", "resolved": "https://registry.npmjs.org/undici/-/undici-7.19.2.tgz", @@ -13377,91 +12208,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -13488,12 +12234,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", diff --git a/package.json b/package.json index 5486309c81..6e969dc425 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,6 @@ "animate.css": "^4.1.1", "console-stamp": "^3.1.2", "croner": "^9.1.0", - "envsub": "^4.1.0", "eslint": "^9.39.2", "express": "^5.2.1", "feedme": "^2.0.2", diff --git a/tests/configs/port_variable.js.template b/tests/configs/port_variable.js similarity index 100% rename from tests/configs/port_variable.js.template rename to tests/configs/port_variable.js