diff --git a/README.md b/README.md index 28d935d..a7fc00b 100644 --- a/README.md +++ b/README.md @@ -25,42 +25,7 @@ Venus Influx Loader is distributed as: - NPM module: https://www.npmjs.com/package/venus-influx-loader - Docker Image: https://hub.docker.com/r/victronenergy/venus-influx-loader -## Development - -To start experimenting, please install [Docker Desktop](https://www.docker.com/products/docker-desktop/) and use the following steps to spin up a quick dev environment: - -### Build Venus Influx Loader docker image locally - -``` -$ export OWNER="martin" -$ (cd docker && ./build-dev-image.sh) -``` - -### Run InfluxDB docker image instance locally - -``` -$ (cd docker && ./run-influxdb.sh) -``` - -### Run Venus Influx Loader docker image locally - -``` -$ export OWNER="martin" -$ (cd docker && ./run-dev-image.sh) -``` - -Navigate to http://localhost:8088 to access Venus Influx Loader Admin UI, use `admin`, `admin` to sign in, and configure what Venus devices to watch. - -Install Venus Grafana by following the instructions here: https://github.com/victronenergy/venus-grafana. - - -## Source Code Details - -The repository is spit into the following components: - -## Server - -The directory `src/server` contains node.js based server watching Venus devices using MQTT and storing real time measurements into InfluxDB. It vends two binaries: `bin/venus-influx-loader`, and `bin/venus-upnp-browser`. +## Advanced Configuration ### Venus Influx Loader @@ -68,7 +33,7 @@ Venus Influx Loader allows MQTT connection to the Venus devices running on the s Configuration details and necessary usernames and passwords are stored in `config.json`, and `secrets.json` that are looked up under `--config-path` (`/config` by default). Config Path needs to be writable. -> TODO: should not be needed to config path to be writable in production deployments. +> TODO: should not be needed for config path to be writable in production deployments. Configuration files can either be created manually, or by starting the Venus Influx Loader, and accessing the Admin UI by browsing to `http://localhost:8088`. The default usernname and password is `admin`, `admin`. @@ -94,15 +59,25 @@ Options: -h, --help display help for command ``` +#### Tip: Run Influx Loader headless + For production use, once the system is configured `--disable-admin-api` can be used to run the `venus-influx-loader` headless. +#### Tip: Run Influx Loader behind Load Balancer with your own authentication + +Use `--disable-admin-api-auth` to skip basic authentication mechanism protecting access to Admin Web User Interface. That way you can implement your own authentication mechanism. + +#### Tip: Customize Admin UI + +Use `--hide-settings-*` options to tweak the Admin UI and hide parts of the settings that you do not want to accidentally change. For example InfluxDB settings do not need to be overriden once configured. + ### Venus UPNP Browser Venus Influx Loader contains built in mechanism to discover Venus devices running on the same network via UPNP, that is enabled by default. In cases where `venus-influx-loader` may not have access to local network UPNP, such as when it runs in isolated docker network, or in docker bridge mode, `venus-upnp-browser` can be used to discover Venus devices over UPNP. -The reason behind spliting these two functionalities among two binaries is: +The reason behind spliting the UPNP discovery into separate binary is: - ~~Docker container running in host networking mode can not expose ports under Docker Desktop for Mac and Windows (https://github.com/docker/for-mac/issues/6185). So `venus-influx-loader` running in `host` networking mode can access UPNP, but will not get access to port `8088` to enable Admin UI.~~ - Docker Desktop since version 4.29 (https://docs.docker.com/network/drivers/host/#docker-desktop) allows to experimentally enable host networking mode in which a container running in host network mode can actually expose UDP/TCP ports and gain access to the host network. @@ -111,7 +86,7 @@ The reason behind spliting these two functionalities among two binaries is: To workaround the limitations, `venus-upnp-browser` actually runs in docker host mode network - having access to both local area UPNP, as well as `venus-influx-loader` admin port exposed via docker, `venus-upnp-browser` communicates discovered Venus devices and diagnostic information to `venus-influx-loader` via `--discovery-api`. -Note: `host` and `bridge` network mode work properly only on Linux. UPNP does not work in Docker Desktop for Mac at all. +Note: `host` and `bridge` network mode work properly only on Linux, support is being added to Docker Desktop for Windows and Mac incrementally. UPNP does not work in Docker Desktop for Mac at all. ``` € npx venus-upnp-browser --help @@ -125,28 +100,66 @@ Options: -h, --help display help for command ``` +## Development + +To start experimenting, please install [Docker Desktop](https://www.docker.com/products/docker-desktop/) and use the following steps to spin up a quick dev environment: + +### Build Venus Influx Loader docker image locally + +``` +$ export OWNER="martin" +$ (cd docker && ./build-dev-image.sh) +``` + +### Run InfluxDB docker image instance locally + +``` +$ (cd docker && ./run-influxdb.sh) +``` + +### Run Venus Influx Loader docker image locally + +``` +$ export OWNER="martin" +$ (cd docker && ./run-dev-image.sh) +``` + +Navigate to http://localhost:8088 to access Venus Influx Loader Admin UI, use `admin`, `admin` to sign in, and configure what Venus devices to watch. + +Install Venus Grafana by following the instructions here: https://github.com/victronenergy/venus-grafana. + + +## Source Code Details + +The repository is spit into the following components: + +## Server + +The directory `src/bin`, and `src/server` contains node.js based server watching Venus devices using MQTT and storing real time measurements into InfluxDB. It vends two binaries: `venus-influx-loader`, and `venus-upnp-browser`. + +Server is written in TypeScript/JavaScript and compiled using `tsc`. + ### Venus Influx Loader Admin UI -The directory `src/client` contains react.js based web admin interface to manage configuration of `src/server`. Client Admin UI app uses `webpack` to compile the browser JavaScript, HTML, and CSS code. +The directory `src/client` contains react.js based web admin interface to manage configuration of `src/server`. Influx Loader Admin UI app uses `webpack` to compile the browser JavaScript, HTML, and CSS code. ## Development ### Start venus-influx-loader, and client in hot reloading mode +First install all required dependencies: + ``` $ npm install -$ npm run dev ``` -This command will use [`concurrently`](https://www.npmjs.com/package/concurrently) command to start hot reloading development instances of both the `src/server`, and `src/client`, so whenever you change source code in `src/` everything should get restarted/reloaded automatically. - -Alternatively you can spin up only hot reloading server, or only hot reloading client via: +Then spin up hot reloading Influx Loader: ``` $ npm run watch-influx-loader ``` -and +and Influx Loader Admin UI: ``` $ npm run watch-client diff --git a/babel.config.json b/babel.config.json index 735eeff..3bf3681 100644 --- a/babel.config.json +++ b/babel.config.json @@ -1,5 +1,7 @@ { "presets": [ - ["@babel/preset-react", { "runtime": "automatic" }], ["@babel/preset-env"] - ], + ["@babel/preset-react", { "runtime": "automatic" }], + ["@babel/preset-env"], + ["@babel/preset-typescript"] + ] } diff --git a/bin/venus-influx-loader.js b/bin/venus-influx-loader.js deleted file mode 100755 index cbcf604..0000000 --- a/bin/venus-influx-loader.js +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node - -const commander = require('commander') -const program = commander.program -const buildVersion = require('../dist/buildInfo').buildVersion - -const Server = require('../src/server/server') - -program - .version(buildVersion) - .description( - 'Monitor Venus devices and capture & store realtime data to serve Grafana' - ) - .option( - '-c, --config-path ', - 'path to store config.json and secrets.json', - '/config' - ) - .option( - '-p, --port ', - 'http port used by Admin Web User Interface and Grafana JSON datasource', - 8088 - ) - .option( - '--disable-admin-api', - 'disable Admin Web User Interface and /admin-api/ endpoint' - ) - .option( - '--disable-admin-api-auth', - 'disable password protection for Admin Web User Interface and /admin-api/ endpoint' - ) - .option( - '--disable-grafana-api', - 'disable Grafana JSON datasource /grafana-api/ endpoint' - ) - .option( - '--enable-discovery-api', - 'enable venus-upnp-browser /discovery-api/ endpoint' - ) - .option( - '--hide-settings-influxdb' - ) - .option( - '--hide-settings-security' - ) - .option( - '--hide-settings-venus-discovery' - ) - .option( - '--hide-settings-venus-manual' - ) - .option( - '--hide-settings-venus-vrm' - ) - -program.parse() -const options = program.opts() - -function log (message) { - console.log(`${program.name()}: ${message}`) -} - -const discoveryApiEndpoint = options.enableDiscoveryApi - ? '/discovery-api/' - : undefined -const adminApiEndpoint = options.disableAdminApi ? undefined : '/admin-api/' -const adminApiEndpointAuthEnabled = options.disableAdminApiAuth ? false : true -const grafanaApiEndpoint = options.disableGrafanaApi - ? undefined - : '/grafana-api/' -const port = options.port - -log('Use --help to learn how to use this program') -log(`Config Path: ${options.configPath}`) -log(`Discovery API: ${discoveryApiEndpoint || 'disabled'}`) -log(`Admin API: ${adminApiEndpoint || 'disabled'}`) -log(`Grafana JSON Datasource API: ${grafanaApiEndpoint || 'disabled'}`) -log(`API Port: ${adminApiEndpoint || grafanaApiEndpoint ? port : 'disabled'}`) - -// exit on Ctrl-C -process.on('SIGINT', function () { - server.stop() - process.exit() -}) - -const server = new Server({ - configPath: options.configPath, - port: port, - discoveryApiEndpoint: discoveryApiEndpoint, - adminApiEndpoint: adminApiEndpoint, - adminApiEndpointAuthEnabled: adminApiEndpointAuthEnabled, - grafanaApiEndpoint: grafanaApiEndpoint, - showEditDiscoverySettings: !options.hideSettingsVenusDiscovery, - showEditVRMSettings: !options.hideSettingsVenusVRM, - showEditManualSettings: !options.hideSettingsVenusManual, - showEditSecuritySettings: (!options.hideSettingsSecurity && adminApiEndpointAuthEnabled), - showEditInfluxDBSettings: !options.hideSettingsInfluxdb, -}) - -// start server -server.start() diff --git a/bin/venus-upnp-browser.js b/bin/venus-upnp-browser.js deleted file mode 100755 index 2558c50..0000000 --- a/bin/venus-upnp-browser.js +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node - -const commander = require('commander') -const program = commander.program -const buildVersion = require('../dist/buildInfo').buildVersion - -const axios = require('axios') - -const upnp = require('../src/server/upnp') - -program - .version(buildVersion) - .description('Discover Venus devices running on local network using UPNP') - .option( - '-d, --discovery-api ', - 'discovery api endpoint', - 'http://localhost:8088/discovery-api/' - ) - -program.parse() -const options = program.opts() - -function log (message) { - console.log(`${program.name()}: ${message}`) -} - -log('Use --help to learn how to use this program') -log(`Discovery API: ${options.discoveryApi}`) - -// endpoints used to talk to venus-influx-loader -const logEndpoint = new URL('log', options.discoveryApi) -const discoveryEndpoint = new URL('upnpDiscovered', options.discoveryApi) - -// upnp browser -const browser = upnp({ - getLogger: name => { - return { - info: message => { - log(message) - postLog(logEndpoint, { level: 'info', message: message }) - }, - error: message => { - log(message) - postLog(logEndpoint, { level: 'error', message: message }) - } - } - }, - emit: (event, data) => { - if (event === 'upnpDiscovered') { - postDiscovery(discoveryEndpoint, data) - } - } -}) - -// cache discovered venus devices and log entries -// so they can be posted to discoveryApi when ready -let cachedLogs = [] -let cachedDiscovery = [] - -function postLog (endpoint, info) { - axios - .post(logEndpoint, info) - .then(response => response.data) - .catch(err => { - log(`Failed to postLog to ${endpoint}, error: ${err.message}`) - cachedLogs.push(info) - }) -} - -function postDiscovery (endpoint, info) { - axios - .post(discoveryEndpoint, info) - .then(response => response.data) - .catch(err => { - log(`Failed to postDiscovery to ${endpoint}, error: ${err.message}`) - cachedDiscovery.push(info) - }) -} - -// flush all cached discovered devices and log entries every 5 sec -setInterval(() => { - const logs = cachedLogs - const discovered = cachedDiscovery - cachedLogs = [] - cachedDiscovery = [] - logs.forEach(log => { - postLog(logEndpoint, log) - }) - discovered.forEach(info => { - postDiscovery(discoveryEndpoint, info) - }) -}, 5000) - -// exit on Ctrl-C -process.on('SIGINT', function () { - browser.stop() - process.exit() -}) - -// start browsing -browser.start() diff --git a/docker/Dockerfile b/docker/Dockerfile index 9a98636..62e8a27 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -17,12 +17,10 @@ RUN apt-get update && apt-get install -y curl WORKDIR /venus-influx-loader -COPY --from=build /venus-influx-loader/bin ./bin -COPY --from=build /venus-influx-loader/dist ./dist -COPY --from=build /venus-influx-loader/src/server ./src/server COPY --from=build /venus-influx-loader/package*.json ./ +COPY --from=build /venus-influx-loader/dist/* ./ -RUN npm install --omit=dev +RUN npm install --omit=dev --ignore-scripts USER root RUN mkdir -p /config && chown -R node /config diff --git a/eslint.config.js b/eslint.config.js index 05223cd..788d002 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,12 +1,12 @@ -const eslint = require("@eslint/js") -const babelParser = require("@babel/eslint-parser") -const reactPlugin = require("eslint-plugin-react") -const prettierPluginRecommended = require("eslint-plugin-prettier/recommended") -const globals = require("globals") -const confusingBrowserGlobals = require("confusing-browser-globals") +import { configs } from "@eslint/js" +import babelParser from "@babel/eslint-parser" +import reactPlugin, { configs as _configs } from "eslint-plugin-react" +import prettierPluginRecommended from "eslint-plugin-prettier/recommended" +import { node, browser } from "globals" +import confusingBrowserGlobals from "confusing-browser-globals" -module.exports = [ - eslint.configs.recommended, +export default [ + configs.recommended, prettierPluginRecommended, { files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"], @@ -14,8 +14,8 @@ module.exports = [ react: reactPlugin, }, rules: { - ...reactPlugin.configs.recommended.rules, - ...reactPlugin.configs["jsx-runtime"].rules, + ..._configs.recommended.rules, + ..._configs["jsx-runtime"].rules, "no-unused-vars": [ "error", { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }, @@ -26,7 +26,7 @@ module.exports = [ ecmaVersion: 2022, sourceType: "module", globals: { - ...globals.node, + ...node, }, }, settings: { @@ -39,7 +39,7 @@ module.exports = [ files: ["src/client/**/*.{js,jsx,mjs,cjs,ts,tsx}"], languageOptions: { globals: { - ...globals.browser, + ...browser, VENUS_INFLUX_LOADER_ADMIN_API_PORT: true, VENUS_INFLUX_LOADER_BUILD_VERSION: true, }, @@ -52,7 +52,7 @@ module.exports = [ files: ["src/server/**/*.{js,jsx,mjs,cjs,ts,tsx}"], languageOptions: { globals: { - ...globals.node, + ...node, }, }, }, diff --git a/generateBuildInfo.sh b/generateBuildInfo.sh new file mode 100755 index 0000000..118a82c --- /dev/null +++ b/generateBuildInfo.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +BUILD_VERSION=${BUILD_VERSION:=$(git describe --tags)} + +mkdir -p ./dist +echo "// @ts-check\nmodule.exports.buildVersion=\"${BUILD_VERSION}\"" > ./dist/buildInfo.js diff --git a/package-lock.json b/package-lock.json index a532e19..b716d2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,19 +26,21 @@ "xml2js": "^0.6.2" }, "bin": { - "venus-influx-loader": "bin/venus-influx-loader.js", - "venus-upnp-browser": "bin/venus-upnp-browser.js" + "venus-influx-loader": "dist/bin/venus-influx-loader.js", + "venus-upnp-browser": "dist/bin/venus-upnp-browser.js" }, "devDependencies": { "@babel/core": "^7.25.8", "@babel/eslint-parser": "^7.25.1", "@babel/preset-env": "^7.25.8", "@babel/preset-react": "^7.25.7", + "@babel/preset-typescript": "^7.25.7", "@coreui/coreui": "^5", "@coreui/icons": "^3.0.1", "@coreui/icons-react": "^2.3.0", "@coreui/react": "^5", "@popperjs/core": "^2.11.8", + "@types/node": "^22.7.4", "autoprefixer": "^10.4.20", "axios-hooks": "^5.0.2", "babel-loader": "^9.2.1", @@ -70,10 +72,10 @@ "sass-loader": "^16.0.1", "source-list-map": "2.0.1", "style-loader": "^4.0.0", + "typescript": "^5.6.2", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.1.0", - "webpack-shell-plugin-next": "^2.3.2" + "webpack-dev-server": "^5.1.0" }, "engines": { "node": ">=18.x <=20.x" @@ -97,6 +99,7 @@ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" @@ -110,6 +113,7 @@ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -119,6 +123,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.25.7", @@ -168,6 +173,7 @@ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", @@ -183,6 +189,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.25.7" }, @@ -195,6 +202,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", "@babel/types": "^7.25.7" @@ -208,6 +216,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.7", "@babel/helper-validator-option": "^7.25.7", @@ -224,6 +233,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-member-expression-to-functions": "^7.25.7", @@ -245,6 +255,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "regexpu-core": "^6.1.1", @@ -278,6 +289,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", "@babel/types": "^7.25.7" @@ -291,6 +303,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", "@babel/types": "^7.25.7" @@ -304,6 +317,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.7", "@babel/helper-simple-access": "^7.25.7", @@ -322,6 +336,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.25.7" }, @@ -334,6 +349,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -343,6 +359,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-wrap-function": "^7.25.7", @@ -360,6 +377,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.7", "@babel/helper-optimise-call-expression": "^7.25.7", @@ -377,6 +395,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", "@babel/types": "^7.25.7" @@ -390,6 +409,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.7", "@babel/types": "^7.25.7" @@ -403,6 +423,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -412,6 +433,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -421,6 +443,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -430,6 +453,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.25.7", "@babel/traverse": "^7.25.7", @@ -444,6 +468,7 @@ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.25.7", "@babel/types": "^7.25.7" @@ -457,6 +482,7 @@ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", @@ -472,6 +498,7 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.25.8" }, @@ -487,6 +514,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/traverse": "^7.25.7" @@ -503,6 +531,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -518,6 +547,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -533,6 +563,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", @@ -550,6 +581,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/traverse": "^7.25.7" @@ -578,6 +610,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -593,6 +626,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -608,6 +642,23 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz", + "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==", + "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -639,6 +690,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -654,6 +706,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.8.tgz", "integrity": "sha512-9ypqkozyzpG+HxlH4o4gdctalFGIjjdufzo7I2XPda0iBnZ6a+FO0rIEQcdSPXp02CkvGsII1exJhmROPQd5oA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-remap-async-to-generator": "^7.25.7", @@ -671,6 +724,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz", "integrity": "sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", @@ -688,6 +742,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -703,6 +758,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -718,6 +774,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -734,6 +791,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz", "integrity": "sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -750,6 +808,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-compilation-targets": "^7.25.7", @@ -770,6 +829,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -779,6 +839,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/template": "^7.25.7" @@ -795,6 +856,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -810,6 +872,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -826,6 +889,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -841,6 +905,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -857,6 +922,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz", "integrity": "sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -872,6 +938,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -888,6 +955,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz", "integrity": "sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -903,6 +971,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" @@ -919,6 +988,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", @@ -936,6 +1006,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz", "integrity": "sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -951,6 +1022,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -966,6 +1038,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz", "integrity": "sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -981,6 +1054,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -996,6 +1070,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1012,6 +1087,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", @@ -1029,6 +1105,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", @@ -1047,6 +1124,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1063,6 +1141,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1079,6 +1158,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1094,6 +1174,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz", "integrity": "sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1109,6 +1190,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz", "integrity": "sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1124,6 +1206,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz", "integrity": "sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", @@ -1141,6 +1224,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-replace-supers": "^7.25.7" @@ -1157,6 +1241,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz", "integrity": "sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1172,6 +1257,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz", "integrity": "sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" @@ -1188,6 +1274,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1203,6 +1290,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1219,6 +1307,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz", "integrity": "sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-create-class-features-plugin": "^7.25.7", @@ -1236,6 +1325,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1251,6 +1341,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.7.tgz", "integrity": "sha512-r0QY7NVU8OnrwE+w2IWiRom0wwsTbjx4+xH2RTd7AVdof3uurXOF+/mXHQDRk+2jIvWgSaCHKMgggfvM4dyUGA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1266,6 +1357,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-module-imports": "^7.25.7", @@ -1285,6 +1377,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.7.tgz", "integrity": "sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-transform-react-jsx": "^7.25.7" }, @@ -1300,6 +1393,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.7.tgz", "integrity": "sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1316,6 +1410,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "regenerator-transform": "^0.15.2" @@ -1332,6 +1427,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1347,6 +1443,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1362,6 +1459,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" @@ -1378,6 +1476,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1393,6 +1492,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1408,6 +1508,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1418,11 +1519,32 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.7.tgz", + "integrity": "sha512-VKlgy2vBzj8AmEzunocMun2fF06bsSWV+FvVXohtL6FGve/+L217qhHxRTVGHEDO/YR8IANcjzgJsd04J8ge5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-syntax-typescript": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1438,6 +1560,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1454,6 +1577,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1470,6 +1594,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7" @@ -1486,6 +1611,7 @@ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.8.tgz", "integrity": "sha512-58T2yulDHMN8YMUxiLq5YmWUnlDCyY1FsHM+v12VMx+1/FlrUj5tY50iDCpofFQEM8fMYOaY9YRvym2jcjn1Dg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.8", "@babel/helper-compilation-targets": "^7.25.7", @@ -1582,6 +1708,7 @@ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.7.tgz", "integrity": "sha512-GjV0/mUEEXpi1U5ZgDprMRRgajGMRW3G5FjMr5KLKD8nT2fTG8+h/klV3+6Dm5739QE+K5+2e91qFKAYI3pmRg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-validator-option": "^7.25.7", @@ -1597,6 +1724,26 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.25.7.tgz", + "integrity": "sha512-rkkpaXJZOFN45Fb+Gki0c+KMIglk4+zZXOoMJuyEK8y8Kkc8Jd3BDmP7qPsz0zQMJj+UD7EprF+AqAXcILnexw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-typescript": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz", @@ -1614,6 +1761,7 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.7", "@babel/parser": "^7.25.7", @@ -1628,6 +1776,7 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.7", "@babel/generator": "^7.25.7", @@ -1656,6 +1805,7 @@ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.7", "@babel/helper-validator-identifier": "^7.25.7", @@ -1842,6 +1992,7 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1874,6 +2025,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -1883,6 +2035,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.0", "@humanwhocodes/retry": "^0.3.0" @@ -1909,6 +2062,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -2312,11 +2466,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -2785,6 +2940,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -3405,6 +3561,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001663", "electron-to-chromium": "^1.5.28", @@ -3524,13 +3681,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4584,10 +4743,11 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.36", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.36.tgz", - "integrity": "sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==", - "dev": true + "version": "1.5.38", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.38.tgz", + "integrity": "sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg==", + "dev": true, + "license": "ISC" }, "node_modules/emits": { "version": "3.0.0", @@ -4869,6 +5029,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -4878,6 +5039,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", @@ -5983,6 +6145,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -7214,6 +7377,7 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -9034,13 +9198,15 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -9058,6 +9224,7 @@ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -9085,6 +9252,7 @@ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", @@ -9101,13 +9269,15 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regjsparser": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" }, @@ -10286,6 +10456,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -10612,6 +10783,20 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", @@ -10633,15 +10818,17 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10651,6 +10838,7 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -10664,6 +10852,7 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10673,6 +10862,7 @@ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -11001,16 +11191,6 @@ "node": ">=10.0.0" } }, - "node_modules/webpack-shell-plugin-next": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/webpack-shell-plugin-next/-/webpack-shell-plugin-next-2.3.2.tgz", - "integrity": "sha512-VAM1TcncZJHVkXDLlqXt2YMUEYuJca8MRqPThXX0SzxKetXCE16eTzEWaF3a/QbLF2j3grBMosCpnLzxXyu3cA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "webpack": "^5.18.0" - } - }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -11165,6 +11345,7 @@ "version": "3.15.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", "integrity": "sha512-RhruH2Cj0bV0WgNL+lOfoUBI4DVfdUNjVnJGVovWZmrcKtrFTTRzgXYK2O9cymSGjrERCtaAeHwMNnUWXlwZow==", + "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", diff --git a/package.json b/package.json index 378bb98..110f0ea 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,19 @@ "version": "1.0.0", "description": ".", "scripts": { - "start": "bin/venus-influx-loader.js", + "prebuild": "./generateBuildInfo.sh", + "build:bin": "tsc", + "postbuild:bin": "chmod +x dist/bin/*.js", + "build:client": "webpack build --mode production --env production --progress", + "build": "npm run build:bin && npm run build:client", + "clean": "rimraf ./dist", "lint": "eslint src/ --fix", - "clean": "rimraf ./build", + "type-check": "tsc --noEmit", "watch-client": "webpack serve --mode development --progress --hot", - "watch-influx-loader": "babel-watch bin/venus-influx-loader.js -- --config-path ./config/ --port 8088", - "watch-upnp-browser": "babel-watch bin/venus-upnp-browser.js", - "build": "webpack build --mode production --env production --progress", - "dev": "VIL_INFLUXDB_URL=http://localhost:8086 VIL_INFLUXDB_USERNAME=s3cr4t VIL_INFLUXDB_PASSWORD=s3cr4t concurrently npm:watch-influx-loader npm:watch-client" + "watch-influx-loader": "concurrently npm:build:bin \"babel-watch dist/bin/venus-influx-loader.js -- --config-path ./config/ --port 8088\"", + "watch-upnp-browser": "concurrently npm:build:bin \"babel-watch dist/bin/venus-upnp-browser.js\"", + "start": "VIL_INFLUXDB_URL=http://localhost:8086 VIL_INFLUXDB_USERNAME=s3cr4t VIL_INFLUXDB_PASSWORD=s3cr4t concurrently npm:watch-influx-loader npm:watch-client", + "prepare": "npm run build" }, "repository": { "type": "git", @@ -32,8 +37,8 @@ } }, "bin": { - "venus-influx-loader": "./bin/venus-influx-loader.js", - "venus-upnp-browser": "./bin/venus-upnp-browser.js" + "venus-influx-loader": "./dist/bin/venus-influx-loader.js", + "venus-upnp-browser": "./dist/bin/venus-upnp-browser.js" }, "author": "Scott Bender ", "contributors": [ @@ -70,11 +75,13 @@ "@babel/eslint-parser": "^7.25.1", "@babel/preset-env": "^7.25.8", "@babel/preset-react": "^7.25.7", + "@babel/preset-typescript": "^7.25.7", "@coreui/coreui": "^5", "@coreui/icons": "^3.0.1", "@coreui/icons-react": "^2.3.0", "@coreui/react": "^5", "@popperjs/core": "^2.11.8", + "@types/node": "^22.7.4", "autoprefixer": "^10.4.20", "axios-hooks": "^5.0.2", "babel-loader": "^9.2.1", @@ -106,10 +113,10 @@ "sass-loader": "^16.0.1", "source-list-map": "2.0.1", "style-loader": "^4.0.0", + "typescript": "^5.6.2", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.1.0", - "webpack-shell-plugin-next": "^2.3.2" + "webpack-dev-server": "^5.1.0" }, "browser": { "fs": false, diff --git a/src/bin/venus-influx-loader.ts b/src/bin/venus-influx-loader.ts new file mode 100755 index 0000000..42fcbd8 --- /dev/null +++ b/src/bin/venus-influx-loader.ts @@ -0,0 +1,88 @@ +#!/usr/bin/env node + +import commander from "commander" +const program = commander.program +const buildVersion = require("../buildInfo").buildVersion + +import Server from "../server/server.js" + +program + .version(buildVersion) + .description( + "Monitor Venus devices and capture & store realtime data to serve Grafana", + ) + .option( + "-c, --config-path ", + "path to store config.json and secrets.json", + "/config", + ) + .option( + "-p, --port ", + "http port used by Admin Web User Interface and Grafana JSON datasource", + "8088", + ) + .option( + "--disable-admin-api", + "disable Admin Web User Interface and /admin-api/ endpoint", + ) + .option( + "--disable-admin-api-auth", + "disable password protection for Admin Web User Interface and /admin-api/ endpoint", + ) + .option( + "--disable-grafana-api", + "disable Grafana JSON datasource /grafana-api/ endpoint", + ) + .option( + "--enable-discovery-api", + "enable venus-upnp-browser /discovery-api/ endpoint", + ) + .option("--hide-settings-influxdb") + .option("--hide-settings-security") + .option("--hide-settings-venus-discovery") + .option("--hide-settings-venus-manual") + .option("--hide-settings-venus-vrm") + +program.parse() +const options = program.opts() + +function log(message: string) { + console.log(`${program.name()}: ${message}`) +} + +const discoveryApi = options.enableDiscoveryApi ? "/discovery-api/" : undefined +const adminApi = options.disableAdminApi ? undefined : "/admin-api/" +const adminApiAuthEnabled = options.disableAdminApiAuth ? false : true +const grafanaApi = options.disableGrafanaApi ? undefined : "/grafana-api/" +const port = options.port + +log("Use --help to learn how to use this program") +log(`Config Path: ${options.configPath}`) +log(`Discovery API: ${discoveryApi || "disabled"}`) +log(`Admin API: ${adminApi || "disabled"}`) +log(`Grafana JSON Datasource API: ${grafanaApi || "disabled"}`) +log(`API Port: ${adminApi || grafanaApi ? port : "disabled"}`) + +// exit on Ctrl-C +process.on("SIGINT", function () { + server.stop() + process.exit() +}) + +const server = new Server({ + configPath: options.configPath, + port: Number(port), + discoveryApiEndpoint: discoveryApi, + adminApiEndpoint: adminApi, + adminApiEndpointAuthEnabled: adminApiAuthEnabled, + grafanaApiEndpoint: grafanaApi, + showEditDiscoverySettings: !options.hideSettingsVenusDiscovery, + showEditVRMSettings: !options.hideSettingsVenusVRM, + showEditManualSettings: !options.hideSettingsVenusManual, + showEditSecuritySettings: + !options.hideSettingsSecurity && adminApiAuthEnabled, + showEditInfluxDBSettings: !options.hideSettingsInfluxdb, +}) + +// start server +server.start() diff --git a/src/bin/venus-upnp-browser.ts b/src/bin/venus-upnp-browser.ts new file mode 100755 index 0000000..1a1a448 --- /dev/null +++ b/src/bin/venus-upnp-browser.ts @@ -0,0 +1,110 @@ +#!/usr/bin/env node + +import commander from "commander" +const program = commander.program +const buildVersion = require("../buildInfo").buildVersion + +import axios from "axios" + +import upnp from "../server/upnp.js" + +program + .version(buildVersion) + .description("Discover Venus devices running on local network using UPNP") + .option( + "-d, --discovery-api ", + "discovery api endpoint", + "http://localhost:8088/discovery-api/", + ) + +program.parse() +const options = program.opts() + +function log(message: string) { + console.log(`${program.name()}: ${message}`) +} + +log("Use --help to learn how to use this program") +log(`Discovery API: ${options.discoveryApi}`) + +// endpoints used to talk to venus-influx-loader +const logEndpoint = new URL("log", options.discoveryApi) +const discoveryEndpoint = new URL("upnpDiscovered", options.discoveryApi) + +// upnp browser +const browser = upnp({ + getLogger: (_name: string) => { + return { + info: (message: string) => { + log(message) + postLog(logEndpoint, { level: "info", message: message }) + }, + error: (message: string) => { + log(message) + postLog(logEndpoint, { level: "error", message: message }) + }, + } + }, + emit: (event: string, data: any) => { + if (event === "upnpDiscovered") { + postDiscovery(discoveryEndpoint, data) + } + }, +}) + +interface LogMessage { + level: string + message: string +} + +interface DiscoveryMessage { + data: string +} + +// cache discovered venus devices and log entries +// so they can be posted to discoveryApi when ready +let cachedLogs: LogMessage[] = [] +let cachedDiscovery: DiscoveryMessage[] = [] + +function postLog(endpoint: URL, info: LogMessage) { + axios + .post(endpoint.toString(), info) + .then((response) => response.data) + .catch((err) => { + log(`Failed to postLog to ${endpoint}, error: ${err.message}`) + cachedLogs.push(info) + }) +} + +function postDiscovery(endpoint: URL, info: DiscoveryMessage) { + axios + .post(endpoint.toString(), info) + .then((response) => response.data) + .catch((err) => { + log(`Failed to postDiscovery to ${endpoint}, error: ${err.message}`) + cachedDiscovery.push(info) + }) +} + +// flush all cached discovered devices and log entries every 5 sec +setInterval(() => { + const logs = cachedLogs + const discovered = cachedDiscovery + cachedLogs = [] + cachedDiscovery = [] + logs.forEach((log) => { + postLog(logEndpoint, log) + }) + discovered.forEach((info) => { + postDiscovery(discoveryEndpoint, info) + }) +}, 5000) + +// exit on Ctrl-C +process.on("SIGINT", function () { + browser.stop() + process.exit() +}) + +// start browsing +browser.start() diff --git a/src/server/loader.js b/src/server/loader.js index 6b7d71f..e6fc84f 100644 --- a/src/server/loader.js +++ b/src/server/loader.js @@ -1,7 +1,7 @@ const _ = require("lodash") const mqtt = require("mqtt") const ignoredMeasurements = require("./ignoredMeasurements") -const buildVersion = require("../../dist/buildInfo").buildVersion +const buildVersion = require("../buildInfo").buildVersion const collectStatsInterval = 5 const keepAliveInterval = 30 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..35011f7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "skipLibCheck": true + }, + "include": ["./src/**/*"], + "exclude": ["node_modules", "dist", "src/client"] +} diff --git a/webpack.config.js b/webpack.config.js index b0a5309..1cedb1c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,17 +1,13 @@ const webpack = require("webpack") const path = require("node:path") -const childProcess = require("node:child_process") const MiniCssExtractPlugin = require("mini-css-extract-plugin") const HtmlWebpackPlugin = require("html-webpack-plugin") const TerserPlugin = require("terser-webpack-plugin") const { CleanWebpackPlugin } = require("clean-webpack-plugin") -const WebpackShellPluginNext = require("webpack-shell-plugin-next") const SRC_DIR = path.resolve(__dirname, "src/client") -const BUILD_DIR = path.resolve(__dirname, "dist") -const BUILD_VERSION = - process.env.BUILD_VERSION || - childProcess.execSync("git describe --tags").toString().trim() +const BUILD_DIR = path.resolve(__dirname, "dist/client") +const BUILD_VERSION = require("./dist/buildInfo").buildVersion console.log("BUILD_DIR", BUILD_DIR) console.log("SRC_DIR", SRC_DIR) @@ -125,7 +121,7 @@ module.exports = (env, argv) => { // in dev, hardcode to 8088, as webpack will spin up webpack dev server on random port // and window.location will point to webpack dev server, instead of venus influx loader VENUS_INFLUX_LOADER_ADMIN_API_PORT: env.production ? undefined : 8088, - VENUS_INFLUX_LOADER_BUILD_VERSION: `\"${BUILD_VERSION}\"`, + VENUS_INFLUX_LOADER_BUILD_VERSION: `"${BUILD_VERSION}"`, }), new CleanWebpackPlugin(), new MiniCssExtractPlugin(), @@ -133,15 +129,6 @@ module.exports = (env, argv) => { inject: true, template: path.join(SRC_DIR, "public/index.html"), }), - new WebpackShellPluginNext({ - onBuildEnd: { - scripts: [ - `echo module.exports.buildVersion=\\"${BUILD_VERSION}\\" >> ./dist/buildInfo.js`, - ], - blocking: true, - parallel: false, - }, - }), ], optimization: { minimize: true,