diff --git a/.eslintrc.js b/.eslintrc.js index b0934d6d8..4713799d7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,9 @@ module.exports = { + ignorePatterns: [ + "test/*", + "server/modules/apicache/*", + "src/util.js" + ], root: true, env: { browser: true, @@ -17,39 +22,48 @@ module.exports = { requireConfigFile: false, }, rules: { - "linebreak-style": ["error", "unix"], - "camelcase": ["warn", { + "yoda": "error", + eqeqeq: [ "warn", "smart" ], + "linebreak-style": [ "error", "unix" ], + "camelcase": [ "warn", { "properties": "never", "ignoreImports": true }], - // override/add rules settings here, such as: - // 'vue/no-unused-vars': 'error' - "no-unused-vars": "warn", + "no-unused-vars": [ "warn", { + "args": "none" + }], indent: [ "error", 4, { - ignoredNodes: ["TemplateLiteral"], + ignoredNodes: [ "TemplateLiteral" ], SwitchCase: 1, }, ], - quotes: ["warn", "double"], - semi: "warn", - "vue/html-indent": ["warn", 4], // default: 2 + quotes: [ "error", "double" ], + semi: "error", + "vue/html-indent": [ "error", 4 ], // default: 2 "vue/max-attributes-per-line": "off", "vue/singleline-html-element-content-newline": "off", "vue/html-self-closing": "off", + "vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675 "vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly - "no-multi-spaces": ["error", { + "vue/multi-word-component-names": "off", + "no-multi-spaces": [ "error", { ignoreEOLComments: true, }], - "space-before-function-paren": ["error", { + "array-bracket-spacing": [ "warn", "always", { + "singleValue": true, + "objectsInArrays": false, + "arraysInArrays": false + }], + "space-before-function-paren": [ "error", { "anonymous": "always", "named": "never", "asyncArrow": "always" }], "curly": "error", - "object-curly-spacing": ["error", "always"], + "object-curly-spacing": [ "error", "always" ], "object-curly-newline": "off", "object-property-newline": "error", "comma-spacing": "error", @@ -59,37 +73,37 @@ module.exports = { "keyword-spacing": "warn", "space-infix-ops": "warn", "arrow-spacing": "warn", - "no-trailing-spaces": "warn", - "no-constant-condition": ["error", { + "no-trailing-spaces": "error", + "no-constant-condition": [ "error", { "checkLoops": false, }], "space-before-blocks": "warn", //'no-console': 'warn', "no-extra-boolean-cast": "off", - "no-multiple-empty-lines": ["warn", { + "no-multiple-empty-lines": [ "warn", { "max": 1, "maxBOF": 0, }], - "lines-between-class-members": ["warn", "always", { + "lines-between-class-members": [ "warn", "always", { exceptAfterSingleLine: true, }], "no-unneeded-ternary": "error", - "array-bracket-newline": ["error", "consistent"], - "eol-last": ["error", "always"], + "array-bracket-newline": [ "error", "consistent" ], + "eol-last": [ "error", "always" ], //'prefer-template': 'error', - "comma-dangle": ["warn", "only-multiline"], - "no-empty": ["error", { + "comma-dangle": [ "warn", "only-multiline" ], + "no-empty": [ "error", { "allowEmptyCatch": true }], "no-control-regex": "off", - "one-var": ["error", "never"], - "max-statements-per-line": ["error", { "max": 1 }] + "one-var": [ "error", "never" ], + "max-statements-per-line": [ "error", { "max": 1 }] }, "overrides": [ { "files": [ "src/languages/*.js", "src/icon.js" ], "rules": { - "comma-dangle": ["error", "always-multiline"], + "comma-dangle": [ "error", "always-multiline" ], } }, diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3dc7c8b26..fe6a66594 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -20,6 +20,7 @@ Please delete any options that are not relevant. - [ ] I ran ESLint and other linters for modified files - [ ] I have performed a self-review of my own code and tested it - [ ] I have commented my code, particularly in hard-to-understand areas + (including JSDoc for methods) - [ ] My changes generate no new warnings - [ ] My code needed automated testing. I have added them (this is optional task) diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml index e01c02cee..d26b76e68 100644 --- a/.github/workflows/auto-test.yml +++ b/.github/workflows/auto-test.yml @@ -11,25 +11,42 @@ on: jobs: auto-test: + needs: [ check-linters ] runs-on: ${{ matrix.os }} + timeout-minutes: 15 strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] - node-version: [14.x, 16.x, 17.x] + node: [ 14, 16, 17, 18 ] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v2 + - run: git config --global core.autocrlf false # Mainly for Windows + - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + - name: Use Node.js ${{ matrix.node }} + uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ matrix.node }} cache: 'npm' - - run: npm run install-legacy + - run: npm install - run: npm run build - run: npm test env: HEADLESS_TEST: 1 JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }} + check-linters: + runs-on: ubuntu-latest + + steps: + - run: git config --global core.autocrlf false # Mainly for Windows + - uses: actions/checkout@v3 + + - name: Use Node.js 14 + uses: actions/setup-node@v3 + with: + node-version: 14 + cache: 'npm' + - run: npm install + - run: npm run lint diff --git a/.stylelintrc b/.stylelintrc index aad673dbc..52301b542 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,9 +1,13 @@ { "extends": "stylelint-config-standard", + "customSyntax": "postcss-html", "rules": { "indentation": 4, "no-descending-specificity": null, "selector-list-comma-newline-after": null, - "declaration-empty-line-before": null + "declaration-empty-line-before": null, + "alpha-value-notation": "number", + "color-function-notation": "legacy", + "shorthand-property-no-redundant-values": null } } diff --git a/CNAME b/CNAME index a5348b076..442505166 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -git.kuma.pet \ No newline at end of file +git.kuma.pet diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e6f7dfad..940f1c2cb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,24 +27,20 @@ The frontend code build into "dist" directory. The server (express.js) exposes t ## Can I create a pull request for Uptime Kuma? -⚠️ 2022-03-02 Update: - -Since I found that merging pull requests is a pretty heavy task for me, I try to rearrange it. +(Updated 2022-04-24) Since I don't want to waste your time, be sure to create empty draft pull request, so we can discuss first. ✅ Accept: - Bug/Security fix - Translations - Adding notification providers -❌ Avoid: +⚠️ Discuss First - Large pull requests -- New big features - -My long story here: https://www.reddit.com/r/UptimeKuma/comments/t1t6or/comment/hynyijx/ +- New features ### Recommended Pull Request Guideline -Before deep into coding, disscussion first is preferred. Creating an empty pull request for disscussion would be recommended. +Before deep into coding, discussion first is preferred. Creating an empty pull request for discussion would be recommended. 1. Fork the project 1. Clone your fork repo to local @@ -79,6 +75,7 @@ I personally do not like something need to learn so much and need to config so m - 4 spaces indentation - Follow `.editorconfig` - Follow ESLint +- Methods and functions should be documented with JSDoc ## Name convention @@ -89,9 +86,10 @@ I personally do not like something need to learn so much and need to config so m ## Tools - Node.js >= 14 +- NPM >= 8.5 - Git - IDE that supports ESLint and EditorConfig (I am using IntelliJ IDEA) -- A SQLite tool (SQLite Expert Personal is suggested) +- A SQLite GUI tool (SQLite Expert Personal is suggested) ## Install dependencies @@ -99,39 +97,45 @@ I personally do not like something need to learn so much and need to config so m npm ci ``` -## How to start the Backend Dev Server +## Dev Server -(2021-09-23 Update) +(2022-04-26 Update) + +We can start the frontend dev server and the backend dev server in one command. + +Port `3000` and port `3001` will be used. ```bash -npm run start-server-dev +npm run dev ``` +## Backend Server + It binds to `0.0.0.0:3001` by default. -### Backend Details It is mainly a socket.io app + express.js. -express.js is just used for serving the frontend built files (index.html, .js and .css etc.) +express.js is used for: +- entry point such as redirecting to a status page or the dashboard +- serving the frontend built files (index.html, .js and .css etc.) +- serving internal APIs of status page + + +### Structure in /server/ - model/ (Object model, auto mapping to the database table name) - modules/ (Modified 3rd-party modules) - notification-providers/ (individual notification logic) - routers/ (Express Routers) - socket-handler (Socket.io Handlers) -- server.js (Server main logic) +- server.js (Server entry point and main logic) -## How to start the Frontend Dev Server +## Frontend Dev Server -1. Set the env var `NODE_ENV` to "development". -2. Start the frontend dev server by the following command. +It binds to `0.0.0.0:3000` by default. Frontend dev server is used for development only. - ```bash - npm run dev - ``` - - It binds to `0.0.0.0:3000` by default. +For production, it is not used. It will be compiled to `dist` directory instead. You can use Vue.js devtools Chrome extension for debugging. diff --git a/README.md b/README.md index 8bb922dc9..d846f143f 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,15 @@ VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollec * Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server / Docker Containers. * Fancy, Reactive, Fast UI/UX. -* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [70+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications). +* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications). * 20 second intervals. * [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/languages) -* Simple Status Page +* Multiple Status Pages +* Map Status Page to Domain * Ping Chart * Certificate Info +* Proxy Support +* 2FA available ## 🔧 How to Install @@ -154,10 +157,17 @@ https://www.reddit.com/r/UptimeKuma/ ## Contribute -If you want to report a bug or request a new feature. Free feel to open a [new issue](https://github.com/louislam/uptime-kuma/issues). +### Beta Version +Check out the latest beta release here: https://github.com/louislam/uptime-kuma/releases + +### Bug Reports / Feature Requests +If you want to report a bug or request a new feature, feel free to open a [new issue](https://github.com/louislam/uptime-kuma/issues). + +### Translations If you want to translate Uptime Kuma into your language, please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages -If you want to modify Uptime Kuma, this guideline may be useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md +Feel free to correct my grammar in this README, source code, or wiki, as my mother language is not English and my grammar is not that great. -Unfortunately, English proofreading is needed too because my grammar is not that great. Feel free to correct my grammar in this README, source code, or wiki. +### Pull Requests +If you want to modify Uptime Kuma, this guideline may be useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md diff --git a/SECURITY.md b/SECURITY.md index 3a11e8817..d043841a7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,10 +13,7 @@ currently being supported with security updates. ### Uptime Kuma Versions -| Version | Supported | -| ------- | ------------------ | -| 1.9.X | :white_check_mark: | -| <= 1.8.X | ❌ | +You should use or upgrade to the latest version of Uptime Kuma. All `1.X.X` versions are upgradable to the lastest version. ### Upgradable Docker Tags @@ -24,8 +21,8 @@ currently being supported with security updates. | ------- | ------------------ | | 1 | :white_check_mark: | | 1-debian | :white_check_mark: | -| 1-alpine | :white_check_mark: | | latest | :white_check_mark: | | debian | :white_check_mark: | -| alpine | :white_check_mark: | +| 1-alpine | ⚠️ Deprecated | +| alpine | ⚠️ Deprecated | | All other tags | ❌ | diff --git a/babel.config.js b/babel.config.js index d2ad8213a..6bb8a01a5 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,11 +1,11 @@ const config = {}; if (process.env.TEST_FRONTEND) { - config.presets = ["@babel/preset-env"]; + config.presets = [ "@babel/preset-env" ]; } if (process.env.TEST_BACKEND) { - config.plugins = ["babel-plugin-rewire"]; + config.plugins = [ "babel-plugin-rewire" ]; } module.exports = config; diff --git a/config/vite.config.js b/config/vite.config.js index a9701d426..9fdc5fabf 100644 --- a/config/vite.config.js +++ b/config/vite.config.js @@ -10,15 +10,15 @@ export default defineConfig({ plugins: [ vue(), legacy({ - targets: ["ie > 11"], - additionalLegacyPolyfills: ["regenerator-runtime/runtime"] + targets: [ "ie > 11" ], + additionalLegacyPolyfills: [ "regenerator-runtime/runtime" ] }) ], css: { postcss: { "parser": postCssScss, "map": false, - "plugins": [postcssRTLCSS] + "plugins": [ postcssRTLCSS ] } }, }); diff --git a/db/patch-added-mqtt-monitor.sql b/db/patch-added-mqtt-monitor.sql new file mode 100644 index 000000000..02b0b09d9 --- /dev/null +++ b/db/patch-added-mqtt-monitor.sql @@ -0,0 +1,16 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD mqtt_topic TEXT; + +ALTER TABLE monitor + ADD mqtt_success_message VARCHAR(255); + +ALTER TABLE monitor + ADD mqtt_username VARCHAR(255); + +ALTER TABLE monitor + ADD mqtt_password VARCHAR(255); + +COMMIT; diff --git a/db/patch-status-page-footer-css.sql b/db/patch-status-page-footer-css.sql new file mode 100644 index 000000000..413918f11 --- /dev/null +++ b/db/patch-status-page-footer-css.sql @@ -0,0 +1,6 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; +ALTER TABLE status_page ADD footer_text TEXT; +ALTER TABLE status_page ADD custom_css TEXT; +ALTER TABLE status_page ADD show_powered_by BOOLEAN NOT NULL DEFAULT 1; +COMMIT; diff --git a/docker/alpine-base.dockerfile b/docker/alpine-base.dockerfile index a23c81084..1e1643ca3 100644 --- a/docker/alpine-base.dockerfile +++ b/docker/alpine-base.dockerfile @@ -4,5 +4,5 @@ WORKDIR /app # Install apprise, iputils for non-root ping, setpriv RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \ - pip3 --no-cache-dir install apprise==0.9.7 && \ + pip3 --no-cache-dir install apprise==0.9.8.3 && \ rm -rf /root/.cache diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile index 62889dc94..f2016b802 100644 --- a/docker/debian-base.dockerfile +++ b/docker/debian-base.dockerfile @@ -11,7 +11,7 @@ WORKDIR /app RUN apt update && \ apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \ sqlite3 iputils-ping util-linux dumb-init && \ - pip3 --no-cache-dir install apprise==0.9.7 && \ + pip3 --no-cache-dir install apprise==0.9.8.3 && \ rm -rf /var/lib/apt/lists/* # Install cloudflared diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index a6499ef9f..f01f0ea52 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -8,7 +8,7 @@ services: image: louislam/uptime-kuma:1 container_name: uptime-kuma volumes: - - ./uptime-kuma:/app/data + - ./uptime-kuma-data:/app/data ports: - - 3001:3001 + - 3001:3001 # : restart: always diff --git a/ecosystem.config.js b/ecosystem.config.js index 5f4034007..bff3451f7 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -1,6 +1,6 @@ module.exports = { - apps: [{ - name: "uptime-kuma", - script: "./server/server.js", - }] -} + apps: [{ + name: "uptime-kuma", + script: "./server/server.js", + }] +}; diff --git a/extra/beta/update-version.js b/extra/beta/update-version.js index e452f32de..df2cb40a6 100644 --- a/extra/beta/update-version.js +++ b/extra/beta/update-version.js @@ -1,11 +1,10 @@ const pkg = require("../../package.json"); const fs = require("fs"); -const child_process = require("child_process"); +const childProcess = require("child_process"); const util = require("../../src/util"); util.polyfill(); -const oldVersion = pkg.version; const version = process.env.VERSION; console.log("Beta Version: " + version); @@ -21,6 +20,10 @@ if (! exists) { // Process package.json pkg.version = version; fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n"); + + // Also update package-lock.json + childProcess.spawnSync("npm", [ "install" ]); + commit(version); tag(version); @@ -32,7 +35,7 @@ if (! exists) { function commit(version) { let msg = "Update to " + version; - let res = child_process.spawnSync("git", ["commit", "-m", msg, "-a"]); + let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]); let stdout = res.stdout.toString().trim(); console.log(stdout); @@ -40,15 +43,15 @@ function commit(version) { throw new Error("commit error"); } - res = child_process.spawnSync("git", ["push", "origin", "master"]); + res = childProcess.spawnSync("git", [ "push", "origin", "master" ]); console.log(res.stdout.toString().trim()); } function tag(version) { - let res = child_process.spawnSync("git", ["tag", version]); + let res = childProcess.spawnSync("git", [ "tag", version ]); console.log(res.stdout.toString().trim()); - res = child_process.spawnSync("git", ["push", "origin", version]); + res = childProcess.spawnSync("git", [ "push", "origin", version ]); console.log(res.stdout.toString().trim()); } @@ -57,15 +60,7 @@ function tagExists(version) { throw new Error("invalid version"); } - let res = child_process.spawnSync("git", ["tag", "-l", version]); + let res = childProcess.spawnSync("git", [ "tag", "-l", version ]); return res.stdout.toString().trim() === version; } - -function safeDelete(dir) { - if (fs.existsSync(dir)) { - fs.rmdirSync(dir, { - recursive: true, - }); - } -} diff --git a/extra/close-incorrect-issue.js b/extra/close-incorrect-issue.js index a15a5da37..ae38bccc2 100644 --- a/extra/close-incorrect-issue.js +++ b/extra/close-incorrect-issue.js @@ -29,7 +29,7 @@ const github = require("@actions/github"); owner: issue.owner, repo: issue.repo, issue_number: issue.number, - labels: ["invalid-format"] + labels: [ "invalid-format" ] }); // Add the issue closing comment diff --git a/extra/mark-as-nightly.js b/extra/mark-as-nightly.js index 0316596bf..a55fd98f7 100644 --- a/extra/mark-as-nightly.js +++ b/extra/mark-as-nightly.js @@ -4,21 +4,21 @@ const util = require("../src/util"); util.polyfill(); -const oldVersion = pkg.version -const newVersion = oldVersion + "-nightly" +const oldVersion = pkg.version; +const newVersion = oldVersion + "-nightly"; -console.log("Old Version: " + oldVersion) -console.log("New Version: " + newVersion) +console.log("Old Version: " + oldVersion); +console.log("New Version: " + newVersion); if (newVersion) { // Process package.json - pkg.version = newVersion - pkg.scripts.setup = pkg.scripts.setup.replaceAll(oldVersion, newVersion) - pkg.scripts["build-docker"] = pkg.scripts["build-docker"].replaceAll(oldVersion, newVersion) - fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n") + pkg.version = newVersion; + pkg.scripts.setup = pkg.scripts.setup.replaceAll(oldVersion, newVersion); + pkg.scripts["build-docker"] = pkg.scripts["build-docker"].replaceAll(oldVersion, newVersion); + fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n"); // Process README.md if (fs.existsSync("README.md")) { - fs.writeFileSync("README.md", fs.readFileSync("README.md", "utf8").replaceAll(oldVersion, newVersion)) + fs.writeFileSync("README.md", fs.readFileSync("README.md", "utf8").replaceAll(oldVersion, newVersion)); } } diff --git a/extra/reset-password.js b/extra/reset-password.js index 160ef0a3e..8036a4566 100644 --- a/extra/reset-password.js +++ b/extra/reset-password.js @@ -4,6 +4,7 @@ const Database = require("../server/database"); const { R } = require("redbean-node"); const readline = require("readline"); const { initJWTSecret } = require("../server/util-server"); +const User = require("../server/model/user"); const args = require("args-parser")(process.argv); const rl = readline.createInterface({ input: process.stdin, @@ -30,7 +31,7 @@ const main = async () => { let confirmPassword = await question("Confirm New Password: "); if (password === confirmPassword) { - await user.resetPassword(password); + await User.resetPassword(user.id, password); // Reset all sessions by reset jwt secret await initJWTSecret(); diff --git a/extra/simple-dns-server.js b/extra/simple-dns-server.js index 5e5745f04..376dbdd04 100644 --- a/extra/simple-dns-server.js +++ b/extra/simple-dns-server.js @@ -26,7 +26,7 @@ server.on("request", (request, send, rinfo) => { ttl: 300, address: "1.2.3.4" }); - } if (question.type === Packet.TYPE.AAAA) { + } else if (question.type === Packet.TYPE.AAAA) { response.answers.push({ name: question.name, type: question.type, diff --git a/extra/simple-mqtt-server.js b/extra/simple-mqtt-server.js new file mode 100644 index 000000000..238d27726 --- /dev/null +++ b/extra/simple-mqtt-server.js @@ -0,0 +1,50 @@ +const { log } = require("../src/util"); + +const mqttUsername = "louis1"; +const mqttPassword = "!@#$LLam"; + +class SimpleMqttServer { + aedes = require("aedes")(); + server = require("net").createServer(this.aedes.handle); + + constructor(port) { + this.port = port; + } + + start() { + this.server.listen(this.port, () => { + console.log("server started and listening on port ", this.port); + }); + } +} + +let server1 = new SimpleMqttServer(10000); + +server1.aedes.authenticate = function (client, username, password, callback) { + if (username && password) { + console.log(password.toString("utf-8")); + callback(null, username === mqttUsername && password.toString("utf-8") === mqttPassword); + } else { + callback(null, false); + } +}; + +server1.aedes.on("subscribe", (subscriptions, client) => { + console.log(subscriptions); + + for (let s of subscriptions) { + if (s.topic === "test") { + server1.aedes.publish({ + topic: "test", + payload: Buffer.from("ok"), + }, (error) => { + if (error) { + log.error("mqtt_server", error); + } + }); + } + } + +}); + +server1.start(); diff --git a/extra/update-version.js b/extra/update-version.js index d72fee68f..d5c2ee5ca 100644 --- a/extra/update-version.js +++ b/extra/update-version.js @@ -1,7 +1,6 @@ const pkg = require("../package.json"); const fs = require("fs"); -const rmSync = require("./fs-rmSync.js"); -const child_process = require("child_process"); +const childProcess = require("child_process"); const util = require("../src/util"); util.polyfill(); @@ -26,6 +25,9 @@ if (! exists) { pkg.scripts.setup = pkg.scripts.setup.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`); fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n"); + // Also update package-lock.json + childProcess.spawnSync("npm", [ "install" ]); + commit(newVersion); tag(newVersion); @@ -42,7 +44,7 @@ if (! exists) { function commit(version) { let msg = "Update to " + version; - let res = child_process.spawnSync("git", ["commit", "-m", msg, "-a"]); + let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]); let stdout = res.stdout.toString().trim(); console.log(stdout); @@ -52,7 +54,7 @@ function commit(version) { } function tag(version) { - let res = child_process.spawnSync("git", ["tag", version]); + let res = childProcess.spawnSync("git", [ "tag", version ]); console.log(res.stdout.toString().trim()); } @@ -67,7 +69,7 @@ function tagExists(version) { throw new Error("invalid version"); } - let res = child_process.spawnSync("git", ["tag", "-l", version]); + let res = childProcess.spawnSync("git", [ "tag", "-l", version ]); return res.stdout.toString().trim() === version; } diff --git a/extra/update-wiki-version.js b/extra/update-wiki-version.js index 10631c332..d0f10561f 100644 --- a/extra/update-wiki-version.js +++ b/extra/update-wiki-version.js @@ -1,4 +1,4 @@ -const child_process = require("child_process"); +const childProcess = require("child_process"); const fs = require("fs"); const newVersion = process.env.VERSION; @@ -16,23 +16,23 @@ function updateWiki(newVersion) { safeDelete(wikiDir); - child_process.spawnSync("git", ["clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir]); + childProcess.spawnSync("git", [ "clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir ]); let content = fs.readFileSync(howToUpdateFilename).toString(); // Replace the version: https://regex101.com/r/hmj2Bc/1 content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`); fs.writeFileSync(howToUpdateFilename, content); - child_process.spawnSync("git", ["add", "-A"], { + childProcess.spawnSync("git", [ "add", "-A" ], { cwd: wikiDir, }); - child_process.spawnSync("git", ["commit", "-m", `Update to ${newVersion}`], { + childProcess.spawnSync("git", [ "commit", "-m", `Update to ${newVersion}` ], { cwd: wikiDir, }); console.log("Pushing to Github"); - child_process.spawnSync("git", ["push"], { + childProcess.spawnSync("git", [ "push" ], { cwd: wikiDir, }); diff --git a/package-lock.json b/package-lock.json index 91ca4e527..561bdf31c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,23 @@ { "name": "uptime-kuma", - "version": "1.14.0-beta.0", + "version": "1.15.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.14.0-beta.0", + "version": "1.15.1", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-svg-core": "~1.2.36", "@fortawesome/free-regular-svg-icons": "~5.15.4", "@fortawesome/free-solid-svg-icons": "~5.15.4", "@fortawesome/vue-fontawesome": "~3.0.0-5", - "@louislam/sqlite3": "~6.0.1", + "@louislam/sqlite3": "~15.0.6", "@popperjs/core": "~2.10.2", "args-parser": "~1.3.0", "axios": "~0.26.1", + "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", "bree": "~7.1.5", @@ -24,6 +25,7 @@ "chart.js": "~3.6.2", "chartjs-adapter-dayjs": "~1.0.0", "check-password-strength": "^2.0.5", + "chroma-js": "^2.1.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "dayjs": "~1.10.8", @@ -38,12 +40,14 @@ "jsonwebtoken": "~8.5.1", "jwt-decode": "^3.1.2", "limiter": "^2.1.0", + "mqtt": "^4.2.8", "node-cloudflared-tunnel": "~1.0.9", "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", "postcss-rtlcss": "~3.4.1", "postcss-scss": "~4.0.3", + "prismjs": "^1.27.0", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", "qrcode": "~1.5.0", @@ -63,6 +67,7 @@ "vue-i18n": "~9.1.9", "vue-image-crop-upload": "~3.0.3", "vue-multiselect": "~3.0.0-alpha.2", + "vue-prism-editor": "^2.0.0-alpha.2", "vue-qrcode": "~1.0.0", "vue-router": "~4.0.14", "vue-toastification": "~2.0.0-rc.5", @@ -70,27 +75,31 @@ }, "devDependencies": { "@actions/github": "~5.0.1", - "@babel/eslint-parser": "~7.15.8", + "@babel/eslint-parser": "~7.17.0", "@babel/preset-env": "^7.15.8", "@types/bootstrap": "~5.1.9", "@vitejs/plugin-legacy": "~1.6.4", "@vitejs/plugin-vue": "~1.9.4", "@vue/compiler-sfc": "~3.2.31", + "aedes": "^0.46.3", "babel-plugin-rewire": "~1.2.0", + "concurrently": "^7.1.0", "core-js": "~3.18.3", "cross-env": "~7.0.3", "dns2": "~2.0.1", - "eslint": "~7.32.0", - "eslint-plugin-vue": "~7.18.0", + "eslint": "~8.14.0", + "eslint-plugin-vue": "~8.7.1", "jest": "~27.2.5", "jest-puppeteer": "~6.0.3", - "npm-check-updates": "^12.5.5", + "npm-check-updates": "^12.5.9", + "postcss-html": "^1.3.1", "puppeteer": "~13.1.3", "sass": "~1.42.1", - "stylelint": "~14.2.0", - "stylelint-config-standard": "~24.0.0", + "stylelint": "~14.7.1", + "stylelint-config-standard": "~25.0.0", "typescript": "~4.4.4", - "vite": "~2.6.14" + "vite": "~2.6.14", + "wait-on": "^6.0.1" }, "engines": { "node": "14.* || >=16.*" @@ -181,9 +190,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.15.8.tgz", - "integrity": "sha512-fYP7QFngCvgxjUuw8O057SVH5jCXsbFFOoE77CFDcvzwBVgTOkMD/L4mIC5Ud1xf8chK/no2fRbSSn1wvNmKuQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", + "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "dev": true, "dependencies": { "eslint-scope": "^5.1.1", @@ -195,7 +204,7 @@ }, "peerDependencies": { "@babel/core": ">=7.11.0", - "eslint": ">=7.5.0" + "eslint": "^7.5.0 || ^8.0.0" } }, "node_modules/@babel/generator": { @@ -1764,25 +1773,31 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", + "debug": "^4.3.2", + "espree": "^9.3.1", "globals": "^13.9.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.13.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", @@ -1798,6 +1813,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -1868,7 +1895,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "devOptional": true + "dev": true }, "node_modules/@hapi/hoek": { "version": "9.2.1", @@ -1886,12 +1913,12 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" }, @@ -2672,19 +2699,20 @@ } }, "node_modules/@louislam/sqlite3": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-6.0.1.tgz", - "integrity": "sha512-QGLj5bjQ+O4YSPj/qxtEAArbIqW9wNzBUamlIcRbvFjFiNokItwdubqL2Gl5iX0q1mUn3Z6NoFO1rrAZ/qqlsA==", + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.0.6.tgz", + "integrity": "sha512-+HF/4OEy+yakYzJlSPJbLDtf499t0s0eaglXC9y3Oa9OBZ+dKAaTW5+Ft1RCvfUJLFw/oyYjHtMsg9V+7NT05g==", "hasInstallScript": true, "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.7", - "node-addon-api": "^3.0.0" + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" }, "optionalDependencies": { - "node-gyp": "^8.4.1" + "node-gyp": "^7.1.2" }, "peerDependencies": { - "node-gyp": "8.x" + "node-gyp": "7.x" }, "peerDependenciesMeta": { "node-gyp": { @@ -2760,31 +2788,6 @@ "node": ">= 8" } }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@npmcli/git": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.0.tgz", @@ -2861,7 +2864,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "devOptional": true, + "dev": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -3822,6 +3825,68 @@ "node": ">=0.4.0" } }, + "node_modules/aedes": { + "version": "0.46.3", + "resolved": "https://registry.npmjs.org/aedes/-/aedes-0.46.3.tgz", + "integrity": "sha512-i3B+H74uNRhlqcs/JdrMp7e3daz4Cwls0x4yLcfjGXz2tIwnxhF6od4m86O6yyNdz/Gg3jfY3q0sc/Cz8qzg6g==", + "dev": true, + "dependencies": { + "aedes-packet": "^2.3.1", + "aedes-persistence": "^8.1.3", + "bulk-write-stream": "^2.0.1", + "end-of-stream": "^1.4.4", + "fastfall": "^1.5.1", + "fastparallel": "^2.4.1", + "fastseries": "^2.0.0", + "hyperid": "^3.0.0", + "mqemitter": "^4.5.0", + "mqtt-packet": "^7.1.2", + "readable-stream": "^3.6.0", + "retimer": "^3.0.0", + "reusify": "^1.0.4", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/aedes-packet": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/aedes-packet/-/aedes-packet-2.3.1.tgz", + "integrity": "sha512-LqBd57uc2rui2RbjycW17dylglejG26mM4ewVXGNDnVp/SUHFVEgm7d1HTmYrnSkSCNoHti042qgcTwv/F+BtQ==", + "dev": true, + "dependencies": { + "mqtt-packet": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aedes-persistence": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/aedes-persistence/-/aedes-persistence-8.1.3.tgz", + "integrity": "sha512-VMCjEV+2g1TNJb/IlDEUy6SP9crT+QUhe2xc6UjyqrFNBNgTvHmOefXY7FxWrwmR2QA02vwg3+5p/JXkyg/Dkw==", + "dev": true, + "dependencies": { + "aedes-packet": "^2.3.1", + "from2": "^2.3.0", + "qlobber": "^5.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aedes/node_modules/mqtt-packet": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-7.1.2.tgz", + "integrity": "sha512-FFZbcZ2omsf4c5TxEQfcX9hI+JzDpDKPT46OmeIBpVA7+t32ey25UNqlqNXTmeZOr5BLsSIERpQQLsFWJS94SQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.2", + "debug": "^4.1.1", + "process-nextick-args": "^2.0.1" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -3837,7 +3902,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "devOptional": true, + "dev": true, "dependencies": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -3851,7 +3916,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "devOptional": true, + "dev": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -3864,7 +3929,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "devOptional": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3876,6 +3941,14 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/anafanafo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz", + "integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==", + "dependencies": { + "char-width-table-consumer": "^1.0.0" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -3885,15 +3958,6 @@ "string-width": "^4.1.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -4005,6 +4069,24 @@ "node": ">=0.10.0" } }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -4024,6 +4106,21 @@ "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.1.0.tgz", "integrity": "sha512-t7Zm5YGgEEc/3eYAicF32m/TNvL+XOeYZy9CvBUeJY/szM7frLolFylhrlZNWV/ohWhcUXygrBGjYmoQdxF4CQ==" }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "optional": true + }, "node_modules/axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -4279,6 +4376,22 @@ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, + "node_modules/badge-maker": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz", + "integrity": "sha512-OO/PS7Zg2E6qaUWzHEHt21Q5VjcFBAJVA8ztgT/fIdSZFBUwoyeo0ZhA6V5tUM8Vcjq8DJl6jfGhpjESssyqMQ==", + "dependencies": { + "anafanafo": "2.0.0", + "css-color-converter": "^2.0.0" + }, + "bin": { + "badge": "lib/badge-cli.js" + }, + "engines": { + "node": ">= 10", + "npm": ">= 5" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4288,7 +4401,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -4328,6 +4440,15 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, "node_modules/bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", @@ -4348,6 +4469,11 @@ "node": ">=8" } }, + "node_modules/binary-search": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" + }, "node_modules/bintrees": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", @@ -4357,7 +4483,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -4408,6 +4533,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", @@ -4631,7 +4762,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -4668,8 +4798,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/builtins": { "version": "5.0.0", @@ -4695,6 +4824,16 @@ "node": ">=10" } }, + "node_modules/bulk-write-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-2.0.1.tgz", + "integrity": "sha512-XWOLjgHtpDasHfwM8oO4df1JoZwa7/OwTsXDzh4rUTo+9CowzeOFBZz43w+H14h1fyq+xl28tVIBrdjcjj4Gug==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4703,35 +4842,6 @@ "node": ">= 0.8" } }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/cacheable-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", @@ -4837,6 +4947,12 @@ } ] }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "optional": true + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -4860,6 +4976,14 @@ "node": ">=10" } }, + "node_modules/char-width-table-consumer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz", + "integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==", + "dependencies": { + "binary-search": "^1.3.5" + } + }, "node_modules/chardet": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz", @@ -4919,6 +5043,29 @@ "node": ">=10" } }, + "node_modules/chroma-js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz", + "integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==", + "dependencies": { + "cross-env": "^6.0.3" + } + }, + "node_modules/chroma-js/node_modules/cross-env": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", + "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", + "dependencies": { + "cross-spawn": "^7.0.0" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/ci-info": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", @@ -4941,7 +5088,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } @@ -5040,6 +5187,15 @@ "node": ">= 0.12.0" } }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -5123,6 +5279,23 @@ "node": ">= 6" } }, + "node_modules/commist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "dependencies": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + } + }, + "node_modules/commist/node_modules/leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/compare-versions": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", @@ -5138,6 +5311,145 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concurrently": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.1.0.tgz", + "integrity": "sha512-Bz0tMlYKZRUDqJlNiF/OImojMB9ruKUz6GCfmhFnSapXgPe+3xzY4byqoKG9tUZ7L2PGEUjfLPOLfIX3labnmw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "bin": { + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.0 || >=16.0.0" + } + }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/concurrently/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -5241,6 +5553,12 @@ "semver": "bin/semver.js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "devOptional": true + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -5299,7 +5617,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -5318,6 +5635,40 @@ "node": ">=8" } }, + "node_modules/css-color-converter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz", + "integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==", + "dependencies": { + "color-convert": "^0.5.2", + "color-name": "^1.1.4", + "css-unit-converter": "^1.1.2" + } + }, + "node_modules/css-color-converter/node_modules/color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + }, + "node_modules/css-color-converter/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/css-functions-list": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz", + "integrity": "sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw==", + "dev": true, + "engines": { + "node": ">=12.22" + } + }, + "node_modules/css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -5377,6 +5728,18 @@ "node": ">=0.8" } }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -5391,6 +5754,19 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "dev": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.10.8", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", @@ -5612,6 +5988,41 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, "node_modules/domexception": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", @@ -5633,6 +6044,35 @@ "node": ">=8" } }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -5651,6 +6091,27 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -5704,6 +6165,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -5713,7 +6175,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "dependencies": { "once": "^1.4.0" } @@ -5805,16 +6266,16 @@ } } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, "engines": { - "node": ">=8.6" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/env-paths": { @@ -5830,7 +6291,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "devOptional": true + "dev": true }, "node_modules/error-ex": { "version": "1.3.2", @@ -6215,49 +6676,44 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", + "glob-parent": "^6.0.1", "globals": "^13.6.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -6265,28 +6721,45 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-plugin-vue": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.18.0.tgz", - "integrity": "sha512-ceDXlXYMMPMSXw7tdKUR42w9jlzthJGJ3Kvm3YrZ0zuQfvAySNxe8sm6VHuksBW0+060GzYXhHJG6IHVOfF83Q==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", "dev": true, "dependencies": { - "eslint-utils": "^2.1.0", + "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", - "semver": "^6.3.0", - "vue-eslint-parser": "^7.10.0" + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" }, "engines": { - "node": ">=8.10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/eslint-scope": { @@ -6303,27 +6776,21 @@ } }, "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">=6" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=5" } }, "node_modules/eslint-visitor-keys": { @@ -6335,15 +6802,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6359,6 +6817,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6405,6 +6869,49 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/eslint/node_modules/globals": { "version": "13.13.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", @@ -6429,19 +6936,16 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "argparse": "^2.0.1" }, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "js-yaml": "bin/js-yaml.js" } }, "node_modules/eslint/node_modules/supports-color": { @@ -6477,26 +6981,38 @@ } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "dependencies": { - "acorn": "^7.4.0", + "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/esprima": { @@ -6723,6 +7239,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -6758,11 +7280,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ], + "optional": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "devOptional": true }, "node_modules/fast-glob": { "version": "3.2.11", @@ -6784,7 +7315,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "devOptional": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -6804,6 +7335,28 @@ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, + "node_modules/fastfall": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz", + "integrity": "sha1-P+4DMxpJ0dObPN96XpzWb0dee5Q=", + "dev": true, + "dependencies": { + "reusify": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fastparallel": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.4.1.tgz", + "integrity": "sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4", + "xtend": "^4.0.2" + } + }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -6813,6 +7366,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fastseries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-2.0.0.tgz", + "integrity": "sha512-XBU9RXeoYc2/VnvMhplAxEmZLfIk7cvTBu+xwoBuTI8pL19E03cmca17QQycKIdxgwCeFA/a4u27gv1h3ya5LQ==", + "dev": true + }, "node_modules/favico.js": { "version": "0.3.10", "resolved": "https://registry.npmjs.org/favico.js/-/favico.js-0.3.10.tgz", @@ -7076,6 +7635,15 @@ "node": ">=0.10.0" } }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -7114,6 +7682,46 @@ "node": ">= 0.6" } }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -7258,6 +7866,15 @@ "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -7382,15 +7999,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/globjoin": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", @@ -7437,6 +8045,29 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "devOptional": true }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "optional": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -7497,6 +8128,15 @@ "node": ">=8" } }, + "node_modules/help-me": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", + "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", + "dependencies": { + "glob": "^7.1.6", + "readable-stream": "^3.6.0" + } + }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -7549,19 +8189,41 @@ "dev": true }, "node_modules/html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" } }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "devOptional": true + "dev": true }, "node_modules/http-errors": { "version": "1.8.1", @@ -7602,6 +8264,21 @@ "node": ">= 6" } }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -7635,11 +8312,21 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "devOptional": true, + "dev": true, "dependencies": { "ms": "^2.0.0" } }, + "node_modules/hyperid": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-3.0.1.tgz", + "integrity": "sha512-I+tl7TS5nsoVhkxqX1rS3Qmqlq44eoPUcgPthW8v3IW8CvWL7lwtd6HQbkDUMrBKJTG0vgEaRsjT35imW/D+9Q==", + "dev": true, + "dependencies": { + "uuid": "^8.3.2", + "uuid-parse": "^1.1.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -7655,7 +8342,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -7672,9 +8358,9 @@ ] }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { "node": ">= 4" @@ -7740,7 +8426,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.8.19" } @@ -7749,7 +8435,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" } @@ -7758,7 +8444,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "devOptional": true + "dev": true }, "node_modules/inflight": { "version": "1.0.6", @@ -7951,7 +8637,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", - "devOptional": true + "dev": true }, "node_modules/is-npm": { "version": "5.0.0", @@ -8057,7 +8743,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "devOptional": true }, "node_modules/is-valid-path": { "version": "0.1.1", @@ -8085,11 +8771,16 @@ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "devOptional": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "devOptional": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "node_modules/isobject": { "version": "3.0.1", @@ -8100,6 +8791,12 @@ "node": ">=0.10.0" } }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "optional": true + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -10083,6 +10780,11 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/js-sdsl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz", + "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10102,6 +10804,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -10230,11 +10938,17 @@ "jju": "^1.1.0" } }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "optional": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "devOptional": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -10242,6 +10956,12 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "optional": true + }, "node_modules/json5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", @@ -10298,6 +11018,21 @@ "semver": "bin/semver" } }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "optional": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/just-performance": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/just-performance/-/just-performance-4.3.0.tgz", @@ -10730,56 +11465,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "optional": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -11030,8 +11715,7 @@ "node_modules/minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minimist-options": { "version": "4.1.0", @@ -11071,7 +11755,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "devOptional": true, + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -11079,28 +11763,11 @@ "node": ">= 8" } }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "devOptional": true, + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -11122,7 +11789,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "devOptional": true, + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -11134,7 +11801,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "devOptional": true, + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -11193,6 +11860,61 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, + "node_modules/mqemitter": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/mqemitter/-/mqemitter-4.5.0.tgz", + "integrity": "sha512-Mp/zytFeIv6piJQkEKnncHcP4R/ErJc5C7dfonkhkNUT2LA/nTayrfNxbipp3M5iCJUTQSUtzfQAQA3XVcKz6w==", + "dev": true, + "dependencies": { + "fastparallel": "^2.3.0", + "qlobber": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mqtt": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", + "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", + "dependencies": { + "commist": "^1.0.0", + "concat-stream": "^2.0.0", + "debug": "^4.1.1", + "duplexify": "^4.1.1", + "help-me": "^3.0.0", + "inherits": "^2.0.3", + "lru-cache": "^6.0.0", + "minimist": "^1.2.5", + "mqtt-packet": "^6.8.0", + "number-allocator": "^1.0.9", + "pump": "^3.0.0", + "readable-stream": "^3.6.0", + "reinterval": "^1.1.0", + "rfdc": "^1.3.0", + "split2": "^3.1.0", + "ws": "^7.5.5", + "xtend": "^4.0.2" + }, + "bin": { + "mqtt": "bin/mqtt.js", + "mqtt_pub": "bin/pub.js", + "mqtt_sub": "bin/sub.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mqtt-packet": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", + "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", + "dependencies": { + "bl": "^4.0.2", + "debug": "^4.1.1", + "process-nextick-args": "^2.0.1" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -11229,9 +11951,9 @@ } }, "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" }, "node_modules/node-cloudflared-tunnel": { "version": "1.0.9", @@ -11280,20 +12002,20 @@ } }, "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", "optional": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", + "graceful-fs": "^4.2.3", "nopt": "^5.0.0", - "npmlog": "^6.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", + "semver": "^7.3.2", + "tar": "^6.0.2", "which": "^2.0.2" }, "bin": { @@ -11303,57 +12025,96 @@ "node": ">= 10.12.0" } }, + "node_modules/node-gyp/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-gyp/node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "optional": true + }, "node_modules/node-gyp/node_modules/are-we-there-yet": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", - "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "optional": true, "dependencies": { "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "readable-stream": "^2.0.6" } }, "node_modules/node-gyp/node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/node-gyp/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.10.0" } }, "node_modules/node-gyp/node_modules/npmlog": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz", - "integrity": "sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.0", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, + "node_modules/node-gyp/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/node-gyp/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, "node_modules/node-gyp/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "optional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -11365,6 +12126,41 @@ "node": ">=10" } }, + "node_modules/node-gyp/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/node-gyp/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-gyp/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -11471,15 +12267,15 @@ } }, "node_modules/npm-check-updates": { - "version": "12.5.5", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.5.tgz", - "integrity": "sha512-7LH6KN6F1fZMtY4zNYAQPpJU1ToxZ6sSCxk948vrLIz97aNqmPLSX72MrmbOWwpyBgLCPbFJWY/k3zE18pmxfw==", + "version": "12.5.9", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.9.tgz", + "integrity": "sha512-l9iOvD7EsQb96gFJL45V01YG6bP8+dmobYnSguvehPuNwgdWNMrE8RC8bSfURX5iUmX4bkobN4T8XMHXN9GMHA==", "dev": true, "dependencies": { "chalk": "^4.1.2", "cint": "^8.2.1", "cli-table": "^0.3.11", - "commander": "^9.0.0", + "commander": "^9.1.0", "fast-memoize": "^2.5.2", "find-up": "5.0.0", "fp-and-or": "^0.1.3", @@ -11492,11 +12288,11 @@ "lodash": "^4.17.21", "minimatch": "^5.0.1", "p-map": "^4.0.0", - "pacote": "^13.0.3", + "pacote": "^13.0.5", "parse-github-url": "^1.0.2", "progress": "^2.0.3", "prompts": "^2.4.2", - "rc-config-loader": "^4.0.0", + "rc-config-loader": "^4.1.0", "remote-git-tags": "^3.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", @@ -11963,6 +12759,36 @@ "set-blocking": "^2.0.0" } }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-allocator": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.10.tgz", + "integrity": "sha512-K4AvNGKo9lP6HqsZyfSr9KDaqnwFzW203inhQEOwFrmFaYevpdX4VNwdOLk197aHujzbT//z6pCBrCOUYSM5iw==", + "dependencies": { + "debug": "^4.3.1", + "js-sdsl": "^2.1.2" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/numbered": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", @@ -11974,6 +12800,15 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -12115,7 +12950,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "devOptional": true, + "dev": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -12393,7 +13228,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -12423,6 +13257,12 @@ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "optional": true + }, "node_modules/pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", @@ -12505,6 +13345,20 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-html": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.3.1.tgz", + "integrity": "sha512-SJ7iRw+IngyZv3Z9lChlZU30a9y9MZjZZcoUJmx0T/nKE9S+hetJ8fAv/MRu4bPnGDsXhVlaFs5+umpK3yaaQQ==", + "dev": true, + "dependencies": { + "htmlparser2": "^7.1.2", + "postcss": "^8.4.0", + "postcss-safe-parser": "^6.0.0" + }, + "engines": { + "node": "^12 || >=14" + } + }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -12625,6 +13479,14 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "engines": { + "node": ">=6" + } + }, "node_modules/proc-log": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", @@ -12634,6 +13496,11 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -12682,13 +13549,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "devOptional": true + "dev": true }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "devOptional": true, + "dev": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -12737,13 +13604,12 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "devOptional": true }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -12753,7 +13619,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -12838,6 +13704,15 @@ } } }, + "node_modules/qlobber": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/qlobber/-/qlobber-5.0.3.tgz", + "integrity": "sha512-wW4GTZPePyh0RgOsM18oDyOUlXfurVRgoNyJfS+y7VWPyd0GYhQp5T2tycZFZjonH+hngxIfklGJhTP/ghidgQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/qrcode": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz", @@ -13035,9 +13910,9 @@ } }, "node_modules/rc-config-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.0.0.tgz", - "integrity": "sha512-//LRTblJEcqbmmro1GCmZ39qZXD+JqzuD8Y5/IZU3Dhp3A1Yr0Xn68ks8MQ6qKfKvYCWDveUmRDKDA40c+sCXw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.0.tgz", + "integrity": "sha512-aW+kX4qy0CiM9L4fG4Us3oEOpIrOrXzWykAn+xldD07Y9PXWjTH744oHbv0Kc9ZwWaylw3jMjxaf14RgStrNrA==", "dev": true, "dependencies": { "debug": "^4.1.1", @@ -13363,6 +14238,11 @@ "jsesc": "bin/jsesc" } }, + "node_modules/reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + }, "node_modules/remote-git-tags": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", @@ -13372,6 +14252,84 @@ "node": ">=8" } }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "optional": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "optional": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "optional": true, + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -13471,11 +14429,17 @@ "lowercase-keys": "^1.0.0" } }, + "node_modules/retimer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz", + "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==", + "dev": true + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "devOptional": true, + "dev": true, "engines": { "node": ">= 4" } @@ -13490,6 +14454,11 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -13804,7 +14773,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -13816,7 +14784,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -14034,6 +15001,12 @@ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, "node_modules/spawn-please": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-1.0.0.tgz", @@ -14095,17 +15068,50 @@ "specificity": "bin/specificity" } }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "optional": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "devOptional": true, + "dev": true, "dependencies": { "minipass": "^3.1.1" }, @@ -14142,6 +15148,11 @@ "node": ">= 0.6" } }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -14235,24 +15246,25 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.2.0.tgz", - "integrity": "sha512-i0DrmDXFNpDsWiwx6SPRs4/pyw4kvZgqpDGvsTslQMY7hpUl6r33aQvNSn6cnTg2wtZ9rreFElI7XAKpOWi1vQ==", + "version": "14.7.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.7.1.tgz", + "integrity": "sha512-rUOWm67hrzGXXyO/cInENEejF4urh1dLgOb9cr/3XLDb/t/A+rXQp3p6+no8o8QCKTgBUdhVUq/bXMgE988PJw==", "dev": true, "dependencies": { "balanced-match": "^2.0.0", "colord": "^2.9.2", "cosmiconfig": "^7.0.1", - "debug": "^4.3.3", + "css-functions-list": "^3.0.1", + "debug": "^4.3.4", "execall": "^2.0.0", - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "fastest-levenshtein": "^1.0.12", "file-entry-cache": "^6.0.1", "get-stdin": "^8.0.0", "global-modules": "^2.0.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "globjoin": "^0.1.4", - "html-tags": "^3.1.0", + "html-tags": "^3.2.0", "ignore": "^5.2.0", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", @@ -14260,25 +15272,26 @@ "known-css-properties": "^0.24.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", - "micromatch": "^4.0.4", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.12", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.7", - "postcss-value-parser": "^4.1.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "specificity": "^0.4.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", + "supports-hyperlinks": "^2.2.0", "svg-tags": "^1.0.0", - "table": "^6.7.5", + "table": "^6.8.0", "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.1" }, "bin": { "stylelint": "bin/stylelint.js" @@ -14292,24 +15305,24 @@ } }, "node_modules/stylelint-config-recommended": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-6.0.0.tgz", - "integrity": "sha512-ZorSSdyMcxWpROYUvLEMm0vSZud2uB7tX1hzBZwvVY9SV/uly4AvvJPPhCcymZL3fcQhEQG5AELmrxWqtmzacw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", + "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", "dev": true, "peerDependencies": { - "stylelint": "^14.0.0" + "stylelint": "^14.4.0" } }, "node_modules/stylelint-config-standard": { - "version": "24.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-24.0.0.tgz", - "integrity": "sha512-+RtU7fbNT+VlNbdXJvnjc3USNPZRiRVp/d2DxOF/vBDDTi0kH5RX2Ny6errdtZJH3boO+bmqIYEllEmok4jiuw==", + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-25.0.0.tgz", + "integrity": "sha512-21HnP3VSpaT1wFjFvv9VjvOGDtAviv47uTp3uFmzcN+3Lt+RYRv6oAplLaV51Kf792JSxJ6svCJh/G18E9VnCA==", "dev": true, "dependencies": { - "stylelint-config-recommended": "^6.0.0" + "stylelint-config-recommended": "^7.0.0" }, "peerDependencies": { - "stylelint": "^14.0.0" + "stylelint": "^14.4.0" } }, "node_modules/stylelint/node_modules/balanced-match": { @@ -14344,15 +15357,6 @@ "node": ">=6" } }, - "node_modules/stylelint/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/stylelint/node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -14383,6 +15387,19 @@ "which": "bin/which" } }, + "node_modules/stylelint/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -14743,6 +15760,24 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -14788,6 +15823,11 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -14864,7 +15904,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "devOptional": true, + "dev": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -14873,7 +15913,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "devOptional": true, + "dev": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -15039,7 +16079,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "devOptional": true, "dependencies": { "punycode": "^2.1.0" } @@ -15069,6 +16109,21 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uuid-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/uuid-parse/-/uuid-parse-1.1.0.tgz", + "integrity": "sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==", + "dev": true + }, "node_modules/v-pagination-3": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/v-pagination-3/-/v-pagination-3-0.1.7.tgz", @@ -15138,6 +16193,26 @@ "node": ">= 0.8" } }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "optional": true + }, "node_modules/vite": { "version": "2.6.14", "resolved": "https://registry.npmjs.org/vite/-/vite-2.6.14.tgz", @@ -15261,50 +16336,73 @@ } }, "node_modules/vue-eslint-parser": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz", - "integrity": "sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", "dev": true, "dependencies": { - "debug": "^4.1.1", - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.2.1", + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", "esquery": "^1.4.0", "lodash": "^4.17.21", - "semver": "^6.3.0" + "semver": "^7.3.5" }, "engines": { - "node": ">=8.10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "eslint": ">=5.0.0" + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/vue-eslint-parser/node_modules/espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" } }, "node_modules/vue-i18n": { @@ -15341,6 +16439,17 @@ "npm": ">= 3.0.0" } }, + "node_modules/vue-prism-editor": { + "version": "2.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz", + "integrity": "sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/vue-qrcode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/vue-qrcode/-/vue-qrcode-1.0.0.tgz", @@ -15505,7 +16614,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, "dependencies": { "isexe": "^2.0.0" }, @@ -15621,7 +16729,6 @@ "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, "engines": { "node": ">=8.3.0" }, @@ -15667,6 +16774,14 @@ "node": ">=0.4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -15831,9 +16946,9 @@ } }, "@babel/eslint-parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.15.8.tgz", - "integrity": "sha512-fYP7QFngCvgxjUuw8O057SVH5jCXsbFFOoE77CFDcvzwBVgTOkMD/L4mIC5Ud1xf8chK/no2fRbSSn1wvNmKuQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", + "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "dev": true, "requires": { "eslint-scope": "^5.1.1", @@ -16927,22 +18042,28 @@ "integrity": "sha512-QgGnZ9b7o4k0Ai1ZbTJWwZpZcFK9d+Gb+DyNt4UT9x6IEIs5HVu0iIlmgzGqN+t9MoJSpSPo9S/Mm51UtHr3JA==" }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", + "debug": "^4.3.2", + "espree": "^9.3.1", "globals": "^13.9.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "globals": { "version": "13.13.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", @@ -16952,6 +18073,15 @@ "type-fest": "^0.20.2" } }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -16998,7 +18128,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "devOptional": true + "dev": true }, "@hapi/hoek": { "version": "9.2.1", @@ -17016,12 +18146,12 @@ } }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" } @@ -17616,13 +18746,14 @@ } }, "@louislam/sqlite3": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-6.0.1.tgz", - "integrity": "sha512-QGLj5bjQ+O4YSPj/qxtEAArbIqW9wNzBUamlIcRbvFjFiNokItwdubqL2Gl5iX0q1mUn3Z6NoFO1rrAZ/qqlsA==", + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.0.6.tgz", + "integrity": "sha512-+HF/4OEy+yakYzJlSPJbLDtf499t0s0eaglXC9y3Oa9OBZ+dKAaTW5+Ft1RCvfUJLFw/oyYjHtMsg9V+7NT05g==", "requires": { - "@mapbox/node-pre-gyp": "^1.0.7", - "node-addon-api": "^3.0.0", - "node-gyp": "^8.4.1" + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "node-gyp": "^7.1.2", + "tar": "^6.1.11" } }, "@mapbox/node-pre-gyp": { @@ -17677,27 +18808,6 @@ "fastq": "^1.6.0" } }, - "@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "optional": true, - "requires": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, "@npmcli/git": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.0.tgz", @@ -17757,7 +18867,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "devOptional": true, + "dev": true, "requires": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -18620,6 +19730,61 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "aedes": { + "version": "0.46.3", + "resolved": "https://registry.npmjs.org/aedes/-/aedes-0.46.3.tgz", + "integrity": "sha512-i3B+H74uNRhlqcs/JdrMp7e3daz4Cwls0x4yLcfjGXz2tIwnxhF6od4m86O6yyNdz/Gg3jfY3q0sc/Cz8qzg6g==", + "dev": true, + "requires": { + "aedes-packet": "^2.3.1", + "aedes-persistence": "^8.1.3", + "bulk-write-stream": "^2.0.1", + "end-of-stream": "^1.4.4", + "fastfall": "^1.5.1", + "fastparallel": "^2.4.1", + "fastseries": "^2.0.0", + "hyperid": "^3.0.0", + "mqemitter": "^4.5.0", + "mqtt-packet": "^7.1.2", + "readable-stream": "^3.6.0", + "retimer": "^3.0.0", + "reusify": "^1.0.4", + "uuid": "^8.3.2" + }, + "dependencies": { + "mqtt-packet": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-7.1.2.tgz", + "integrity": "sha512-FFZbcZ2omsf4c5TxEQfcX9hI+JzDpDKPT46OmeIBpVA7+t32ey25UNqlqNXTmeZOr5BLsSIERpQQLsFWJS94SQ==", + "dev": true, + "requires": { + "bl": "^4.0.2", + "debug": "^4.1.1", + "process-nextick-args": "^2.0.1" + } + } + } + }, + "aedes-packet": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/aedes-packet/-/aedes-packet-2.3.1.tgz", + "integrity": "sha512-LqBd57uc2rui2RbjycW17dylglejG26mM4ewVXGNDnVp/SUHFVEgm7d1HTmYrnSkSCNoHti042qgcTwv/F+BtQ==", + "dev": true, + "requires": { + "mqtt-packet": "^6.3.0" + } + }, + "aedes-persistence": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/aedes-persistence/-/aedes-persistence-8.1.3.tgz", + "integrity": "sha512-VMCjEV+2g1TNJb/IlDEUy6SP9crT+QUhe2xc6UjyqrFNBNgTvHmOefXY7FxWrwmR2QA02vwg3+5p/JXkyg/Dkw==", + "dev": true, + "requires": { + "aedes-packet": "^2.3.1", + "from2": "^2.3.0", + "qlobber": "^5.0.3" + } + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -18632,7 +19797,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "devOptional": true, + "dev": true, "requires": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -18643,7 +19808,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "devOptional": true, + "dev": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -18653,7 +19818,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "devOptional": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -18661,6 +19826,14 @@ "uri-js": "^4.2.2" } }, + "anafanafo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz", + "integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==", + "requires": { + "char-width-table-consumer": "^1.0.0" + } + }, "ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -18670,12 +19843,6 @@ "string-width": "^4.1.0" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -18760,6 +19927,21 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "optional": true + }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -18776,6 +19958,18 @@ "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.1.0.tgz", "integrity": "sha512-t7Zm5YGgEEc/3eYAicF32m/TNvL+XOeYZy9CvBUeJY/szM7frLolFylhrlZNWV/ohWhcUXygrBGjYmoQdxF4CQ==" }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "optional": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "optional": true + }, "axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -18982,6 +20176,15 @@ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, + "badge-maker": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz", + "integrity": "sha512-OO/PS7Zg2E6qaUWzHEHt21Q5VjcFBAJVA8ztgT/fIdSZFBUwoyeo0ZhA6V5tUM8Vcjq8DJl6jfGhpjESssyqMQ==", + "requires": { + "anafanafo": "2.0.0", + "css-color-converter": "^2.0.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -18990,8 +20193,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "base64id": { "version": "2.0.0", @@ -19013,6 +20215,15 @@ } } }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", @@ -19030,6 +20241,11 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "binary-search": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" + }, "bintrees": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", @@ -19039,7 +20255,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -19086,6 +20301,12 @@ } } }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, "boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", @@ -19243,7 +20464,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -19263,8 +20483,7 @@ "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "builtins": { "version": "5.0.0", @@ -19286,37 +20505,21 @@ } } }, + "bulk-write-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-2.0.1.tgz", + "integrity": "sha512-XWOLjgHtpDasHfwM8oO4df1JoZwa7/OwTsXDzh4rUTo+9CowzeOFBZz43w+H14h1fyq+xl28tVIBrdjcjj4Gug==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, - "cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "optional": true, - "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - } - }, "cacheable-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", @@ -19387,6 +20590,12 @@ "integrity": "sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "optional": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -19404,6 +20613,14 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "char-width-table-consumer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz", + "integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==", + "requires": { + "binary-search": "^1.3.5" + } + }, "chardet": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz", @@ -19445,6 +20662,24 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" }, + "chroma-js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz", + "integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==", + "requires": { + "cross-env": "^6.0.3" + }, + "dependencies": { + "cross-env": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", + "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", + "requires": { + "cross-spawn": "^7.0.0" + } + } + } + }, "ci-info": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", @@ -19467,7 +20702,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "devOptional": true + "dev": true }, "cli-boxes": { "version": "2.2.1", @@ -19543,6 +20778,12 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "optional": true + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -19614,6 +20855,22 @@ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true }, + "commist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "requires": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + }, + "dependencies": { + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + } + } + }, "compare-versions": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", @@ -19629,6 +20886,110 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "concurrently": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.1.0.tgz", + "integrity": "sha512-Bz0tMlYKZRUDqJlNiF/OImojMB9ruKUz6GCfmhFnSapXgPe+3xzY4byqoKG9tUZ7L2PGEUjfLPOLfIX3labnmw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -19712,6 +21073,12 @@ } } }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "devOptional": true + }, "cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -19755,7 +21122,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -19768,6 +21134,39 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, + "css-color-converter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz", + "integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==", + "requires": { + "color-convert": "^0.5.2", + "color-name": "^1.1.4", + "css-unit-converter": "^1.1.2" + }, + "dependencies": { + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "css-functions-list": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz", + "integrity": "sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw==", + "dev": true + }, + "css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -19817,6 +21216,15 @@ "fs-exists-sync": "^0.1.0" } }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -19828,6 +21236,12 @@ "whatwg-url": "^8.0.0" } }, + "date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "dev": true + }, "dayjs": { "version": "1.10.8", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.8.tgz", @@ -20003,6 +21417,31 @@ "esutils": "^2.0.2" } }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, "domexception": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", @@ -20020,6 +21459,26 @@ } } }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, "dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -20035,6 +21494,27 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -20079,6 +21559,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "requires": { "iconv-lite": "^0.6.2" @@ -20088,7 +21569,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -20148,14 +21628,11 @@ "@socket.io/base64-arraybuffer": "~1.0.2" } }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } + "entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true }, "env-paths": { "version": "2.2.1", @@ -20167,7 +21644,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "devOptional": true + "dev": true }, "error-ex": { "version": "1.3.2", @@ -20412,62 +21889,48 @@ } }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", + "glob-parent": "^6.0.1", "globals": "^13.6.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -20477,6 +21940,12 @@ "color-convert": "^2.0.1" } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20508,6 +21977,37 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, "globals": { "version": "13.13.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", @@ -20523,13 +22023,13 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "argparse": "^2.0.1" } }, "supports-color": { @@ -20550,15 +22050,28 @@ } }, "eslint-plugin-vue": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.18.0.tgz", - "integrity": "sha512-ceDXlXYMMPMSXw7tdKUR42w9jlzthJGJ3Kvm3YrZ0zuQfvAySNxe8sm6VHuksBW0+060GzYXhHJG6IHVOfF83Q==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", "dev": true, "requires": { - "eslint-utils": "^2.1.0", + "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", - "semver": "^6.3.0", - "vue-eslint-parser": "^7.10.0" + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "eslint-scope": { @@ -20572,20 +22085,12 @@ } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "eslint-visitor-keys": "^2.0.0" } }, "eslint-visitor-keys": { @@ -20600,20 +22105,26 @@ "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "requires": { - "acorn": "^7.4.0", + "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "eslint-visitor-keys": "^3.3.0" }, "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true } } @@ -20799,6 +22310,12 @@ "basic-auth": "^2.0.1" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, "extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -20822,11 +22339,17 @@ } } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "optional": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "devOptional": true }, "fast-glob": { "version": "3.2.11", @@ -20845,7 +22368,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "devOptional": true }, "fast-levenshtein": { "version": "2.0.6", @@ -20865,6 +22388,25 @@ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, + "fastfall": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz", + "integrity": "sha1-P+4DMxpJ0dObPN96XpzWb0dee5Q=", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } + }, + "fastparallel": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.4.1.tgz", + "integrity": "sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4", + "xtend": "^4.0.2" + } + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -20874,6 +22416,12 @@ "reusify": "^1.0.4" } }, + "fastseries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-2.0.0.tgz", + "integrity": "sha512-XBU9RXeoYc2/VnvMhplAxEmZLfIk7cvTBu+xwoBuTI8pL19E03cmca17QQycKIdxgwCeFA/a4u27gv1h3ya5LQ==", + "dev": true + }, "favico.js": { "version": "0.3.10", "resolved": "https://registry.npmjs.org/favico.js/-/favico.js-0.3.10.tgz", @@ -21076,6 +22624,12 @@ "for-in": "^1.0.1" } }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "optional": true + }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -21102,6 +22656,48 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -21206,6 +22802,15 @@ "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -21296,14 +22901,6 @@ "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - } } }, "globjoin": { @@ -21348,6 +22945,22 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "devOptional": true }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "optional": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "optional": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -21390,6 +23003,15 @@ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true }, + "help-me": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", + "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", + "requires": { + "glob": "^7.1.6", + "readable-stream": "^3.6.0" + } + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -21432,16 +23054,28 @@ "dev": true }, "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", "dev": true }, + "htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "devOptional": true + "dev": true }, "http-errors": { "version": "1.8.1", @@ -21473,6 +23107,17 @@ "debug": "4" } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -21500,11 +23145,21 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "devOptional": true, + "dev": true, "requires": { "ms": "^2.0.0" } }, + "hyperid": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-3.0.1.tgz", + "integrity": "sha512-I+tl7TS5nsoVhkxqX1rS3Qmqlq44eoPUcgPthW8v3IW8CvWL7lwtd6HQbkDUMrBKJTG0vgEaRsjT35imW/D+9Q==", + "dev": true, + "requires": { + "uuid": "^8.3.2", + "uuid-parse": "^1.1.0" + } + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -21516,13 +23171,12 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "ignore-walk": { @@ -21564,19 +23218,19 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "devOptional": true + "dev": true }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "devOptional": true + "dev": true }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "devOptional": true + "dev": true }, "inflight": { "version": "1.0.6", @@ -21728,7 +23382,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", - "devOptional": true + "dev": true }, "is-npm": { "version": "5.0.0", @@ -21801,7 +23455,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "devOptional": true }, "is-valid-path": { "version": "0.1.1", @@ -21823,11 +23477,16 @@ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "devOptional": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "devOptional": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { "version": "3.0.1", @@ -21835,6 +23494,12 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "optional": true + }, "istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -23326,6 +24991,11 @@ "@sideway/pinpoint": "^2.0.0" } }, + "js-sdsl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz", + "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -23342,6 +25012,12 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, "jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -23440,11 +25116,17 @@ "jju": "^1.1.0" } }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "optional": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "devOptional": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -23452,6 +25134,12 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "optional": true + }, "json5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", @@ -23494,6 +25182,18 @@ } } }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, "just-performance": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/just-performance/-/just-performance-4.3.0.tgz", @@ -23845,49 +25545,6 @@ "semver": "^6.0.0" } }, - "make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "optional": true, - "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "dependencies": { - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "optional": true - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "optional": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - } - } - }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -24067,8 +25724,7 @@ "minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minimist-options": { "version": "4.1.0", @@ -24101,28 +25757,16 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "devOptional": true, + "dev": true, "requires": { "minipass": "^3.0.0" } }, - "minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "optional": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - } - }, "minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "devOptional": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -24141,7 +25785,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "devOptional": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -24150,7 +25794,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "devOptional": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -24193,6 +25837,50 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, + "mqemitter": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/mqemitter/-/mqemitter-4.5.0.tgz", + "integrity": "sha512-Mp/zytFeIv6piJQkEKnncHcP4R/ErJc5C7dfonkhkNUT2LA/nTayrfNxbipp3M5iCJUTQSUtzfQAQA3XVcKz6w==", + "dev": true, + "requires": { + "fastparallel": "^2.3.0", + "qlobber": "^5.0.0" + } + }, + "mqtt": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", + "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", + "requires": { + "commist": "^1.0.0", + "concat-stream": "^2.0.0", + "debug": "^4.1.1", + "duplexify": "^4.1.1", + "help-me": "^3.0.0", + "inherits": "^2.0.3", + "lru-cache": "^6.0.0", + "minimist": "^1.2.5", + "mqtt-packet": "^6.8.0", + "number-allocator": "^1.0.9", + "pump": "^3.0.0", + "readable-stream": "^3.6.0", + "reinterval": "^1.1.0", + "rfdc": "^1.3.0", + "split2": "^3.1.0", + "ws": "^7.5.5", + "xtend": "^4.0.2" + } + }, + "mqtt-packet": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", + "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", + "requires": { + "bl": "^4.0.2", + "debug": "^4.1.1", + "process-nextick-args": "^2.0.1" + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -24220,9 +25908,9 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" }, "node-cloudflared-tunnel": { "version": "1.0.9", @@ -24262,69 +25950,140 @@ } }, "node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", "optional": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", + "graceful-fs": "^4.2.3", "nopt": "^5.0.0", - "npmlog": "^6.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", + "semver": "^7.3.2", + "tar": "^6.0.2", "which": "^2.0.2" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "optional": true + }, "are-we-there-yet": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", - "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "optional": true, "requires": { "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "readable-stream": "^2.0.6" } }, "gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" } }, "npmlog": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz", - "integrity": "sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.0", - "set-blocking": "^2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "optional": true, "requires": { "lru-cache": "^6.0.0" } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } } } }, @@ -24409,15 +26168,15 @@ } }, "npm-check-updates": { - "version": "12.5.5", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.5.tgz", - "integrity": "sha512-7LH6KN6F1fZMtY4zNYAQPpJU1ToxZ6sSCxk948vrLIz97aNqmPLSX72MrmbOWwpyBgLCPbFJWY/k3zE18pmxfw==", + "version": "12.5.9", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-12.5.9.tgz", + "integrity": "sha512-l9iOvD7EsQb96gFJL45V01YG6bP8+dmobYnSguvehPuNwgdWNMrE8RC8bSfURX5iUmX4bkobN4T8XMHXN9GMHA==", "dev": true, "requires": { "chalk": "^4.1.2", "cint": "^8.2.1", "cli-table": "^0.3.11", - "commander": "^9.0.0", + "commander": "^9.1.0", "fast-memoize": "^2.5.2", "find-up": "5.0.0", "fp-and-or": "^0.1.3", @@ -24430,11 +26189,11 @@ "lodash": "^4.17.21", "minimatch": "^5.0.1", "p-map": "^4.0.0", - "pacote": "^13.0.3", + "pacote": "^13.0.5", "parse-github-url": "^1.0.2", "progress": "^2.0.3", "prompts": "^2.4.2", - "rc-config-loader": "^4.0.0", + "rc-config-loader": "^4.1.0", "remote-git-tags": "^3.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", @@ -24784,6 +26543,30 @@ "set-blocking": "^2.0.0" } }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-allocator": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.10.tgz", + "integrity": "sha512-K4AvNGKo9lP6HqsZyfSr9KDaqnwFzW203inhQEOwFrmFaYevpdX4VNwdOLk197aHujzbT//z6pCBrCOUYSM5iw==", + "requires": { + "debug": "^4.3.1", + "js-sdsl": "^2.1.2" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "optional": true + }, "numbered": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", @@ -24795,6 +26578,12 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "optional": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -24894,7 +26683,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "devOptional": true, + "dev": true, "requires": { "aggregate-error": "^3.0.0" } @@ -25097,8 +26886,7 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { "version": "1.0.7", @@ -25122,6 +26910,12 @@ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "optional": true + }, "pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", @@ -25173,6 +26967,17 @@ "source-map-js": "^1.0.2" } }, + "postcss-html": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.3.1.tgz", + "integrity": "sha512-SJ7iRw+IngyZv3Z9lChlZU30a9y9MZjZZcoUJmx0T/nKE9S+hetJ8fAv/MRu4bPnGDsXhVlaFs5+umpK3yaaQQ==", + "dev": true, + "requires": { + "htmlparser2": "^7.1.2", + "postcss": "^8.4.0", + "postcss-safe-parser": "^6.0.0" + } + }, "postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -25251,12 +27056,22 @@ } } }, + "prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==" + }, "proc-log": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -25298,13 +27113,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "devOptional": true + "dev": true }, "promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "devOptional": true, + "dev": true, "requires": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -25344,13 +27159,12 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "devOptional": true }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -25360,7 +27174,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "devOptional": true }, "pupa": { "version": "2.1.1", @@ -25414,6 +27228,12 @@ } } }, + "qlobber": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/qlobber/-/qlobber-5.0.3.tgz", + "integrity": "sha512-wW4GTZPePyh0RgOsM18oDyOUlXfurVRgoNyJfS+y7VWPyd0GYhQp5T2tycZFZjonH+hngxIfklGJhTP/ghidgQ==", + "dev": true + }, "qrcode": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz", @@ -25564,9 +27384,9 @@ } }, "rc-config-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.0.0.tgz", - "integrity": "sha512-//LRTblJEcqbmmro1GCmZ39qZXD+JqzuD8Y5/IZU3Dhp3A1Yr0Xn68ks8MQ6qKfKvYCWDveUmRDKDA40c+sCXw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.0.tgz", + "integrity": "sha512-aW+kX4qy0CiM9L4fG4Us3oEOpIrOrXzWykAn+xldD07Y9PXWjTH744oHbv0Kc9ZwWaylw3jMjxaf14RgStrNrA==", "dev": true, "requires": { "debug": "^4.1.1", @@ -25830,12 +27650,80 @@ } } }, + "reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + }, "remote-git-tags": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", "dev": true }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "optional": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "optional": true + } + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -25910,11 +27798,17 @@ "lowercase-keys": "^1.0.0" } }, + "retimer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz", + "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==", + "dev": true + }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "devOptional": true + "dev": true }, "reusify": { "version": "1.0.4", @@ -25922,6 +27816,11 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -26147,7 +28046,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -26155,8 +28053,7 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "signal-exit": { "version": "3.0.7", @@ -26327,6 +28224,12 @@ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, "spawn-please": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-1.0.0.tgz", @@ -26382,17 +28285,42 @@ "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==", "dev": true }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "optional": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, "ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "devOptional": true, + "dev": true, "requires": { "minipass": "^3.1.1" } @@ -26419,6 +28347,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -26488,24 +28421,25 @@ "dev": true }, "stylelint": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.2.0.tgz", - "integrity": "sha512-i0DrmDXFNpDsWiwx6SPRs4/pyw4kvZgqpDGvsTslQMY7hpUl6r33aQvNSn6cnTg2wtZ9rreFElI7XAKpOWi1vQ==", + "version": "14.7.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.7.1.tgz", + "integrity": "sha512-rUOWm67hrzGXXyO/cInENEejF4urh1dLgOb9cr/3XLDb/t/A+rXQp3p6+no8o8QCKTgBUdhVUq/bXMgE988PJw==", "dev": true, "requires": { "balanced-match": "^2.0.0", "colord": "^2.9.2", "cosmiconfig": "^7.0.1", - "debug": "^4.3.3", + "css-functions-list": "^3.0.1", + "debug": "^4.3.4", "execall": "^2.0.0", - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "fastest-levenshtein": "^1.0.12", "file-entry-cache": "^6.0.1", "get-stdin": "^8.0.0", "global-modules": "^2.0.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "globjoin": "^0.1.4", - "html-tags": "^3.1.0", + "html-tags": "^3.2.0", "ignore": "^5.2.0", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", @@ -26513,25 +28447,26 @@ "known-css-properties": "^0.24.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", - "micromatch": "^4.0.4", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.12", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.7", - "postcss-value-parser": "^4.1.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "specificity": "^0.4.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", + "supports-hyperlinks": "^2.2.0", "svg-tags": "^1.0.0", - "table": "^6.7.5", + "table": "^6.8.0", "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.1" }, "dependencies": { "balanced-match": { @@ -26560,12 +28495,6 @@ "which": "^1.3.1" } }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -26586,22 +28515,32 @@ "requires": { "isexe": "^2.0.0" } + }, + "write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } } } }, "stylelint-config-recommended": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-6.0.0.tgz", - "integrity": "sha512-ZorSSdyMcxWpROYUvLEMm0vSZud2uB7tX1hzBZwvVY9SV/uly4AvvJPPhCcymZL3fcQhEQG5AELmrxWqtmzacw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", + "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", "dev": true }, "stylelint-config-standard": { - "version": "24.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-24.0.0.tgz", - "integrity": "sha512-+RtU7fbNT+VlNbdXJvnjc3USNPZRiRVp/d2DxOF/vBDDTi0kH5RX2Ny6errdtZJH3boO+bmqIYEllEmok4jiuw==", + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-25.0.0.tgz", + "integrity": "sha512-21HnP3VSpaT1wFjFvv9VjvOGDtAviv47uTp3uFmzcN+3Lt+RYRv6oAplLaV51Kf792JSxJ6svCJh/G18E9VnCA==", "dev": true, "requires": { - "stylelint-config-recommended": "^6.0.0" + "stylelint-config-recommended": "^7.0.0" } }, "supports-color": { @@ -26894,6 +28833,21 @@ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -26924,6 +28878,11 @@ "mime-types": "~2.1.24" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -26981,7 +28940,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "devOptional": true, + "dev": true, "requires": { "unique-slug": "^2.0.0" } @@ -26990,7 +28949,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "devOptional": true, + "dev": true, "requires": { "imurmurhash": "^0.1.4" } @@ -27113,7 +29072,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "devOptional": true, "requires": { "punycode": "^2.1.0" } @@ -27137,6 +29096,18 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "uuid-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/uuid-parse/-/uuid-parse-1.1.0.tgz", + "integrity": "sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==", + "dev": true + }, "v-pagination-3": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/v-pagination-3/-/v-pagination-3-0.1.7.tgz", @@ -27196,6 +29167,25 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "optional": true + } + } + }, "vite": { "version": "2.6.14", "resolved": "https://registry.npmjs.org/vite/-/vite-2.6.14.tgz", @@ -27261,35 +29251,49 @@ "integrity": "sha512-/3xFwzSykLW2HiiLie43a+FFgNOcokbBJ+fzvFXd0r2T8MYohqvphUyDQ8lbAwzQ3Dlcrb1c9ykifGkhSIAk6A==" }, "vue-eslint-parser": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz", - "integrity": "sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", "dev": true, "requires": { - "debug": "^4.1.1", - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.2.1", + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", "esquery": "^1.4.0", "lodash": "^4.17.21", - "semver": "^6.3.0" + "semver": "^7.3.5" }, "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" } } } @@ -27318,6 +29322,11 @@ "resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.0.0-alpha.2.tgz", "integrity": "sha512-Xp9fGJECns45v+v8jXbCIsAkCybYkEg0lNwr7Z6HDUSMyx2TEIK2giipPE+qXiShEc1Ipn+ZtttH2iq9hwXP4Q==" }, + "vue-prism-editor": { + "version": "2.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz", + "integrity": "sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==" + }, "vue-qrcode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/vue-qrcode/-/vue-qrcode-1.0.0.tgz", @@ -27446,7 +29455,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, "requires": { "isexe": "^2.0.0" } @@ -27536,8 +29544,7 @@ "ws": { "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==" }, "xdg-basedir": { "version": "4.0.0", @@ -27562,6 +29569,11 @@ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 28db266a6..1ba25baf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.14.0", + "version": "1.16.0-beta.0", "license": "MIT", "repository": { "type": "git", @@ -10,12 +10,15 @@ "node": "14.* || >=16.*" }, "scripts": { - "install-legacy": "npm install --legacy-peer-deps", - "update-legacy": "npm update --legacy-peer-deps", + "install-legacy": "npm install", + "update-legacy": "npm update", "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .", + "lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .", "lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore", + "lint-fix:style": "stylelint \"**/*.{vue,css,scss}\" --fix --ignore-path .gitignore", "lint": "npm run lint:js && npm run lint:style", - "dev": "vite --host --config ./config/vite.config.js", + "dev": "concurrently -k -r \"wait-on tcp:3000 && npm run start-server-dev \" \"npm run start-frontend-dev\"", + "start-frontend-dev": "cross-env NODE_ENV=development vite --host --config ./config/vite.config.js", "start": "npm run start-server", "start-server": "node server/server.js", "start-server-dev": "cross-env NODE_ENV=development node server/server.js", @@ -36,7 +39,7 @@ "build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push", "build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain", "upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain", - "setup": "git checkout 1.14.0 && npm ci --production && npm run download-dist", + "setup": "git checkout 1.15.1 && npm ci --production && npm run download-dist", "download-dist": "node extra/download-dist.js", "mark-as-nightly": "node extra/mark-as-nightly.js", "reset-password": "node extra/reset-password.js", @@ -48,6 +51,7 @@ "test-install-script-ubuntu1604": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu1604.dockerfile .", "test-nodejs16": "docker build --progress plain -f test/ubuntu-nodejs16.dockerfile .", "simple-dns-server": "node extra/simple-dns-server.js", + "simple-mqtt-server": "node extra/simple-mqtt-server.js", "update-language-files-with-base-lang": "cd extra/update-language-files && node index.js %npm_config_base_lang% && eslint ../../src/languages/**.js --fix", "update-language-files": "cd extra/update-language-files && node index.js && eslint ../../src/languages/**.js --fix", "ncu-patch": "npm-check-updates -u -t patch", @@ -60,10 +64,11 @@ "@fortawesome/free-regular-svg-icons": "~5.15.4", "@fortawesome/free-solid-svg-icons": "~5.15.4", "@fortawesome/vue-fontawesome": "~3.0.0-5", - "@louislam/sqlite3": "~6.0.1", + "@louislam/sqlite3": "~15.0.6", "@popperjs/core": "~2.10.2", "args-parser": "~1.3.0", "axios": "~0.26.1", + "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", "bree": "~7.1.5", @@ -71,6 +76,7 @@ "chart.js": "~3.6.2", "chartjs-adapter-dayjs": "~1.0.0", "check-password-strength": "^2.0.5", + "chroma-js": "^2.1.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "dayjs": "~1.10.8", @@ -85,12 +91,14 @@ "jsonwebtoken": "~8.5.1", "jwt-decode": "^3.1.2", "limiter": "^2.1.0", + "mqtt": "^4.2.8", "node-cloudflared-tunnel": "~1.0.9", "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", "postcss-rtlcss": "~3.4.1", "postcss-scss": "~4.0.3", + "prismjs": "^1.27.0", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", "qrcode": "~1.5.0", @@ -110,6 +118,7 @@ "vue-i18n": "~9.1.9", "vue-image-crop-upload": "~3.0.3", "vue-multiselect": "~3.0.0-alpha.2", + "vue-prism-editor": "^2.0.0-alpha.2", "vue-qrcode": "~1.0.0", "vue-router": "~4.0.14", "vue-toastification": "~2.0.0-rc.5", @@ -117,26 +126,30 @@ }, "devDependencies": { "@actions/github": "~5.0.1", - "@babel/eslint-parser": "~7.15.8", + "@babel/eslint-parser": "~7.17.0", "@babel/preset-env": "^7.15.8", "@types/bootstrap": "~5.1.9", "@vitejs/plugin-legacy": "~1.6.4", "@vitejs/plugin-vue": "~1.9.4", "@vue/compiler-sfc": "~3.2.31", + "aedes": "^0.46.3", "babel-plugin-rewire": "~1.2.0", + "concurrently": "^7.1.0", "core-js": "~3.18.3", "cross-env": "~7.0.3", "dns2": "~2.0.1", - "eslint": "~7.32.0", - "eslint-plugin-vue": "~7.18.0", + "eslint": "~8.14.0", + "eslint-plugin-vue": "~8.7.1", "jest": "~27.2.5", "jest-puppeteer": "~6.0.3", - "npm-check-updates": "^12.5.5", + "npm-check-updates": "^12.5.9", + "postcss-html": "^1.3.1", "puppeteer": "~13.1.3", "sass": "~1.42.1", - "stylelint": "~14.2.0", - "stylelint-config-standard": "~24.0.0", + "stylelint": "~14.7.1", + "stylelint-config-standard": "~25.0.0", "typescript": "~4.4.4", - "vite": "~2.6.14" + "vite": "~2.6.14", + "wait-on": "^6.0.1" } } diff --git a/public/icon.svg b/public/icon.svg index 825c344e2..9c0bc6cae 100644 --- a/public/icon.svg +++ b/public/icon.svg @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/server/2fa.js b/server/2fa.js index bc8145cff..c7076da20 100644 --- a/server/2fa.js +++ b/server/2fa.js @@ -1,8 +1,12 @@ -const { checkLogin } = require("./util-server"); const { R } = require("redbean-node"); class TwoFA { + /** + * Disable 2FA for specified user + * @param {number} userID ID of user to disable + * @returns {Promise} + */ static async disable2FA(userID) { return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [ userID, diff --git a/server/auth.js b/server/auth.js index cd14f690e..3ce1a6041 100644 --- a/server/auth.js +++ b/server/auth.js @@ -2,14 +2,13 @@ const basicAuth = require("express-basic-auth"); const passwordHash = require("./password-hash"); const { R } = require("redbean-node"); const { setting } = require("./util-server"); -const { debug } = require("../src/util"); const { loginRateLimiter } = require("./rate-limiter"); /** - * - * @param username : string - * @param password : string - * @returns {Promise} + * Login to web app + * @param {string} username + * @param {string} password + * @returns {Promise<(Bean|null)>} */ exports.login = async function (username, password) { if (typeof username !== "string" || typeof password !== "string") { @@ -35,11 +34,17 @@ exports.login = async function (username, password) { }; /** - * A function that checks if a user is logged in. - * @param {string} username The username of the user to check for. - * @param {function} callback The callback to call when done, with an error and result parameter. - * - * Generated by Trelent + * Callback for myAuthorizer + * @callback myAuthorizerCB + * @param {any} err Any error encountered + * @param {boolean} authorized Is the client authorized? + */ + +/** + * Custom authorizer for express-basic-auth + * @param {string} username + * @param {string} password + * @param {myAuthorizerCB} callback */ function myAuthorizer(username, password, callback) { // Login Rate Limit diff --git a/server/check-version.js b/server/check-version.js index c9d87c96f..00b47a26e 100644 --- a/server/check-version.js +++ b/server/check-version.js @@ -7,6 +7,7 @@ exports.latestVersion = null; let interval; +/** Start 48 hour check interval */ exports.startInterval = () => { let check = async () => { try { @@ -42,6 +43,11 @@ exports.startInterval = () => { interval = setInterval(check, 3600 * 1000 * 48); }; +/** + * Enable the check update feature + * @param {boolean} value Should the check update feature be enabled? + * @returns {Promise} + */ exports.enableCheckUpdate = async (value) => { await setSetting("checkUpdate", value); diff --git a/server/client.js b/server/client.js index 3a2d6df27..f6f133d19 100644 --- a/server/client.js +++ b/server/client.js @@ -3,15 +3,15 @@ */ const { TimeLogger } = require("../src/util"); const { R } = require("redbean-node"); -const { io } = require("./server"); +const { UptimeKumaServer } = require("./uptime-kuma-server"); +const io = UptimeKumaServer.getInstance().io; const { setting } = require("./util-server"); const checkVersion = require("./check-version"); /** - * Send a list of notifications to the user. - * @param {Socket} socket The socket object that is connected to the client. - * - * Generated by Trelent + * Send list of notification providers to client + * @param {Socket} socket Socket.io socket instance + * @returns {Promise} */ async function sendNotificationList(socket) { const timeLogger = new TimeLogger(); @@ -34,8 +34,11 @@ async function sendNotificationList(socket) { /** * Send Heartbeat History list to socket - * @param toUser True = send to all browsers with the same user id, False = send to the current browser only - * @param overwrite Overwrite client-side's heartbeat list + * @param {Socket} socket Socket.io instance + * @param {number} monitorID ID of monitor to send heartbeat history + * @param {boolean} [toUser=false] True = send to all browsers with the same user id, False = send to the current browser only + * @param {boolean} [overwrite=false] Overwrite client-side's heartbeat list + * @returns {Promise} */ async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) { const timeLogger = new TimeLogger(); @@ -61,11 +64,12 @@ async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = } /** - * Important Heart beat list (aka event list) - * @param socket - * @param monitorID - * @param toUser True = send to all browsers with the same user id, False = send to the current browser only - * @param overwrite Overwrite client-side's heartbeat list + * Important Heart beat list (aka event list) + * @param {Socket} socket Socket.io instance + * @param {number} monitorID ID of monitor to send heartbeat history + * @param {boolean} [toUser=false] True = send to all browsers with the same user id, False = send to the current browser only + * @param {boolean} [overwrite=false] Overwrite client-side's heartbeat list + * @returns {Promise} */ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) { const timeLogger = new TimeLogger(); @@ -90,15 +94,14 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove } /** - * Delivers proxy list - * - * @param socket + * Emit proxy list to client + * @param {Socket} socket Socket.io socket instance * @return {Promise} */ async function sendProxyList(socket) { const timeLogger = new TimeLogger(); - const list = await R.find("proxy", " user_id = ? ", [socket.userID]); + const list = await R.find("proxy", " user_id = ? ", [ socket.userID ]); io.to(socket.userID).emit("proxyList", list.map(bean => bean.export())); timeLogger.print("Send Proxy List"); @@ -108,9 +111,8 @@ async function sendProxyList(socket) { /** * Emits the version information to the client. - * @param {Socket} socket The socket object that is connected to the client. - * - * Generated by Trelent + * @param {Socket} socket Socket.io socket instance + * @returns {Promise} */ async function sendInfo(socket) { socket.emit("info", { diff --git a/server/config.js b/server/config.js index 24ccfaa14..d46f24b75 100644 --- a/server/config.js +++ b/server/config.js @@ -1,7 +1,20 @@ const args = require("args-parser")(process.argv); const demoMode = args["demo"] || false; +const badgeConstants = { + naColor: "#999", + defaultUpColor: "#66c20a", + defaultDownColor: "#c2290a", + defaultPingColor: "blue", // as defined by badge-maker / shields.io + defaultStyle: "flat", + defaultPingValueSuffix: "ms", + defaultPingLabelSuffix: "h", + defaultUptimeValueSuffix: "%", + defaultUptimeLabelSuffix: "h", +}; + module.exports = { args, - demoMode + demoMode, + badgeConstants, }; diff --git a/server/database.js b/server/database.js index a5046c6d4..6a3511c6d 100644 --- a/server/database.js +++ b/server/database.js @@ -1,7 +1,7 @@ const fs = require("fs"); const { R } = require("redbean-node"); const { setSetting, setting } = require("./util-server"); -const { debug, sleep } = require("../src/util"); +const { log, sleep } = require("../src/util"); const dayjs = require("dayjs"); const knex = require("knex"); @@ -57,7 +57,9 @@ class Database { "patch-status-page.sql": true, "patch-proxy.sql": true, "patch-monitor-expiry-notification.sql": true, - } + "patch-status-page-footer-css.sql": true, + "patch-added-mqtt-monitor.sql": true, + }; /** * The final version should be 10 after merged tag feature @@ -67,6 +69,10 @@ class Database { static noReject = true; + /** + * Initialize the database + * @param {Object} args Arguments to initialize DB with + */ static init(args) { // Data Directory (must be end with "/") Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/"; @@ -81,9 +87,18 @@ class Database { fs.mkdirSync(Database.uploadDir, { recursive: true }); } - console.log(`Data Dir: ${Database.dataDir}`); + log.info("db", `Data Dir: ${Database.dataDir}`); } + /** + * Connect to the database + * @param {boolean} [testMode=false] Should the connection be + * started in test mode? + * @param {boolean} [autoloadModels=true] Should models be + * automatically loaded? + * @param {boolean} [noLog=false] Should logs not be output? + * @returns {Promise} + */ static async connect(testMode = false, autoloadModels = true, noLog = false) { const acquireConnectionTimeout = 120 * 1000; @@ -136,13 +151,14 @@ class Database { await R.exec("PRAGMA synchronous = FULL"); if (!noLog) { - console.log("SQLite config:"); - console.log(await R.getAll("PRAGMA journal_mode")); - console.log(await R.getAll("PRAGMA cache_size")); - console.log("SQLite Version: " + await R.getCell("SELECT sqlite_version()")); + log.info("db", "SQLite config:"); + log.info("db", await R.getAll("PRAGMA journal_mode")); + log.info("db", await R.getAll("PRAGMA cache_size")); + log.info("db", "SQLite Version: " + await R.getCell("SELECT sqlite_version()")); } } + /** Patch the database */ static async patch() { let version = parseInt(await setting("database_version")); @@ -150,15 +166,15 @@ class Database { version = 0; } - console.info("Your database version: " + version); - console.info("Latest database version: " + this.latestVersion); + log.info("db", "Your database version: " + version); + log.info("db", "Latest database version: " + this.latestVersion); if (version === this.latestVersion) { - console.info("Database patch not needed"); + log.info("db", "Database patch not needed"); } else if (version > this.latestVersion) { - console.info("Warning: Database version is newer than expected"); + log.info("db", "Warning: Database version is newer than expected"); } else { - console.info("Database patch is needed"); + log.info("db", "Database patch is needed"); this.backup(version); @@ -166,17 +182,17 @@ class Database { try { for (let i = version + 1; i <= this.latestVersion; i++) { const sqlFile = `./db/patch${i}.sql`; - console.info(`Patching ${sqlFile}`); + log.info("db", `Patching ${sqlFile}`); await Database.importSQLFile(sqlFile); - console.info(`Patched ${sqlFile}`); + log.info("db", `Patched ${sqlFile}`); await setSetting("database_version", i); } } catch (ex) { await Database.close(); - console.error(ex); - console.error("Start Uptime-Kuma failed due to issue patching the database"); - console.error("Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); + log.error("db", ex); + log.error("db", "Start Uptime-Kuma failed due to issue patching the database"); + log.error("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); this.restore(); process.exit(1); @@ -188,19 +204,21 @@ class Database { } /** + * Patch DB using new process * Call it from patch() only + * @private * @returns {Promise} */ static async patch2() { - console.log("Database Patch 2.0 Process"); + log.info("db", "Database Patch 2.0 Process"); let databasePatchedFiles = await setting("databasePatchedFiles"); if (! databasePatchedFiles) { databasePatchedFiles = {}; } - debug("Patched files:"); - debug(databasePatchedFiles); + log.debug("db", "Patched files:"); + log.debug("db", databasePatchedFiles); try { for (let sqlFilename in this.patchList) { @@ -208,15 +226,15 @@ class Database { } if (this.patched) { - console.log("Database Patched Successfully"); + log.info("db", "Database Patched Successfully"); } } catch (ex) { await Database.close(); - console.error(ex); - console.error("Start Uptime-Kuma failed due to issue patching the database"); - console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); + log.error("db", ex); + log.error("db", "Start Uptime-Kuma failed due to issue patching the database"); + log.error("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); this.restore(); @@ -295,24 +313,27 @@ class Database { } /** + * Patch database using new patching process * Used it patch2() only + * @private * @param sqlFilename * @param databasePatchedFiles + * @returns {Promise} */ static async patch2Recursion(sqlFilename, databasePatchedFiles) { let value = this.patchList[sqlFilename]; if (! value) { - console.log(sqlFilename + " skip"); + log.info("db", sqlFilename + " skip"); return; } // Check if patched if (! databasePatchedFiles[sqlFilename]) { - console.log(sqlFilename + " is not patched"); + log.info("db", sqlFilename + " is not patched"); if (value.parents) { - console.log(sqlFilename + " need parents"); + log.info("db", sqlFilename + " need parents"); for (let parentSQLFilename of value.parents) { await this.patch2Recursion(parentSQLFilename, databasePatchedFiles); } @@ -320,24 +341,24 @@ class Database { this.backup(dayjs().format("YYYYMMDDHHmmss")); - console.log(sqlFilename + " is patching"); + log.info("db", sqlFilename + " is patching"); this.patched = true; await this.importSQLFile("./db/" + sqlFilename); databasePatchedFiles[sqlFilename] = true; - console.log(sqlFilename + " was patched successfully"); + log.info("db", sqlFilename + " was patched successfully"); } else { - debug(sqlFilename + " is already patched, skip"); + log.debug("db", sqlFilename + " is already patched, skip"); } } /** - * Sadly, multi sql statements is not supported by many sqlite libraries, I have to implement it myself - * @param filename + * Load an SQL file and execute it + * @param filename Filename of SQL file to import * @returns {Promise} */ static async importSQLFile(filename) { - + // Sadly, multi sql statements is not supported by many sqlite libraries, I have to implement it myself await R.getCell("SELECT 1"); let text = fs.readFileSync(filename).toString(); @@ -365,6 +386,10 @@ class Database { } } + /** + * Aquire a direct connection to database + * @returns {any} + */ static getBetterSQLite3Database() { return R.knex.client.acquireConnection(); } @@ -379,7 +404,7 @@ class Database { }; process.addListener("unhandledRejection", listener); - console.log("Closing the database"); + log.info("db", "Closing the database"); while (true) { Database.noReject = true; @@ -389,10 +414,10 @@ class Database { if (Database.noReject) { break; } else { - console.log("Waiting to close the database"); + log.info("db", "Waiting to close the database"); } } - console.log("SQLite closed"); + log.info("db", "SQLite closed"); process.removeListener("unhandledRejection", listener); } @@ -400,11 +425,11 @@ class Database { /** * One backup one time in this process. * Reset this.backupPath if you want to backup again - * @param version + * @param {string} version Version code of backup */ static backup(version) { if (! this.backupPath) { - console.info("Backing up the database"); + log.info("db", "Backing up the database"); this.backupPath = this.dataDir + "kuma.db.bak" + version; fs.copyFileSync(Database.path, this.backupPath); @@ -422,12 +447,10 @@ class Database { } } - /** - * - */ + /** Restore from most recent backup */ static restore() { if (this.backupPath) { - console.error("Patching the database failed!!! Restoring the backup"); + log.error("db", "Patching the database failed!!! Restoring the backup"); const shmPath = Database.path + "-shm"; const walPath = Database.path + "-wal"; @@ -446,7 +469,7 @@ class Database { fs.unlinkSync(walPath); } } catch (e) { - console.log("Restore failed; you may need to restore the backup manually"); + log.error("db", "Restore failed; you may need to restore the backup manually"); process.exit(1); } @@ -462,17 +485,22 @@ class Database { } } else { - console.log("Nothing to restore"); + log.info("db", "Nothing to restore"); } } + /** Get the size of the database */ static getSize() { - debug("Database.getSize()"); + log.debug("db", "Database.getSize()"); let stats = fs.statSync(Database.path); - debug(stats); + log.debug("db", stats); return stats.size; } + /** + * Shrink the database + * @returns {Promise} + */ static async shrink() { await R.exec("VACUUM"); } diff --git a/server/image-data-uri.js b/server/image-data-uri.js index 1ab499c15..eaf651f01 100644 --- a/server/image-data-uri.js +++ b/server/image-data-uri.js @@ -3,18 +3,21 @@ Modified with 0 dependencies */ let fs = require("fs"); +const { log } = require("../src/util"); let ImageDataURI = (() => { /** - * @param {string} dataURI - A string that is a valid Data URI. - * @returns {?Object} An object with properties "imageType" and "dataBase64". The former is the image type, e.g., "png", and the latter is a base64 encoded string of the image's binary data. If it fails to parse, returns null instead of an object. - * - * Generated by Trelent + * Decode the data:image/ URI + * @param {string} dataURI data:image/ URI to decode + * @returns {?Object} An object with properties "imageType" and "dataBase64". + * The former is the image type, e.g., "png", and the latter is a base64 + * encoded string of the image's binary data. If it fails to parse, returns + * null instead of an object. */ function decode(dataURI) { if (!/data:image\//.test(dataURI)) { - console.log("ImageDataURI :: Error :: It seems that it is not an Image Data URI. Couldn't match \"data:image/\""); + log.error("image-data-uri", "It seems that it is not an Image Data URI. Couldn't match \"data:image/\""); return null; } @@ -27,15 +30,15 @@ let ImageDataURI = (() => { } /** - * @param {Buffer} data - The image data to be encoded. - * @param {String} mediaType - The type of the image, e.g., "image/png". - * @returns {String|null} A string representing the base64-encoded version of the given Buffer object or null if an error occurred. - * - * Generated by Trelent + * Endcode an image into data:image/ URI + * @param {(Buffer|string)} data Data to encode + * @param {string} mediaType Media type of data + * @returns {(string|null)} A string representing the base64-encoded + * version of the given Buffer object or null if an error occurred. */ function encode(data, mediaType) { if (!data || !mediaType) { - console.log("ImageDataURI :: Error :: Missing some of the required params: data, mediaType "); + log.error("image-data-uri", "Missing some of the required params: data, mediaType"); return null; } @@ -47,11 +50,10 @@ let ImageDataURI = (() => { } /** - * Converts a data URI to a file path. - * @param {string} dataURI The Data URI of the image. - * @param {string} [filePath] The path where the image will be saved, defaults to "./". - * - * Generated by Trelent + * Write data URI to file + * @param {string} dataURI data:image/ URI + * @param {string} [filePath] Path to write file to + * @returns {Promise} */ function outputFile(dataURI, filePath) { filePath = filePath || "./"; diff --git a/server/jobs.js b/server/jobs.js index d33adb98c..f9c7f86e9 100644 --- a/server/jobs.js +++ b/server/jobs.js @@ -1,6 +1,7 @@ const path = require("path"); const Bree = require("bree"); const { SHARE_ENV } = require("worker_threads"); +const { log } = require("../src/util"); let bree; const jobs = [ { @@ -9,6 +10,11 @@ const jobs = [ }, ]; +/** + * Initialize background jobs + * @param {Object} args Arguments to pass to workers + * @returns {Bree} + */ const initBackgroundJobs = function (args) { bree = new Bree({ root: path.resolve("server", "jobs"), @@ -18,7 +24,7 @@ const initBackgroundJobs = function (args) { workerData: args, }, workerMessageHandler: (message) => { - console.log("[Background Job]:", message); + log.info("jobs", message); } }); diff --git a/server/jobs/clear-old-data.js b/server/jobs/clear-old-data.js index 7c368014d..0ec5ffa5f 100644 --- a/server/jobs/clear-old-data.js +++ b/server/jobs/clear-old-data.js @@ -30,7 +30,7 @@ const DEFAULT_KEEP_PERIOD = 180; try { await R.exec( "DELETE FROM heartbeat WHERE time < DATETIME('now', '-' || ? || ' days') ", - [parsedPeriod] + [ parsedPeriod ] ); } catch (e) { log(`Failed to clear old data: ${e.message}`); diff --git a/server/jobs/util-worker.js b/server/jobs/util-worker.js index 9426840d7..1aeec794d 100644 --- a/server/jobs/util-worker.js +++ b/server/jobs/util-worker.js @@ -2,14 +2,24 @@ const { parentPort, workerData } = require("worker_threads"); const Database = require("../database"); const path = require("path"); +/** + * Send message to parent process for logging + * since worker_thread does not have access to stdout, this is used + * instead of console.log() + * @param {any} any The message to log + */ const log = function (any) { if (parentPort) { parentPort.postMessage(any); } }; +/** + * Exit the worker process + * @param {number} error The status code to exit + */ const exit = function (error) { - if (error && error != 0) { + if (error && error !== 0) { process.exit(error); } else { if (parentPort) { @@ -20,6 +30,7 @@ const exit = function (error) { } }; +/** Connects to the database */ const connectDb = async function () { const dbPath = path.join( process.env.DATA_DIR || workerData["data-dir"] || "./data/" diff --git a/server/model/group.js b/server/model/group.js index 3e1f2d449..599b758bc 100644 --- a/server/model/group.js +++ b/server/model/group.js @@ -3,6 +3,12 @@ const { R } = require("redbean-node"); class Group extends BeanModel { + /** + * Return an object that ready to parse to JSON for public + * Only show necessary data to public + * @param {boolean} [showTags=false] Should the JSON include monitor tags + * @returns {Object} + */ async toPublicJSON(showTags = false) { let monitorBeanList = await this.getMonitorList(); let monitorList = []; @@ -19,6 +25,10 @@ class Group extends BeanModel { }; } + /** + * Get all monitors + * @returns {Bean[]} + */ async getMonitorList() { return R.convertToBeans("monitor", await R.getAll(` SELECT monitor.* FROM monitor, monitor_group diff --git a/server/model/heartbeat.js b/server/model/heartbeat.js index e0a77c069..a0b40d08e 100644 --- a/server/model/heartbeat.js +++ b/server/model/heartbeat.js @@ -13,6 +13,11 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); */ class Heartbeat extends BeanModel { + /** + * Return an object that ready to parse to JSON for public + * Only show necessary data to public + * @returns {Object} + */ toPublicJSON() { return { status: this.status, @@ -22,6 +27,10 @@ class Heartbeat extends BeanModel { }; } + /** + * Return an object that ready to parse to JSON + * @returns {Object} + */ toJSON() { return { monitorID: this.monitor_id, diff --git a/server/model/incident.js b/server/model/incident.js index 89c117e90..f954cc74a 100644 --- a/server/model/incident.js +++ b/server/model/incident.js @@ -2,6 +2,11 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); class Incident extends BeanModel { + /** + * Return an object that ready to parse to JSON for public + * Only show necessary data to public + * @returns {Object} + */ toPublicJSON() { return { id: this.id, diff --git a/server/model/monitor.js b/server/model/monitor.js index 894ae71e5..c7e2cd315 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -6,8 +6,8 @@ dayjs.extend(utc); dayjs.extend(timezone); const axios = require("axios"); const { Prometheus } = require("../prometheus"); -const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); -const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = require("../util-server"); +const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); +const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mqttAsync } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification"); @@ -15,6 +15,7 @@ const { Proxy } = require("../proxy"); const { demoMode } = require("../config"); const version = require("../../package.json").version; const apicache = require("../modules/apicache"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); /** * status: @@ -27,6 +28,7 @@ class Monitor extends BeanModel { /** * Return an object that ready to parse to JSON for public * Only show necessary data to public + * @returns {Object} */ async toPublicJSON(showTags = false) { let obj = { @@ -41,8 +43,9 @@ class Monitor extends BeanModel { /** * Return an object that ready to parse to JSON + * @returns {Object} */ - async toJSON() { + async toJSON(includeSensitiveData = true) { let notificationIDList = {}; @@ -56,15 +59,11 @@ class Monitor extends BeanModel { const tags = await this.getTags(); - return { + let data = { id: this.id, name: this.name, url: this.url, method: this.method, - body: this.body, - headers: this.headers, - basic_auth_user: this.basic_auth_user, - basic_auth_pass: this.basic_auth_pass, hostname: this.hostname, port: this.port, maxretries: this.maxretries, @@ -89,11 +88,32 @@ class Monitor extends BeanModel { proxyId: this.proxy_id, notificationIDList, tags: tags, + mqttUsername: this.mqttUsername, + mqttPassword: this.mqttPassword, + mqttTopic: this.mqttTopic, + mqttSuccessMessage: this.mqttSuccessMessage }; + + if (includeSensitiveData) { + data = { + ...data, + headers: this.headers, + body: this.body, + basic_auth_user: this.basic_auth_user, + basic_auth_pass: this.basic_auth_pass, + pushToken: this.pushToken, + }; + } + + return data; } + /** + * Get all tags applied to this monitor + * @returns {Promise[]>} + */ async getTags() { - return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]); + return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [ this.id ]); } /** @@ -105,6 +125,10 @@ class Monitor extends BeanModel { return Buffer.from(user + ":" + pass).toString("base64"); } + /** + * Is the TLS expiry notification enabled? + * @returns {boolean} + */ isEnabledExpiryNotification() { return Boolean(this.expiryNotification); } @@ -125,10 +149,18 @@ class Monitor extends BeanModel { return Boolean(this.upsideDown); } + /** + * Get accepted status codes + * @returns {Object} + */ getAcceptedStatuscodes() { return JSON.parse(this.accepted_statuscodes_json); } + /** + * Start monitor + * @param {Server} io Socket server instance + */ start(io) { let previousBeat = null; let retries = 0; @@ -154,7 +186,7 @@ class Monitor extends BeanModel { // undefined if not https let tlsInfo = undefined; - if (! previousBeat) { + if (!previousBeat || this.type === "push") { previousBeat = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [ this.id, ]); @@ -172,7 +204,7 @@ class Monitor extends BeanModel { } // Duration - if (! isFirstBeat) { + if (!isFirstBeat) { bean.duration = dayjs(bean.time).diff(dayjs(previousBeat.time), "second"); } else { bean.duration = 0; @@ -196,7 +228,7 @@ class Monitor extends BeanModel { rejectUnauthorized: !this.getIgnoreTls(), }; - debug(`[${this.name}] Prepare Options for axios`); + log.debug("monitor", `[${this.name}] Prepare Options for axios`); const options = { url: this.url, @@ -233,8 +265,8 @@ class Monitor extends BeanModel { options.httpsAgent = new https.Agent(httpsAgentOptions); } - debug(`[${this.name}] Axios Options: ${JSON.stringify(options)}`); - debug(`[${this.name}] Axios Request`); + log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`); + log.debug("monitor", `[${this.name}] Axios Request`); let res = await axios.request(options); bean.msg = `${res.status} - ${res.statusText}`; @@ -243,29 +275,30 @@ class Monitor extends BeanModel { // Check certificate if https is used let certInfoStartTime = dayjs().valueOf(); if (this.getUrl()?.protocol === "https:") { - debug(`[${this.name}] Check cert`); + log.debug("monitor", `[${this.name}] Check cert`); try { let tlsInfoObject = checkCertificate(res); tlsInfo = await this.updateTlsInfo(tlsInfoObject); if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) { - debug(`[${this.name}] call sendCertNotification`); + log.debug("monitor", `[${this.name}] call sendCertNotification`); await this.sendCertNotification(tlsInfoObject); } } catch (e) { if (e.message !== "No TLS certificate in response") { - console.error(e.message); + log.error("monitor", "Caught error"); + log.error("monitor", e.message); } } } if (process.env.TIMELOGGER === "1") { - debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms"); + log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms"); } - if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) { - console.log(res.data); + if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID === this.id) { + log.info("monitor", res.data); } if (this.type === "http") { @@ -304,24 +337,24 @@ class Monitor extends BeanModel { let dnsRes = await dnsResolve(this.hostname, this.dns_resolve_server, this.dns_resolve_type); bean.ping = dayjs().valueOf() - startTime; - if (this.dns_resolve_type == "A" || this.dns_resolve_type == "AAAA" || this.dns_resolve_type == "TXT") { + if (this.dns_resolve_type === "A" || this.dns_resolve_type === "AAAA" || this.dns_resolve_type === "TXT") { dnsMessage += "Records: "; dnsMessage += dnsRes.join(" | "); - } else if (this.dns_resolve_type == "CNAME" || this.dns_resolve_type == "PTR") { + } else if (this.dns_resolve_type === "CNAME" || this.dns_resolve_type === "PTR") { dnsMessage = dnsRes[0]; - } else if (this.dns_resolve_type == "CAA") { + } else if (this.dns_resolve_type === "CAA") { dnsMessage = dnsRes[0].issue; - } else if (this.dns_resolve_type == "MX") { + } else if (this.dns_resolve_type === "MX") { dnsRes.forEach(record => { dnsMessage += `Hostname: ${record.exchange} - Priority: ${record.priority} | `; }); dnsMessage = dnsMessage.slice(0, -2); - } else if (this.dns_resolve_type == "NS") { + } else if (this.dns_resolve_type === "NS") { dnsMessage += "Servers: "; dnsMessage += dnsRes.join(" | "); - } else if (this.dns_resolve_type == "SOA") { + } else if (this.dns_resolve_type === "SOA") { dnsMessage += `NS-Name: ${dnsRes.nsname} | Hostmaster: ${dnsRes.hostmaster} | Serial: ${dnsRes.serial} | Refresh: ${dnsRes.refresh} | Retry: ${dnsRes.retry} | Expire: ${dnsRes.expire} | MinTTL: ${dnsRes.minttl}`; - } else if (this.dns_resolve_type == "SRV") { + } else if (this.dns_resolve_type === "SRV") { dnsRes.forEach(record => { dnsMessage += `Name: ${record.name} | Port: ${record.port} | Priority: ${record.priority} | Weight: ${record.weight} | `; }); @@ -345,12 +378,9 @@ class Monitor extends BeanModel { time ]); - debug("heartbeatCount" + heartbeatCount + " " + time); + log.debug("monitor", "heartbeatCount" + heartbeatCount + " " + time); if (heartbeatCount <= 0) { - // Fix #922, since previous heartbeat could be inserted by api, it should get from database - previousBeat = await Monitor.getPreviousHeartbeat(this.id); - throw new Error("No heartbeat in the time window"); } else { // No need to insert successful heartbeat for push type, so end here @@ -376,7 +406,7 @@ class Monitor extends BeanModel { }, httpsAgent: new https.Agent({ maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940) - rejectUnauthorized: ! this.getIgnoreTls(), + rejectUnauthorized: !this.getIgnoreTls(), }), maxRedirects: this.maxredirects, validateStatus: (status) => { @@ -398,7 +428,6 @@ class Monitor extends BeanModel { } else { throw new Error("Server not found on Steam"); } - } else if (this.type === "docker") { debug(`[${this.name}] Prepare Options for Axios`); @@ -426,7 +455,14 @@ class Monitor extends BeanModel { bean.status = UP; bean.msg = ""; } - + } else if (this.type === "mqtt") { + bean.msg = await mqttAsync(this.hostname, this.mqttTopic, this.mqttSuccessMessage, { + port: this.port, + username: this.mqttUsername, + password: this.mqttPassword, + interval: this.interval, + }); + bean.status = UP; } else { bean.msg = "Unknown Monitor Type"; bean.status = PENDING; @@ -457,7 +493,7 @@ class Monitor extends BeanModel { } } - debug(`[${this.name}] Check isImportant`); + log.debug("monitor", `[${this.name}] Check isImportant`); let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status); // Mark as important if status changed, ignore pending pings, @@ -465,11 +501,11 @@ class Monitor extends BeanModel { if (isImportant) { bean.important = true; - debug(`[${this.name}] sendNotification`); + log.debug("monitor", `[${this.name}] sendNotification`); await Monitor.sendNotification(isFirstBeat, this, bean); // Clear Status Page Cache - debug(`[${this.name}] apicache clear`); + log.debug("monitor", `[${this.name}] apicache clear`); apicache.clear(); } else { @@ -477,47 +513,48 @@ class Monitor extends BeanModel { } if (bean.status === UP) { - console.info(`Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); + log.info("monitor", `Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); } else if (bean.status === PENDING) { if (this.retryInterval > 0) { beatInterval = this.retryInterval; } - console.warn(`Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`); + log.warn("monitor", `Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`); } else { - console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); + log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); } - debug(`[${this.name}] Send to socket`); + log.debug("monitor", `[${this.name}] Send to socket`); io.to(this.user_id).emit("heartbeat", bean.toJSON()); Monitor.sendStats(io, this.id, this.user_id); - debug(`[${this.name}] Store`); + log.debug("monitor", `[${this.name}] Store`); await R.store(bean); - debug(`[${this.name}] prometheus.update`); + log.debug("monitor", `[${this.name}] prometheus.update`); prometheus.update(bean, tlsInfo); previousBeat = bean; if (! this.isStop) { - debug(`[${this.name}] SetTimeout for next check.`); + log.debug("monitor", `[${this.name}] SetTimeout for next check.`); this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); } else { - console.log(`[${this.name}] isStop = true, no next check.`); + log.info("monitor", `[${this.name}] isStop = true, no next check.`); } }; + /** Get a heartbeat and handle errors */ const safeBeat = async () => { try { await beat(); } catch (e) { console.trace(e); - errorLog(e, false); - console.error("Please report to https://github.com/louislam/uptime-kuma/issues"); + UptimeKumaServer.errorLog(e, false); + log.error("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues"); if (! this.isStop) { - console.log("Try to restart the monitor"); + log.info("monitor", "Try to restart the monitor"); this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000); } } @@ -533,6 +570,7 @@ class Monitor extends BeanModel { } } + /** Stop monitor */ stop() { clearTimeout(this.heartbeatInterval); this.isStop = true; @@ -540,6 +578,10 @@ class Monitor extends BeanModel { this.prometheus().remove(); } + /** + * Get a new prometheus instance + * @returns {Prometheus} + */ prometheus() { return new Prometheus(this); } @@ -548,7 +590,7 @@ class Monitor extends BeanModel { * Helper Method: * returns URL object for further usage * returns null if url is invalid - * @returns {null|URL} + * @returns {(null|URL)} */ getUrl() { try { @@ -561,48 +603,54 @@ class Monitor extends BeanModel { /** * Store TLS info to database * @param checkCertificateResult - * @returns {Promise} + * @returns {Promise} */ async updateTlsInfo(checkCertificateResult) { - let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ + let tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ this.id, ]); - if (tls_info_bean == null) { - tls_info_bean = R.dispense("monitor_tls_info"); - tls_info_bean.monitor_id = this.id; + if (tlsInfoBean == null) { + tlsInfoBean = R.dispense("monitor_tls_info"); + tlsInfoBean.monitor_id = this.id; } else { // Clear sent history if the cert changed. try { - let oldCertInfo = JSON.parse(tls_info_bean.info_json); + let oldCertInfo = JSON.parse(tlsInfoBean.info_json); let isValidObjects = oldCertInfo && oldCertInfo.certInfo && checkCertificateResult && checkCertificateResult.certInfo; if (isValidObjects) { if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) { - debug("Resetting sent_history"); + log.debug("monitor", "Resetting sent_history"); await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [ this.id ]); } else { - debug("No need to reset sent_history"); - debug(oldCertInfo.certInfo.fingerprint256); - debug(checkCertificateResult.certInfo.fingerprint256); + log.debug("monitor", "No need to reset sent_history"); + log.debug("monitor", oldCertInfo.certInfo.fingerprint256); + log.debug("monitor", checkCertificateResult.certInfo.fingerprint256); } } else { - debug("Not valid object"); + log.debug("monitor", "Not valid object"); } } catch (e) { } } - tls_info_bean.info_json = JSON.stringify(checkCertificateResult); - await R.store(tls_info_bean); + tlsInfoBean.info_json = JSON.stringify(checkCertificateResult); + await R.store(tlsInfoBean); return checkCertificateResult; } + /** + * Send statistics to clients + * @param {Server} io Socket server instance + * @param {number} monitorID ID of monitor to send + * @param {number} userID ID of user to send to + */ static async sendStats(io, monitorID, userID) { const hasClients = getTotalClientInRoom(io, userID) > 0; @@ -612,13 +660,13 @@ class Monitor extends BeanModel { await Monitor.sendUptime(24 * 30, io, monitorID, userID); await Monitor.sendCertInfo(io, monitorID, userID); } else { - debug("No clients in the room, no need to send stats"); + log.debug("monitor", "No clients in the room, no need to send stats"); } } /** - * - * @param duration : int Hours + * Send the average ping to user + * @param {number} duration Hours */ static async sendAvgPing(duration, io, monitorID, userID) { const timeLogger = new TimeLogger(); @@ -638,12 +686,18 @@ class Monitor extends BeanModel { io.to(userID).emit("avgPing", monitorID, avgPing); } + /** + * Send certificate information to client + * @param {Server} io Socket server instance + * @param {number} monitorID ID of monitor to send + * @param {number} userID ID of user to send to + */ static async sendCertInfo(io, monitorID, userID) { - let tls_info = await R.findOne("monitor_tls_info", "monitor_id = ?", [ + let tlsInfo = await R.findOne("monitor_tls_info", "monitor_id = ?", [ monitorID, ]); - if (tls_info != null) { - io.to(userID).emit("certInfo", monitorID, tls_info.info_json); + if (tlsInfo != null) { + io.to(userID).emit("certInfo", monitorID, tlsInfo.info_json); } } @@ -651,7 +705,8 @@ class Monitor extends BeanModel { * Uptime with calculation * Calculation based on: * https://www.uptrends.com/support/kb/reporting/calculation-of-uptime-and-downtime - * @param duration : int Hours + * @param {number} duration Hours + * @param {number} monitorID ID of monitor to calculate */ static async calcUptime(duration, monitorID) { const timeLogger = new TimeLogger(); @@ -717,13 +772,23 @@ class Monitor extends BeanModel { /** * Send Uptime - * @param duration : int Hours + * @param {number} duration Hours + * @param {Server} io Socket server instance + * @param {number} monitorID ID of monitor to send + * @param {number} userID ID of user to send to */ static async sendUptime(duration, io, monitorID, userID) { const uptime = await this.calcUptime(duration, monitorID); io.to(userID).emit("uptime", monitorID, duration, uptime); } + /** + * Has status of monitor changed since last beat? + * @param {boolean} isFirstBeat Is this the first beat of this monitor? + * @param {const} previousBeatStatus Status of the previous beat + * @param {const} currentBeatStatus Status of the current beat + * @returns {boolean} True if is an important beat else false + */ static isImportantBeat(isFirstBeat, previousBeatStatus, currentBeatStatus) { // * ? -> ANY STATUS = important [isFirstBeat] // UP -> PENDING = not important @@ -742,6 +807,12 @@ class Monitor extends BeanModel { return isImportant; } + /** + * Send a notification about a monitor + * @param {boolean} isFirstBeat Is this beat the first of this monitor? + * @param {Monitor} monitor The monitor to send a notificaton about + * @param {Bean} bean Status information about monitor + */ static async sendNotification(isFirstBeat, monitor, bean) { if (!isFirstBeat || bean.status === DOWN) { const notificationList = await Monitor.getNotificationList(monitor); @@ -757,15 +828,20 @@ class Monitor extends BeanModel { for (let notification of notificationList) { try { - await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON()); + await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), bean.toJSON()); } catch (e) { - console.error("Cannot send notification to " + notification.name); - console.log(e); + log.error("monitor", "Cannot send notification to " + notification.name); + log.error("monitor", e); } } } } + /** + * Get list of notification providers for a given monitor + * @param {Monitor} monitor Monitor to get notification providers for + * @returns {Promise[]>} + */ static async getNotificationList(monitor) { let notificationList = await R.getAll("SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id ", [ monitor.id, @@ -773,21 +849,33 @@ class Monitor extends BeanModel { return notificationList; } + /** + * Send notification about a certificate + * @param {Object} tlsInfoObject Information about certificate + */ async sendCertNotification(tlsInfoObject) { if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) { const notificationList = await Monitor.getNotificationList(this); - debug("call sendCertNotificationByTargetDays"); + log.debug("monitor", "call sendCertNotificationByTargetDays"); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList); } } + /** + * Send a certificate notification when certificate expires in less + * than target days + * @param {number} daysRemaining Number of days remaining on certifcate + * @param {number} targetDays Number of days to alert after + * @param {LooseObject[]} notificationList List of notification providers + * @returns {Promise} + */ async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) { if (daysRemaining > targetDays) { - debug(`No need to send cert notification. ${daysRemaining} > ${targetDays}`); + log.debug("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`); return; } @@ -801,21 +889,21 @@ class Monitor extends BeanModel { // Sent already, no need to send again if (row) { - debug("Sent already, no need to send again"); + log.debug("monitor", "Sent already, no need to send again"); return; } let sent = false; - debug("Send certificate notification"); + log.debug("monitor", "Send certificate notification"); for (let notification of notificationList) { try { - debug("Sending to " + notification.name); + log.debug("monitor", "Sending to " + notification.name); await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`); sent = true; } catch (e) { - console.error("Cannot send cert notification to " + notification.name); - console.error(e); + log.error("monitor", "Cannot send cert notification to " + notification.name); + log.error("monitor", e); } } @@ -827,10 +915,15 @@ class Monitor extends BeanModel { ]); } } else { - debug("No notification, no need to send cert notification"); + log.debug("monitor", "No notification, no need to send cert notification"); } } + /** + * Get the status of the previous heartbeat + * @param {number} monitorID ID of monitor to check + * @returns {Promise>} + */ static async getPreviousHeartbeat(monitorID) { return await R.getRow(` SELECT status, time FROM heartbeat diff --git a/server/model/proxy.js b/server/model/proxy.js index 7ddec4349..4517b11bf 100644 --- a/server/model/proxy.js +++ b/server/model/proxy.js @@ -1,6 +1,10 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); class Proxy extends BeanModel { + /** + * Return an object that ready to parse to JSON + * @returns {Object} + */ toJSON() { return { id: this._id, diff --git a/server/model/status_page.js b/server/model/status_page.js index 1383d3b00..99b284ab4 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -6,6 +6,7 @@ class StatusPage extends BeanModel { static domainMappingList = { }; /** + * Loads domain mapping from DB * Return object like this: { "test-uptime.kuma.pet": "default" } * @returns {Promise} */ @@ -17,6 +18,12 @@ class StatusPage extends BeanModel { `); } + /** + * Send status page list to client + * @param {Server} io io Socket server instance + * @param {Socket} socket Socket.io instance + * @returns {Promise} + */ static async sendStatusPageList(io, socket) { let result = {}; @@ -30,6 +37,11 @@ class StatusPage extends BeanModel { return list; } + /** + * Update list of domain names + * @param {string[]} domainNameList + * @returns {Promise} + */ async updateDomainNameList(domainNameList) { if (!Array.isArray(domainNameList)) { @@ -69,6 +81,10 @@ class StatusPage extends BeanModel { } } + /** + * Get list of domain names + * @returns {Object[]} + */ getDomainNameList() { let domainList = []; for (let domain in StatusPage.domainMappingList) { @@ -81,6 +97,10 @@ class StatusPage extends BeanModel { return domainList; } + /** + * Return an object that ready to parse to JSON + * @returns {Object} + */ async toJSON() { return { id: this.id, @@ -92,9 +112,17 @@ class StatusPage extends BeanModel { published: !!this.published, showTags: !!this.show_tags, domainNameList: this.getDomainNameList(), + customCSS: this.custom_css, + footerText: this.footer_text, + showPoweredBy: !!this.show_powered_by, }; } + /** + * Return an object that ready to parse to JSON for public + * Only show necessary data to public + * @returns {Object} + */ async toPublicJSON() { return { slug: this.slug, @@ -104,15 +132,26 @@ class StatusPage extends BeanModel { theme: this.theme, published: !!this.published, showTags: !!this.show_tags, + customCSS: this.custom_css, + footerText: this.footer_text, + showPoweredBy: !!this.show_powered_by, }; } + /** + * Convert slug to status page ID + * @param {string} slug + */ static async slugToID(slug) { return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [ slug ]); } + /** + * Get path to the icon for the page + * @returns {string} + */ getIcon() { if (!this.icon) { return "/icon.svg"; diff --git a/server/model/tag.js b/server/model/tag.js index 748280a70..b31eb8682 100644 --- a/server/model/tag.js +++ b/server/model/tag.js @@ -1,6 +1,11 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); class Tag extends BeanModel { + + /** + * Return an object that ready to parse to JSON + * @returns {Object} + */ toJSON() { return { id: this._id, diff --git a/server/model/user.js b/server/model/user.js index d1d3d200d..fc619c74b 100644 --- a/server/model/user.js +++ b/server/model/user.js @@ -3,19 +3,30 @@ const passwordHash = require("../password-hash"); const { R } = require("redbean-node"); class User extends BeanModel { + /** + * Reset user password + * Fix #1510, as in the context reset-password.js, there is no auto model mapping. Call this static function instead. + * @param {number} userID ID of user to update + * @param {string} newPassword + * @returns {Promise} + */ + static async resetPassword(userID, newPassword) { + await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [ + passwordHash.generate(newPassword), + userID + ]); + } /** - * Direct execute, no need R.store() - * @param newPassword + * Reset this users password + * @param {string} newPassword * @returns {Promise} */ async resetPassword(newPassword) { - await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [ - passwordHash.generate(newPassword), - this.id - ]); + await User.resetPassword(this.id, newPassword); this.password = newPassword; } + } module.exports = User; diff --git a/server/modules/apicache/apicache.js b/server/modules/apicache/apicache.js index 25f0a54f5..41930b24d 100644 --- a/server/modules/apicache/apicache.js +++ b/server/modules/apicache/apicache.js @@ -13,27 +13,49 @@ let t = { let instances = []; +/** + * Does a === b + * @param {any} a + * @returns {function(any): boolean} + */ let matches = function (a) { return function (b) { return a === b; }; }; +/** + * Does a!==b + * @param {any} a + * @returns {function(any): boolean} + */ let doesntMatch = function (a) { return function (b) { return !matches(a)(b); }; }; +/** + * Get log duration + * @param {number} d Time in ms + * @param {string} prefix Prefix for log + * @returns {string} Coloured log string + */ let logDuration = function (d, prefix) { let str = d > 1000 ? (d / 1000).toFixed(2) + "sec" : d + "ms"; return "\x1b[33m- " + (prefix ? prefix + " " : "") + str + "\x1b[0m"; }; +/** + * Get safe headers + * @param {Object} res Express response object + * @returns {Object} + */ function getSafeHeaders(res) { return res.getHeaders ? res.getHeaders() : res._headers; } +/** Constructor for ApiCache instance */ function ApiCache() { let memCache = new MemoryCache(); @@ -70,10 +92,10 @@ function ApiCache() { /** * Logs a message to the console if the `DEBUG` environment variable is set. - * @param {string} a - The first argument to log. - * @param {string} b - The second argument to log. - * @param {string} c - The third argument to log. - * @param {string} d - The fourth argument to log, and so on... (optional) + * @param {string} a The first argument to log. + * @param {string} b The second argument to log. + * @param {string} c The third argument to log. + * @param {string} d The fourth argument to log, and so on... (optional) * * Generated by Trelent */ @@ -90,8 +112,8 @@ function ApiCache() { * Returns true if the given request and response should be logged. * @param {Object} request The HTTP request object. * @param {Object} response The HTTP response object. - * - * Generated by Trelent + * @param {function(Object, Object):boolean} toggle + * @returns {boolean} */ function shouldCacheResponse(request, response, toggle) { let opt = globalOptions; @@ -116,10 +138,9 @@ function ApiCache() { } /** - * Adds a key to the index. - * @param {string} key The key to add. - * - * Generated by Trelent + * Add key to index array + * @param {string} key Key to add + * @param {Object} req Express request object */ function addIndexEntries(key, req) { let groupName = req.apicacheGroup; @@ -135,8 +156,11 @@ function ApiCache() { /** * Returns a new object containing only the whitelisted headers. - * @param {Object} headers The original object of header names and values. - * @param {Array.} globalOptions.headerWhitelist An array of strings representing the whitelisted header names to keep in the output object. + * @param {Object} headers The original object of header names and + * values. + * @param {string[]} globalOptions.headerWhitelist An array of + * strings representing the whitelisted header names to keep in the + * output object. * * Generated by Trelent */ @@ -152,8 +176,10 @@ function ApiCache() { } /** + * Create a cache object * @param {Object} headers The response headers to filter. - * @returns {Object} A new object containing only the whitelisted response headers. + * @returns {Object} A new object containing only the whitelisted + * response headers. * * Generated by Trelent */ @@ -170,8 +196,9 @@ function ApiCache() { /** * Sets a cache value for the given key. * @param {string} key The cache key to set. - * @param {*} value The cache value to set. - * @param {number} duration How long in milliseconds the cached response should be valid for (defaults to 1 hour). + * @param {any} value The cache value to set. + * @param {number} duration How long in milliseconds the cached + * response should be valid for (defaults to 1 hour). * * Generated by Trelent */ @@ -199,7 +226,8 @@ function ApiCache() { /** * Appends content to the response. - * @param {string|Buffer} content The content to append. + * @param {Object} res Express response object + * @param {(string|Buffer)} content The content to append. * * Generated by Trelent */ @@ -229,11 +257,15 @@ function ApiCache() { } /** - * Monkeypatches the response object to add cache control headers and create a cache object. - * @param {Object} req - The request object. - * @param {Object} res - The response object. - * - * Generated by Trelent + * Monkeypatches the response object to add cache control headers + * and create a cache object. + * @param {Object} req Express request object + * @param {Object} res Express response object + * @param {function} next Function to call next + * @param {string} key Key to add response as + * @param {number} duration Time to cache response for + * @param {string} strDuration Duration in string form + * @param {function(Object, Object):boolean} toggle */ function makeResponseCacheable(req, res, next, key, duration, strDuration, toggle) { // monkeypatch res.end to create cache object @@ -302,11 +334,15 @@ function ApiCache() { } /** - * @param {Request} request - * @param {Response} response - * @returns {boolean|undefined} true if the request should be cached, false otherwise. If undefined, defaults to true. - * - * Generated by Trelent + * Send a cached response to client + * @param {Request} request Express request object + * @param {Response} response Express response object + * @param {object} cacheObject Cache object to send + * @param {function(Object, Object):boolean} toggle + * @param {function} next Function to call next + * @param {number} duration Not used + * @returns {boolean|undefined} true if the request should be + * cached, false otherwise. If undefined, defaults to true. */ function sendCachedResponse(request, response, cacheObject, toggle, next, duration) { if (toggle && !toggle(request, response)) { @@ -348,12 +384,19 @@ function ApiCache() { return response.end(data, cacheObject.encoding); } + /** Sync caching options */ function syncOptions() { for (let i in middlewareOptions) { Object.assign(middlewareOptions[i].options, globalOptions, middlewareOptions[i].localOptions); } } + /** + * Clear key from cache + * @param {string} target Key to clear + * @param {boolean} isAutomatic Is the key being cleared automatically + * @returns {number} + */ this.clear = function (target, isAutomatic) { let group = index.groups[target]; let redis = globalOptions.redisClient; @@ -430,10 +473,11 @@ function ApiCache() { /** * Converts a duration string to an integer number of milliseconds. - * @param {string} duration - The string to convert. - * @returns {number} The converted value in milliseconds, or the defaultDuration if it can't be parsed. - * - * Generated by Trelent + * @param {(string|number)} duration The string to convert. + * @param {number} defaultDuration The default duration to return if + * can't parse duration + * @returns {number} The converted value in milliseconds, or the + * defaultDuration if it can't be parsed. */ function parseDuration(duration, defaultDuration) { if (typeof duration === "number") { @@ -457,17 +501,24 @@ function ApiCache() { return defaultDuration; } + /** + * Parse duration + * @param {(number|string)} duration + * @returns {number} Duration parsed to a number + */ this.getDuration = function (duration) { return parseDuration(duration, globalOptions.defaultDuration); }; /** - * Return cache performance statistics (hit rate). Suitable for putting into a route: + * Return cache performance statistics (hit rate). Suitable for + * putting into a route: * * app.get('/api/cache/performance', (req, res) => { * res.json(apicache.getPerformance()) * }) * + * @returns {any[]} */ this.getPerformance = function () { return performanceArray.map(function (p) { @@ -475,6 +526,11 @@ function ApiCache() { }); }; + /** + * Get index of a group + * @param {string} group + * @returns {number} + */ this.getIndex = function (group) { if (group) { return index.groups[group]; @@ -483,6 +539,14 @@ function ApiCache() { } }; + /** + * Express middleware + * @param {(string|number)} strDuration Duration to cache responses + * for. + * @param {function(Object, Object):boolean} middlewareToggle + * @param {Object} localOptions Options for APICache + * @returns + */ this.middleware = function cache(strDuration, middlewareToggle, localOptions) { let duration = instance.getDuration(strDuration); let opt = {}; @@ -506,63 +570,72 @@ function ApiCache() { options(localOptions); /** - * A Function for non tracking performance - */ + * A Function for non tracking performance + */ function NOOPCachePerformance() { this.report = this.hit = this.miss = function () {}; // noop; } /** - * A function for tracking and reporting hit rate. These statistics are returned by the getPerformance() call above. - */ + * A function for tracking and reporting hit rate. These + * statistics are returned by the getPerformance() call above. + */ function CachePerformance() { /** - * Tracks the hit rate for the last 100 requests. - * If there have been fewer than 100 requests, the hit rate just considers the requests that have happened. - */ + * Tracks the hit rate for the last 100 requests. If there + * have been fewer than 100 requests, the hit rate just + * considers the requests that have happened. + */ this.hitsLast100 = new Uint8Array(100 / 4); // each hit is 2 bits /** - * Tracks the hit rate for the last 1000 requests. - * If there have been fewer than 1000 requests, the hit rate just considers the requests that have happened. - */ + * Tracks the hit rate for the last 1000 requests. If there + * have been fewer than 1000 requests, the hit rate just + * considers the requests that have happened. + */ this.hitsLast1000 = new Uint8Array(1000 / 4); // each hit is 2 bits /** - * Tracks the hit rate for the last 10000 requests. - * If there have been fewer than 10000 requests, the hit rate just considers the requests that have happened. - */ + * Tracks the hit rate for the last 10000 requests. If there + * have been fewer than 10000 requests, the hit rate just + * considers the requests that have happened. + */ this.hitsLast10000 = new Uint8Array(10000 / 4); // each hit is 2 bits /** - * Tracks the hit rate for the last 100000 requests. - * If there have been fewer than 100000 requests, the hit rate just considers the requests that have happened. - */ + * Tracks the hit rate for the last 100000 requests. If + * there have been fewer than 100000 requests, the hit rate + * just considers the requests that have happened. + */ this.hitsLast100000 = new Uint8Array(100000 / 4); // each hit is 2 bits /** - * The number of calls that have passed through the middleware since the server started. - */ + * The number of calls that have passed through the + * middleware since the server started. + */ this.callCount = 0; /** - * The total number of hits since the server started - */ + * The total number of hits since the server started + */ this.hitCount = 0; /** - * The key from the last cache hit. This is useful in identifying which route these statistics apply to. - */ + * The key from the last cache hit. This is useful in + * identifying which route these statistics apply to. + */ this.lastCacheHit = null; /** - * The key from the last cache miss. This is useful in identifying which route these statistics apply to. - */ + * The key from the last cache miss. This is useful in + * identifying which route these statistics apply to. + */ this.lastCacheMiss = null; /** - * Return performance statistics - */ + * Return performance statistics + * @returns {Object} + */ this.report = function () { return { lastCacheHit: this.lastCacheHit, @@ -579,10 +652,13 @@ function ApiCache() { }; /** - * Computes a cache hit rate from an array of hits and misses. - * @param {Uint8Array} array An array representing hits and misses. - * @returns a number between 0 and 1, or null if the array has no hits or misses - */ + * Computes a cache hit rate from an array of hits and + * misses. + * @param {Uint8Array} array An array representing hits and + * misses. + * @returns {?number} a number between 0 and 1, or null if + * the array has no hits or misses + */ this.hitRate = function (array) { let hits = 0; let misses = 0; @@ -608,16 +684,17 @@ function ApiCache() { }; /** - * Record a hit or miss in the given array. It will be recorded at a position determined - * by the current value of the callCount variable. - * @param {Uint8Array} array An array representing hits and misses. - * @param {boolean} hit true for a hit, false for a miss - * Each element in the array is 8 bits, and encodes 4 hit/miss records. - * Each hit or miss is encoded as to bits as follows: - * 00 means no hit or miss has been recorded in these bits - * 01 encodes a hit - * 10 encodes a miss - */ + * Record a hit or miss in the given array. It will be + * recorded at a position determined by the current value of + * the callCount variable. + * @param {Uint8Array} array An array representing hits and + * misses. + * @param {boolean} hit true for a hit, false for a miss + * Each element in the array is 8 bits, and encodes 4 + * hit/miss records. Each hit or miss is encoded as to bits + * as follows: 00 means no hit or miss has been recorded in + * these bits 01 encodes a hit 10 encodes a miss + */ this.recordHitInArray = function (array, hit) { let arrayIndex = ~~(this.callCount / 4) % array.length; let bitOffset = (this.callCount % 4) * 2; // 2 bits per record, 4 records per uint8 array element @@ -627,9 +704,11 @@ function ApiCache() { }; /** - * Records the hit or miss in the tracking arrays and increments the call count. - * @param {boolean} hit true records a hit, false records a miss - */ + * Records the hit or miss in the tracking arrays and + * increments the call count. + * @param {boolean} hit true records a hit, false records a + * miss + */ this.recordHit = function (hit) { this.recordHitInArray(this.hitsLast100, hit); this.recordHitInArray(this.hitsLast1000, hit); @@ -642,18 +721,18 @@ function ApiCache() { }; /** - * Records a hit event, setting lastCacheMiss to the given key - * @param {string} key The key that had the cache hit - */ + * Records a hit event, setting lastCacheMiss to the given key + * @param {string} key The key that had the cache hit + */ this.hit = function (key) { this.recordHit(true); this.lastCacheHit = key; }; /** - * Records a miss event, setting lastCacheMiss to the given key - * @param {string} key The key that had the cache miss - */ + * Records a miss event, setting lastCacheMiss to the given key + * @param {string} key The key that had the cache miss + */ this.miss = function (key) { this.recordHit(false); this.lastCacheMiss = key; @@ -664,6 +743,13 @@ function ApiCache() { performanceArray.push(perf); + /** + * Cache a request + * @param {Object} req Express request object + * @param {Object} res Express response object + * @param {function} next Function to call next + * @returns {any} + */ let cache = function (req, res, next) { function bypass() { debug("bypass detected, skipping cache."); @@ -771,6 +857,11 @@ function ApiCache() { return cache; }; + /** + * Process options + * @param {Object} options + * @returns {Object} + */ this.options = function (options) { if (options) { Object.assign(globalOptions, options); @@ -791,6 +882,7 @@ function ApiCache() { } }; + /** Reset the index */ this.resetIndex = function () { index = { all: [], @@ -798,6 +890,11 @@ function ApiCache() { }; }; + /** + * Create a new instance of ApiCache + * @param {Object} config Config to pass + * @returns {ApiCache} + */ this.newInstance = function (config) { let instance = new ApiCache(); @@ -808,6 +905,7 @@ function ApiCache() { return instance; }; + /** Clone this instance */ this.clone = function () { return this.newInstance(this.options()); }; diff --git a/server/modules/apicache/memory-cache.js b/server/modules/apicache/memory-cache.js index ad831e2e4..a91eee324 100644 --- a/server/modules/apicache/memory-cache.js +++ b/server/modules/apicache/memory-cache.js @@ -3,6 +3,15 @@ function MemoryCache() { this.size = 0; } +/** + * + * @param {string} key Key to store cache as + * @param {any} value Value to store + * @param {number} time Time to store for + * @param {function(any, string)} timeoutCallback Callback to call in + * case of timeout + * @returns {Object} + */ MemoryCache.prototype.add = function (key, value, time, timeoutCallback) { let old = this.cache[key]; let instance = this; @@ -22,6 +31,11 @@ MemoryCache.prototype.add = function (key, value, time, timeoutCallback) { return entry; }; +/** + * Delete a cache entry + * @param {string} key Key to delete + * @returns {null} + */ MemoryCache.prototype.delete = function (key) { let entry = this.cache[key]; @@ -36,18 +50,32 @@ MemoryCache.prototype.delete = function (key) { return null; }; +/** + * Get value of key + * @param {string} key + * @returns {Object} + */ MemoryCache.prototype.get = function (key) { let entry = this.cache[key]; return entry; }; +/** + * Get value of cache entry + * @param {string} key + * @returns {any} + */ MemoryCache.prototype.getValue = function (key) { let entry = this.get(key); return entry && entry.value; }; +/** + * Clear cache + * @returns {boolean} + */ MemoryCache.prototype.clear = function () { Object.keys(this.cache).forEach(function (key) { this.delete(key); diff --git a/server/notification-providers/alerta.js b/server/notification-providers/alerta.js index bcee80df7..2b85d67a6 100644 --- a/server/notification-providers/alerta.js +++ b/server/notification-providers/alerta.js @@ -40,17 +40,17 @@ class Alerta extends NotificationProvider { await axios.post(alertaUrl, postData, config); } else { let datadup = Object.assign( { - correlate: ["service_up", "service_down"], + correlate: [ "service_up", "service_down" ], event: monitorJSON["type"], group: "uptimekuma-" + monitorJSON["type"], resource: monitorJSON["name"], }, data ); - if (heartbeatJSON["status"] == DOWN) { + if (heartbeatJSON["status"] === DOWN) { datadup.severity = notification.alertaAlertState; // critical datadup.text = "Service " + monitorJSON["type"] + " is down."; await axios.post(alertaUrl, datadup, config); - } else if (heartbeatJSON["status"] == UP) { + } else if (heartbeatJSON["status"] === UP) { datadup.severity = notification.alertaRecoverState; // cleaned datadup.text = "Service " + monitorJSON["type"] + " is up."; await axios.post(alertaUrl, datadup, config); diff --git a/server/notification-providers/aliyun-sms.js b/server/notification-providers/aliyun-sms.js index 6a2063200..fa73ffb1f 100644 --- a/server/notification-providers/aliyun-sms.js +++ b/server/notification-providers/aliyun-sms.js @@ -37,6 +37,12 @@ class AliyunSMS extends NotificationProvider { } } + /** + * Send the SMS notification + * @param {BeanModel} notification Notification details + * @param {string} msgbody Message template + * @returns {boolean} True if successful else false + */ async sendSms(notification, msgbody) { let params = { PhoneNumbers: notification.phonenumber, @@ -64,13 +70,18 @@ class AliyunSMS extends NotificationProvider { }; let result = await axios(config); - if (result.data.Message == "OK") { + if (result.data.Message === "OK") { return true; } return false; } - /** Aliyun request sign */ + /** + * Aliyun request sign + * @param {Object} param Parameters object to sign + * @param {string} AccessKeySecret Secret key to sign parameters with + * @returns {string} + */ sign(param, AccessKeySecret) { let param2 = {}; let data = []; @@ -82,8 +93,23 @@ class AliyunSMS extends NotificationProvider { param2[key] = param[key]; } + // Escape more characters than encodeURIComponent does. + // For generating Aliyun signature, all characters except A-Za-z0-9~-._ are encoded. + // See https://help.aliyun.com/document_detail/315526.html + // This encoding methods as known as RFC 3986 (https://tools.ietf.org/html/rfc3986) + let moreEscapesTable = function (m) { + return { + "!": "%21", + "*": "%2A", + "'": "%27", + "(": "%28", + ")": "%29" + }[m]; + }; + for (let key in param2) { - data.push(`${encodeURIComponent(key)}=${encodeURIComponent(param2[key])}`); + let value = encodeURIComponent(param2[key]).replace(/[!*'()]/g, moreEscapesTable); + data.push(`${encodeURIComponent(key)}=${value}`); } let StringToSign = `POST&${encodeURIComponent("/")}&${encodeURIComponent(data.join("&"))}`; @@ -93,6 +119,11 @@ class AliyunSMS extends NotificationProvider { .digest("base64"); } + /** + * Convert status constant to string + * @param {const} status The status constant + * @returns {string} + */ statusToString(status) { switch (status) { case DOWN: diff --git a/server/notification-providers/apprise.js b/server/notification-providers/apprise.js index fdcd8d61b..887afbf55 100644 --- a/server/notification-providers/apprise.js +++ b/server/notification-providers/apprise.js @@ -1,14 +1,19 @@ const NotificationProvider = require("./notification-provider"); -const child_process = require("child_process"); +const childProcess = require("child_process"); class Apprise extends NotificationProvider { name = "apprise"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL]) + const args = [ "-vv", "-b", msg, notification.appriseURL ]; + if (notification.title) { + args.push("-t"); + args.push(notification.title); + } + const s = childProcess.spawnSync("apprise", args); - let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found"; + const output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found"; if (output) { @@ -16,7 +21,7 @@ class Apprise extends NotificationProvider { return "Sent Successfully"; } - throw new Error(output) + throw new Error(output); } else { return "No output from apprise"; } diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index 4ebe978ad..092511d87 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -21,35 +21,35 @@ class Bark extends NotificationProvider { name = "Bark"; async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - try { - var barkEndpoint = notification.barkEndpoint; + let barkEndpoint = notification.barkEndpoint; - // check if the endpoint has a "/" suffix, if so, delete it first - if (barkEndpoint.endsWith("/")) { - barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1); - } + // check if the endpoint has a "/" suffix, if so, delete it first + if (barkEndpoint.endsWith("/")) { + barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1); + } - if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == UP) { - let title = "UptimeKuma Monitor Up"; - return await this.postNotification(title, msg, barkEndpoint); - } + if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === UP) { + let title = "UptimeKuma Monitor Up"; + return await this.postNotification(title, msg, barkEndpoint); + } - if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) { - let title = "UptimeKuma Monitor Down"; - return await this.postNotification(title, msg, barkEndpoint); - } + if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === DOWN) { + let title = "UptimeKuma Monitor Down"; + return await this.postNotification(title, msg, barkEndpoint); + } - if (msg != null) { - let title = "UptimeKuma Message"; - return await this.postNotification(title, msg, barkEndpoint); - } - - } catch (error) { - throw error; + if (msg != null) { + let title = "UptimeKuma Message"; + return await this.postNotification(title, msg, barkEndpoint); } } - // add additional parameter for better on device styles (iOS 15 optimized) + /** + * Add additional parameter for better on device styles (iOS 15 + * optimized) + * @param {string} postUrl URL to append parameters to + * @returns {string} + */ appendAdditionalParameters(postUrl) { // grouping all our notifications postUrl += "?group=" + barkNotificationGroup; @@ -60,7 +60,11 @@ class Bark extends NotificationProvider { return postUrl; } - // thrown if failed to check result, result code should be in range 2xx + /** + * Check if result is successful + * @param {Object} result Axios response object + * @throws {Error} The status code is not in range 2xx + */ checkResult(result) { if (result.status == null) { throw new Error("Bark notification failed with invalid response!"); @@ -70,6 +74,13 @@ class Bark extends NotificationProvider { } } + /** + * Send the message + * @param {string} title Message title + * @param {string} subtitle Message + * @param {string} endpoint Endpoint to send request to + * @returns {string} + */ async postNotification(title, subtitle, endpoint) { // url encode title and subtitle title = encodeURIComponent(title); diff --git a/server/notification-providers/clicksendsms.js b/server/notification-providers/clicksendsms.js index 74e2f4c59..e66b982c8 100644 --- a/server/notification-providers/clicksendsms.js +++ b/server/notification-providers/clicksendsms.js @@ -12,7 +12,7 @@ class ClickSendSMS extends NotificationProvider { let config = { headers: { "Content-Type": "application/json", - "Authorization": "Basic " + Buffer.from(notification.clicksendsmsLogin + ":" + notification.clicksendsmsPassword).toString('base64'), + "Authorization": "Basic " + Buffer.from(notification.clicksendsmsLogin + ":" + notification.clicksendsmsPassword).toString("base64"), "Accept": "text/json", } }; diff --git a/server/notification-providers/dingding.js b/server/notification-providers/dingding.js index cf08f14bf..59efd053a 100644 --- a/server/notification-providers/dingding.js +++ b/server/notification-providers/dingding.js @@ -37,6 +37,12 @@ class DingDing extends NotificationProvider { } } + /** + * Send message to DingDing + * @param {BeanModel} notification + * @param {Object} params Parameters of message + * @returns {boolean} True if successful else false + */ async sendToDingDing(notification, params) { let timestamp = Date.now(); @@ -50,13 +56,18 @@ class DingDing extends NotificationProvider { }; let result = await axios(config); - if (result.data.errmsg == "ok") { + if (result.data.errmsg === "ok") { return true; } return false; } - /** DingDing sign */ + /** + * DingDing sign + * @param {Date} timestamp Timestamp of message + * @param {string} secretKey Secret key to sign data with + * @returns {string} + */ sign(timestamp, secretKey) { return Crypto .createHmac("sha256", Buffer.from(secretKey, "utf8")) @@ -64,7 +75,13 @@ class DingDing extends NotificationProvider { .digest("base64"); } + /** + * Convert status constant to string + * @param {const} status The status constant + * @returns {string} + */ statusToString(status) { + // TODO: Move to notification-provider.js to avoid repetition in classes switch (status) { case DOWN: return "DOWN"; diff --git a/server/notification-providers/discord.js b/server/notification-providers/discord.js index 881ad2113..77b04d9d3 100644 --- a/server/notification-providers/discord.js +++ b/server/notification-providers/discord.js @@ -17,25 +17,32 @@ class Discord extends NotificationProvider { let discordtestdata = { username: discordDisplayName, content: msg, - } - await axios.post(notification.discordWebhookUrl, discordtestdata) + }; + await axios.post(notification.discordWebhookUrl, discordtestdata); return okMsg; } - let url; + let address; - if (monitorJSON["type"] === "port") { - url = monitorJSON["hostname"]; - if (monitorJSON["port"]) { - url += ":" + monitorJSON["port"]; - } - - } else { - url = monitorJSON["url"]; + switch (monitorJSON["type"]) { + case "ping": + address = monitorJSON["hostname"]; + break; + case "port": + case "dns": + case "steam": + address = monitorJSON["hostname"]; + if (monitorJSON["port"]) { + address += ":" + monitorJSON["port"]; + } + break; + default: + address = monitorJSON["url"]; + break; } // If heartbeatJSON is not null, we go into the normal alerting loop. - if (heartbeatJSON["status"] == DOWN) { + if (heartbeatJSON["status"] === DOWN) { let discorddowndata = { username: discordDisplayName, embeds: [{ @@ -48,8 +55,8 @@ class Discord extends NotificationProvider { value: monitorJSON["name"], }, { - name: "Service URL", - value: url, + name: "Service URL / Address", + value: address, }, { name: "Time (UTC)", @@ -61,16 +68,16 @@ class Discord extends NotificationProvider { }, ], }], - } + }; if (notification.discordPrefixMessage) { discorddowndata.content = notification.discordPrefixMessage; } - await axios.post(notification.discordWebhookUrl, discorddowndata) + await axios.post(notification.discordWebhookUrl, discorddowndata); return okMsg; - } else if (heartbeatJSON["status"] == UP) { + } else if (heartbeatJSON["status"] === UP) { let discordupdata = { username: discordDisplayName, embeds: [{ @@ -84,7 +91,7 @@ class Discord extends NotificationProvider { }, { name: "Service URL", - value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url, + value: address.startsWith("http") ? "[Visit Service](" + address + ")" : address, }, { name: "Time (UTC)", @@ -96,17 +103,17 @@ class Discord extends NotificationProvider { }, ], }], - } + }; if (notification.discordPrefixMessage) { discordupdata.content = notification.discordPrefixMessage; } - await axios.post(notification.discordWebhookUrl, discordupdata) + await axios.post(notification.discordWebhookUrl, discordupdata); return okMsg; } } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/feishu.js b/server/notification-providers/feishu.js index 05fc9c186..73781ca4e 100644 --- a/server/notification-providers/feishu.js +++ b/server/notification-providers/feishu.js @@ -21,7 +21,7 @@ class Feishu extends NotificationProvider { return okMsg; } - if (heartbeatJSON["status"] == DOWN) { + if (heartbeatJSON["status"] === DOWN) { let downdata = { msg_type: "post", content: { @@ -48,7 +48,7 @@ class Feishu extends NotificationProvider { return okMsg; } - if (heartbeatJSON["status"] == UP) { + if (heartbeatJSON["status"] === UP) { let updata = { msg_type: "post", content: { diff --git a/server/notification-providers/google-chat.js b/server/notification-providers/google-chat.js index 6fb324288..02cb4823c 100644 --- a/server/notification-providers/google-chat.js +++ b/server/notification-providers/google-chat.js @@ -13,11 +13,11 @@ class GoogleChat extends NotificationProvider { try { // Google Chat message formatting: https://developers.google.com/chat/api/guides/message-formats/basic - let textMsg = '' + let textMsg = ""; if (heartbeatJSON && heartbeatJSON.status === UP) { - textMsg = `✅ Application is back online\n`; + textMsg = "✅ Application is back online\n"; } else if (heartbeatJSON && heartbeatJSON.status === DOWN) { - textMsg = `🔴 Application went down\n`; + textMsg = "🔴 Application went down\n"; } if (monitorJSON && monitorJSON.name) { diff --git a/server/notification-providers/gorush.js b/server/notification-providers/gorush.js index 58da5525e..6d756e46c 100644 --- a/server/notification-providers/gorush.js +++ b/server/notification-providers/gorush.js @@ -18,7 +18,7 @@ class Gorush extends NotificationProvider { let data = { "notifications": [ { - "tokens": [notification.gorushDeviceToken], + "tokens": [ notification.gorushDeviceToken ], "platform": platformMapping[notification.gorushPlatform], "message": msg, // Optional diff --git a/server/notification-providers/gotify.js b/server/notification-providers/gotify.js index 085261897..0c5244939 100644 --- a/server/notification-providers/gotify.js +++ b/server/notification-providers/gotify.js @@ -15,7 +15,7 @@ class Gotify extends NotificationProvider { "message": msg, "priority": notification.gotifyPriority || 8, "title": "Uptime-Kuma", - }) + }); return okMsg; diff --git a/server/notification-providers/line.js b/server/notification-providers/line.js index 327696edd..e594e1742 100644 --- a/server/notification-providers/line.js +++ b/server/notification-providers/line.js @@ -25,9 +25,9 @@ class Line extends NotificationProvider { "text": "Test Successful!" } ] - } - await axios.post(lineAPIUrl, testMessage, config) - } else if (heartbeatJSON["status"] == DOWN) { + }; + await axios.post(lineAPIUrl, testMessage, config); + } else if (heartbeatJSON["status"] === DOWN) { let downMessage = { "to": notification.lineUserID, "messages": [ @@ -36,9 +36,9 @@ class Line extends NotificationProvider { "text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] } ] - } - await axios.post(lineAPIUrl, downMessage, config) - } else if (heartbeatJSON["status"] == UP) { + }; + await axios.post(lineAPIUrl, downMessage, config); + } else if (heartbeatJSON["status"] === UP) { let upMessage = { "to": notification.lineUserID, "messages": [ @@ -47,12 +47,12 @@ class Line extends NotificationProvider { "text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] } ] - } - await axios.post(lineAPIUrl, upMessage, config) + }; + await axios.post(lineAPIUrl, upMessage, config); } return okMsg; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/lunasea.js b/server/notification-providers/lunasea.js index c41f400e2..b53f32419 100644 --- a/server/notification-providers/lunasea.js +++ b/server/notification-providers/lunasea.js @@ -8,38 +8,38 @@ class LunaSea extends NotificationProvider { async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { let okMsg = "Sent Successfully."; - let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice + let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice; try { if (heartbeatJSON == null) { let testdata = { "title": "Uptime Kuma Alert", "body": "Testing Successful.", - } - await axios.post(lunaseadevice, testdata) + }; + await axios.post(lunaseadevice, testdata); return okMsg; } - if (heartbeatJSON["status"] == DOWN) { + if (heartbeatJSON["status"] === DOWN) { let downdata = { "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(lunaseadevice, downdata) + }; + await axios.post(lunaseadevice, downdata); return okMsg; } - if (heartbeatJSON["status"] == UP) { + if (heartbeatJSON["status"] === UP) { let updata = { "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(lunaseadevice, updata) + }; + await axios.post(lunaseadevice, updata); return okMsg; } } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/matrix.js b/server/notification-providers/matrix.js index c1054fce6..915c772d7 100644 --- a/server/notification-providers/matrix.js +++ b/server/notification-providers/matrix.js @@ -1,7 +1,7 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const Crypto = require("crypto"); -const { debug } = require("../../src/util"); +const { log } = require("../../src/util"); class Matrix extends NotificationProvider { name = "matrix"; @@ -17,11 +17,11 @@ class Matrix extends NotificationProvider { .slice(0, size) ); - debug("Random String: " + randomString); + log.debug("notification", "Random String: " + randomString); const roomId = encodeURIComponent(notification.internalRoomId); - debug("Matrix Room ID: " + roomId); + log.debug("notification", "Matrix Room ID: " + roomId); try { let config = { diff --git a/server/notification-providers/mattermost.js b/server/notification-providers/mattermost.js index fe7b685e1..2076ad213 100644 --- a/server/notification-providers/mattermost.js +++ b/server/notification-providers/mattermost.js @@ -29,7 +29,7 @@ class Mattermost extends NotificationProvider { const mattermostIconEmoji = notification.mattermosticonemo; const mattermostIconUrl = notification.mattermosticonurl; - if (heartbeatJSON["status"] == DOWN) { + if (heartbeatJSON["status"] === DOWN) { let mattermostdowndata = { username: mattermostUserName, text: "Uptime Kuma Alert", @@ -73,7 +73,7 @@ class Mattermost extends NotificationProvider { mattermostdowndata ); return okMsg; - } else if (heartbeatJSON["status"] == UP) { + } else if (heartbeatJSON["status"] === UP) { let mattermostupdata = { username: mattermostUserName, text: "Uptime Kuma Alert", diff --git a/server/notification-providers/notification-provider.js b/server/notification-providers/notification-provider.js index 61c6242d7..2a182d425 100644 --- a/server/notification-providers/notification-provider.js +++ b/server/notification-providers/notification-provider.js @@ -7,17 +7,23 @@ class NotificationProvider { name = undefined; /** - * @param notification : BeanModel - * @param msg : string General Message - * @param monitorJSON : object Monitor details (For Up/Down only) - * @param heartbeatJSON : object Heartbeat details (For Up/Down only) + * Send a notification + * @param {BeanModel} notification + * @param {string} msg General Message + * @param {?Object} monitorJSON Monitor details (For Up/Down only) + * @param {?Object} heartbeatJSON Heartbeat details (For Up/Down only) * @returns {Promise} Return Successful Message - * Throw Error with fail msg + * @throws Error with fail msg */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { throw new Error("Have to override Notification.send(...)"); } + /** + * Throws an error + * @param {any} error The error to throw + * @throws {any} The error specified + */ throwGeneralAxiosError(error) { let msg = "Error: " + error + " "; @@ -25,11 +31,11 @@ class NotificationProvider { if (typeof error.response.data === "string") { msg += error.response.data; } else { - msg += JSON.stringify(error.response.data) + msg += JSON.stringify(error.response.data); } } - throw new Error(msg) + throw new Error(msg); } } diff --git a/server/notification-providers/octopush.js b/server/notification-providers/octopush.js index 9d77aa5b4..0eda940ba 100644 --- a/server/notification-providers/octopush.js +++ b/server/notification-providers/octopush.js @@ -10,7 +10,7 @@ class Octopush extends NotificationProvider { try { // Default - V2 - if (notification.octopushVersion == 2 || !notification.octopushVersion) { + if (notification.octopushVersion === 2 || !notification.octopushVersion) { let config = { headers: { "api-key": notification.octopushAPIKey, @@ -30,14 +30,14 @@ class Octopush extends NotificationProvider { "purpose": "alert", "sender": notification.octopushSenderName }; - await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config) - } else if (notification.octopushVersion == 1) { + await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config); + } else if (notification.octopushVersion === 1) { let data = { "user_login": notification.octopushDMLogin, "api_key": notification.octopushDMAPIKey, "sms_recipients": notification.octopushDMPhoneNumber, "sms_sender": notification.octopushDMSenderName, - "sms_type": (notification.octopushDMSMSType == "sms_premium") ? "FR" : "XXX", + "sms_type": (notification.octopushDMSMSType === "sms_premium") ? "FR" : "XXX", "transactional": "1", //octopush not supporting non ascii char "sms_text": msg.replace(/[^\x00-\x7F]/g, ""), @@ -49,7 +49,7 @@ class Octopush extends NotificationProvider { }, params: data }; - await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config) + await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config); } else { throw new Error("Unknown Octopush version!"); } diff --git a/server/notification-providers/onebot.js b/server/notification-providers/onebot.js new file mode 100644 index 000000000..6c62eccb5 --- /dev/null +++ b/server/notification-providers/onebot.js @@ -0,0 +1,45 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +class OneBot extends NotificationProvider { + + name = "OneBot"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + try { + let httpAddr = notification.httpAddr; + if (!httpAddr.startsWith("http")) { + httpAddr = "http://" + httpAddr; + } + if (!httpAddr.endsWith("/")) { + httpAddr += "/"; + } + let onebotAPIUrl = httpAddr + "send_msg"; + let config = { + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer " + notification.accessToken, + } + }; + let pushText = "UptimeKuma Alert: " + msg; + let data = { + "auto_escape": true, + "message": pushText, + }; + if (notification.msgType === "group") { + data["message_type"] = "group"; + data["group_id"] = notification.recieverId; + } else { + data["message_type"] = "private"; + data["user_id"] = notification.recieverId; + } + await axios.post(onebotAPIUrl, data, config); + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = OneBot; diff --git a/server/notification-providers/promosms.js b/server/notification-providers/promosms.js index 362ef714a..4f7e8f901 100644 --- a/server/notification-providers/promosms.js +++ b/server/notification-providers/promosms.js @@ -12,7 +12,7 @@ class PromoSMS extends NotificationProvider { let config = { headers: { "Content-Type": "application/json", - "Authorization": "Basic " + Buffer.from(notification.promosmsLogin + ":" + notification.promosmsPassword).toString('base64'), + "Authorization": "Basic " + Buffer.from(notification.promosmsLogin + ":" + notification.promosmsPassword).toString("base64"), "Accept": "text/json", } }; @@ -30,7 +30,7 @@ class PromoSMS extends NotificationProvider { let error = "Something gone wrong. Api returned " + resp.data.response.status + "."; this.throwGeneralAxiosError(error); } - + return okMsg; } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/pushbullet.js b/server/notification-providers/pushbullet.js index c7b824a2c..7f7a1c8d0 100644 --- a/server/notification-providers/pushbullet.js +++ b/server/notification-providers/pushbullet.js @@ -23,26 +23,26 @@ class Pushbullet extends NotificationProvider { "type": "note", "title": "Uptime Kuma Alert", "body": "Testing Successful.", - } - await axios.post(pushbulletUrl, testdata, config) - } else if (heartbeatJSON["status"] == DOWN) { + }; + await axios.post(pushbulletUrl, testdata, config); + } else if (heartbeatJSON["status"] === DOWN) { let downdata = { "type": "note", "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(pushbulletUrl, downdata, config) - } else if (heartbeatJSON["status"] == UP) { + }; + await axios.post(pushbulletUrl, downdata, config); + } else if (heartbeatJSON["status"] === UP) { let updata = { "type": "note", "title": "UptimeKuma Alert: " + monitorJSON["name"], "body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"], - } - await axios.post(pushbulletUrl, updata, config) + }; + await axios.post(pushbulletUrl, updata, config); } return okMsg; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/pushdeer.js b/server/notification-providers/pushdeer.js new file mode 100644 index 000000000..bbd83f4bf --- /dev/null +++ b/server/notification-providers/pushdeer.js @@ -0,0 +1,52 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +const { DOWN, UP } = require("../../src/util"); + +class PushDeer extends NotificationProvider { + + name = "PushDeer"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + let pushdeerlink = "https://api2.pushdeer.com/message/push"; + + let valid = msg != null && monitorJSON != null && heartbeatJSON != null; + + let title; + if (valid && heartbeatJSON.status === UP) { + title = "## Uptime Kuma: " + monitorJSON.name + " up"; + } else if (valid && heartbeatJSON.status === DOWN) { + title = "## Uptime Kuma: " + monitorJSON.name + " down"; + } else { + title = "## Uptime Kuma Message"; + } + + let data = { + "pushkey": notification.pushdeerKey, + "text": title, + "desp": msg.replace(/\n/g, "\n\n"), + "type": "markdown", + }; + + try { + let res = await axios.post(pushdeerlink, data); + + if ("error" in res.data) { + let error = res.data.error; + this.throwGeneralAxiosError(error); + } + if (res.data.content.result.length === 0) { + let error = "Invalid PushDeer key"; + this.throwGeneralAxiosError(error); + } else if (JSON.parse(res.data.content.result[0]).success !== "ok") { + let error = "Unknown error"; + this.throwGeneralAxiosError(error); + } + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = PushDeer; diff --git a/server/notification-providers/pushy.js b/server/notification-providers/pushy.js index 2bb899349..1d6e7f32f 100644 --- a/server/notification-providers/pushy.js +++ b/server/notification-providers/pushy.js @@ -19,10 +19,10 @@ class Pushy extends NotificationProvider { "badge": 1, "sound": "ping.aiff" } - }) + }); return okMsg; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/rocket-chat.js b/server/notification-providers/rocket-chat.js index 25b0b945f..fb48ce1a6 100644 --- a/server/notification-providers/rocket-chat.js +++ b/server/notification-providers/rocket-chat.js @@ -2,7 +2,7 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const Slack = require("./slack"); const { setting } = require("../util-server"); -const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util"); +const { getMonitorRelativeURL, DOWN } = require("../../src/util"); class RocketChat extends NotificationProvider { diff --git a/server/notification-providers/signal.js b/server/notification-providers/signal.js index fee65754e..677208ee6 100644 --- a/server/notification-providers/signal.js +++ b/server/notification-providers/signal.js @@ -16,10 +16,10 @@ class Signal extends NotificationProvider { }; let config = {}; - await axios.post(notification.signalURL, data, config) + await axios.post(notification.signalURL, data, config); return okMsg; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/slack.js b/server/notification-providers/slack.js index b4dad6fe3..da1d6e66b 100644 --- a/server/notification-providers/slack.js +++ b/server/notification-providers/slack.js @@ -10,6 +10,7 @@ class Slack extends NotificationProvider { /** * Deprecated property notification.slackbutton * Set it as primary base url if this is not yet set. + * @param {string} url The primary base URL to use */ static async deprecateURL(url) { let currentPrimaryBaseURL = await setting("primaryBaseURL"); diff --git a/server/notification-providers/smtp.js b/server/notification-providers/smtp.js index d85ee88c9..a6a0cc016 100644 --- a/server/notification-providers/smtp.js +++ b/server/notification-providers/smtp.js @@ -1,6 +1,6 @@ const nodemailer = require("nodemailer"); const NotificationProvider = require("./notification-provider"); -const { DOWN, UP } = require("../../src/util"); +const { DOWN } = require("../../src/util"); class SMTP extends NotificationProvider { diff --git a/server/notification-providers/teams.js b/server/notification-providers/teams.js index 859af569c..c398e03c2 100644 --- a/server/notification-providers/teams.js +++ b/server/notification-providers/teams.js @@ -5,6 +5,12 @@ const { DOWN, UP } = require("../../src/util"); class Teams extends NotificationProvider { name = "teams"; + /** + * Generate the message to send + * @param {const} status The status constant + * @param {string} monitorName Name of monitor + * @returns {string} + */ _statusMessageFactory = (status, monitorName) => { if (status === DOWN) { return `🔴 Application [${monitorName}] went down`; @@ -14,6 +20,11 @@ class Teams extends NotificationProvider { return "Notification"; }; + /** + * Select theme color to use based on status + * @param {const} status The status constant + * @returns {string} Selected color in hex RGB format + */ _getThemeColor = (status) => { if (status === DOWN) { return "ff0000"; @@ -24,6 +35,14 @@ class Teams extends NotificationProvider { return "008cff"; }; + /** + * Generate payload for notification + * @param {const} status The status of the monitor + * @param {string} monitorMessage Message to send + * @param {string} monitorName Name of monitor affected + * @param {string} monitorUrl URL of monitor affected + * @returns {Object} + */ _notificationPayloadFactory = ({ status, monitorMessage, @@ -74,10 +93,21 @@ class Teams extends NotificationProvider { }; }; + /** + * Send the notification + * @param {string} webhookUrl URL to send the request to + * @param {Object} payload Payload generated by _notificationPayloadFactory + */ _sendNotification = async (webhookUrl, payload) => { await axios.post(webhookUrl, payload); }; + /** + * Send a general notification + * @param {string} webhookUrl URL to send request to + * @param {string} msg Message to send + * @returns {Promise} + */ _handleGeneralNotification = (webhookUrl, msg) => { const payload = this._notificationPayloadFactory({ monitorMessage: msg diff --git a/server/notification-providers/techulus-push.js b/server/notification-providers/techulus-push.js index f844d17ce..751ff4c3a 100644 --- a/server/notification-providers/techulus-push.js +++ b/server/notification-providers/techulus-push.js @@ -12,10 +12,10 @@ class TechulusPush extends NotificationProvider { await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, { "title": "Uptime-Kuma", "body": msg, - }) + }); return okMsg; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } } diff --git a/server/notification-providers/telegram.js b/server/notification-providers/telegram.js index 54d33bfbd..2b0576224 100644 --- a/server/notification-providers/telegram.js +++ b/server/notification-providers/telegram.js @@ -14,12 +14,12 @@ class Telegram extends NotificationProvider { chat_id: notification.telegramChatID, text: msg, }, - }) + }); return okMsg; } catch (error) { - let msg = (error.response.data.description) ? error.response.data.description : "Error without description" - throw new Error(msg) + let msg = (error.response.data.description) ? error.response.data.description : "Error without description"; + throw new Error(msg); } } } diff --git a/server/notification-providers/webhook.js b/server/notification-providers/webhook.js index 9cb361f30..d4933cf02 100644 --- a/server/notification-providers/webhook.js +++ b/server/notification-providers/webhook.js @@ -24,17 +24,17 @@ class Webhook extends NotificationProvider { config = { headers: finalData.getHeaders(), - } + }; } else { finalData = data; } - await axios.post(notification.webhookURL, finalData, config) + await axios.post(notification.webhookURL, finalData, config); return okMsg; } catch (error) { - this.throwGeneralAxiosError(error) + this.throwGeneralAxiosError(error); } } diff --git a/server/notification-providers/wecom.js b/server/notification-providers/wecom.js index 7ba8c3783..1825419ad 100644 --- a/server/notification-providers/wecom.js +++ b/server/notification-providers/wecom.js @@ -24,12 +24,18 @@ class WeCom extends NotificationProvider { } } + /** + * Generate the message to send + * @param {Object} heartbeatJSON Heartbeat details (For Up/Down only) + * @param {string} msg General message + * @returns {Object} + */ composeMessage(heartbeatJSON, msg) { let title; - if (msg != null && heartbeatJSON != null && heartbeatJSON['status'] == UP) { + if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === UP) { title = "UptimeKuma Monitor Up"; } - if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) { + if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === DOWN) { title = "UptimeKuma Monitor Down"; } if (msg != null) { diff --git a/server/notification.js b/server/notification.js index 35a268640..269e94440 100644 --- a/server/notification.js +++ b/server/notification.js @@ -24,19 +24,23 @@ const Feishu = require("./notification-providers/feishu"); const AliyunSms = require("./notification-providers/aliyun-sms"); const DingDing = require("./notification-providers/dingding"); const Bark = require("./notification-providers/bark"); +const { log } = require("../src/util"); const SerwerSMS = require("./notification-providers/serwersms"); const Stackfield = require("./notification-providers/stackfield"); const WeCom = require("./notification-providers/wecom"); const GoogleChat = require("./notification-providers/google-chat"); const Gorush = require("./notification-providers/gorush"); const Alerta = require("./notification-providers/alerta"); +const OneBot = require("./notification-providers/onebot"); +const PushDeer = require("./notification-providers/pushdeer"); class Notification { providerList = {}; + /** Initialize the notification providers */ static init() { - console.log("Prepare Notification Providers"); + log.info("notification", "Prepare Notification Providers"); this.providerList = {}; @@ -72,6 +76,8 @@ class Notification { new GoogleChat(), new Gorush(), new Alerta(), + new OneBot(), + new PushDeer(), ]; for (let item of list) { @@ -87,13 +93,13 @@ class Notification { } /** - * - * @param notification : BeanModel - * @param msg : string General Message - * @param monitorJSON : object Monitor details (For Up/Down only) - * @param heartbeatJSON : object Heartbeat details (For Up/Down only) + * Send a notification + * @param {BeanModel} notification + * @param {string} msg General Message + * @param {Object} monitorJSON Monitor details (For Up/Down only) + * @param {Object} heartbeatJSON Heartbeat details (For Up/Down only) * @returns {Promise} Successful msg - * Throw Error with fail msg + * @throws Error with fail msg */ static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { if (this.providerList[notification.type]) { @@ -103,28 +109,35 @@ class Notification { } } + /** + * Save a notification + * @param {Object} notification Notification to save + * @param {?number} notificationID ID of notification to update + * @param {number} userID ID of user who adds notification + * @returns {Promise} + */ static async save(notification, notificationID, userID) { - let bean + let bean; if (notificationID) { bean = await R.findOne("notification", " id = ? AND user_id = ? ", [ notificationID, userID, - ]) + ]); if (! bean) { - throw new Error("notification not found") + throw new Error("notification not found"); } } else { - bean = R.dispense("notification") + bean = R.dispense("notification"); } bean.name = notification.name; bean.user_id = userID; bean.config = JSON.stringify(notification); bean.is_default = notification.isDefault || false; - await R.store(bean) + await R.store(bean); if (notification.applyExisting) { await applyNotificationEveryMonitor(bean.id, userID); @@ -133,19 +146,29 @@ class Notification { return bean; } + /** + * Delete a notification + * @param {number} notificationID ID of notification to delete + * @param {number} userID ID of user who created notification + * @returns {Promise} + */ static async delete(notificationID, userID) { let bean = await R.findOne("notification", " id = ? AND user_id = ? ", [ notificationID, userID, - ]) + ]); if (! bean) { - throw new Error("notification not found") + throw new Error("notification not found"); } - await R.trash(bean) + await R.trash(bean); } + /** + * Check if apprise exists + * @returns {boolean} Does the command apprise exist? + */ static checkApprise() { let commandExistsSync = require("command-exists").sync; let exists = commandExistsSync("apprise"); @@ -155,11 +178,10 @@ class Notification { } /** - * Adds a new monitor to the database. - * @param {number} userID The ID of the user that owns this monitor. - * @param {string} name The name of this monitor. - * - * Generated by Trelent + * Apply the notification to every monitor + * @param {number} notificationID ID of notification to apply + * @param {number} userID ID of user who created notification + * @returns {Promise} */ async function applyNotificationEveryMonitor(notificationID, userID) { let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [ @@ -170,17 +192,17 @@ async function applyNotificationEveryMonitor(notificationID, userID) { let checkNotification = await R.findOne("monitor_notification", " monitor_id = ? AND notification_id = ? ", [ monitors[i].id, notificationID, - ]) + ]); if (! checkNotification) { let relation = R.dispense("monitor_notification"); relation.monitor_id = monitors[i].id; relation.notification_id = notificationID; - await R.store(relation) + await R.store(relation); } } } module.exports = { Notification, -} +}; diff --git a/server/password-hash.js b/server/password-hash.js index 91e5e1add..ba228f6b1 100644 --- a/server/password-hash.js +++ b/server/password-hash.js @@ -2,22 +2,42 @@ const passwordHashOld = require("password-hash"); const bcrypt = require("bcryptjs"); const saltRounds = 10; +/** + * Hash a password + * @param {string} password + * @returns {string} + */ exports.generate = function (password) { return bcrypt.hashSync(password, saltRounds); -} +}; +/** + * Verify a password against a hash + * @param {string} password + * @param {string} hash + * @returns {boolean} Does the password match the hash? + */ exports.verify = function (password, hash) { if (isSHA1(hash)) { - return passwordHashOld.verify(password, hash) + return passwordHashOld.verify(password, hash); } return bcrypt.compareSync(password, hash); -} +}; +/** + * Is the hash a SHA1 hash + * @param {string} hash + * @returns {boolean} + */ function isSHA1(hash) { - return (typeof hash === "string" && hash.startsWith("sha1")) + return (typeof hash === "string" && hash.startsWith("sha1")); } +/** + * Does the hash need to be rehashed? + * @returns {boolean} + */ exports.needRehash = function (hash) { return isSHA1(hash); -} +}; diff --git a/server/ping-lite.js b/server/ping-lite.js index 5f15b6d3a..b7d003b81 100644 --- a/server/ping-lite.js +++ b/server/ping-lite.js @@ -9,11 +9,10 @@ const util = require("./util-server"); module.exports = Ping; /** - * @param {string} host - The host to ping - * @param {object} [options] - Options for the ping command + * Constructor for ping class + * @param {string} host Host to ping + * @param {object} [options] Options for the ping command * @param {array|string} [options.args] - Arguments to pass to the ping command - * - * Generated by Trelent */ function Ping(host, options) { if (!host) { @@ -82,8 +81,17 @@ function Ping(host, options) { Ping.prototype.__proto__ = events.EventEmitter.prototype; -// SEND A PING -// =========== +/** + * Callback for send + * @callback pingCB + * @param {any} err Any error encountered + * @param {number} ms Ping time in ms + */ + +/** + * Send a ping + * @param {pingCB} callback Callback to call with results + */ Ping.prototype.send = function (callback) { let self = this; callback = callback || function (err, ms) { @@ -157,8 +165,10 @@ Ping.prototype.send = function (callback) { } }; -// CALL Ping#send(callback) ON A TIMER -// =================================== +/** + * Ping every interval + * @param {pingCB} callback Callback to call with results + */ Ping.prototype.start = function (callback) { let self = this; this._i = setInterval(function () { @@ -167,8 +177,7 @@ Ping.prototype.start = function (callback) { self.send(callback); }; -// STOP SENDING PINGS -// ================== +/** Stop sending pings */ Ping.prototype.stop = function () { clearInterval(this._i); }; @@ -177,7 +186,7 @@ Ping.prototype.stop = function () { * Try to convert to UTF-8 for Windows, as the ping's output on Windows is not UTF-8 and could be in other languages * Thank @pemassi * https://github.com/louislam/uptime-kuma/issues/570#issuecomment-941984094 - * @param data + * @param {any} data * @returns {string} */ function convertOutput(data) { diff --git a/server/prometheus.js b/server/prometheus.js index 86ad381b5..1473ab7a9 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -1,4 +1,5 @@ const PrometheusClient = require("prom-client"); +const { log } = require("../src/util"); const commonLabels = [ "monitor_name", @@ -8,32 +9,35 @@ const commonLabels = [ "monitor_port", ]; -const monitor_cert_days_remaining = new PrometheusClient.Gauge({ +const monitorCertDaysRemaining = new PrometheusClient.Gauge({ name: "monitor_cert_days_remaining", help: "The number of days remaining until the certificate expires", labelNames: commonLabels }); -const monitor_cert_is_valid = new PrometheusClient.Gauge({ +const monitorCertIsValid = new PrometheusClient.Gauge({ name: "monitor_cert_is_valid", help: "Is the certificate still valid? (1 = Yes, 0= No)", labelNames: commonLabels }); -const monitor_response_time = new PrometheusClient.Gauge({ +const monitorResponseTime = new PrometheusClient.Gauge({ name: "monitor_response_time", help: "Monitor Response Time (ms)", labelNames: commonLabels }); -const monitor_status = new PrometheusClient.Gauge({ +const monitorStatus = new PrometheusClient.Gauge({ name: "monitor_status", help: "Monitor Status (1 = UP, 0= DOWN)", labelNames: commonLabels }); class Prometheus { - monitorLabelValues = {} + monitorLabelValues = {}; + /** + * @param {Object} monitor Monitor object to monitor + */ constructor(monitor) { this.monitorLabelValues = { monitor_name: monitor.name, @@ -44,54 +48,63 @@ class Prometheus { }; } + /** + * Update the metrics page + * @param {Object} heartbeat Heartbeat details + * @param {Object} tlsInfo TLS details + */ update(heartbeat, tlsInfo) { if (typeof tlsInfo !== "undefined") { try { - let is_valid = 0; - if (tlsInfo.valid == true) { - is_valid = 1; + let isValid; + if (tlsInfo.valid === true) { + isValid = 1; } else { - is_valid = 0; + isValid = 0; } - monitor_cert_is_valid.set(this.monitorLabelValues, is_valid); + monitorCertIsValid.set(this.monitorLabelValues, isValid); } catch (e) { - console.error(e); + log.error("prometheus", "Caught error"); + log.error("prometheus", e); } try { if (tlsInfo.certInfo != null) { - monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining); + monitorCertDaysRemaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining); } } catch (e) { - console.error(e); + log.error("prometheus", "Caught error"); + log.error("prometheus", e); } } try { - monitor_status.set(this.monitorLabelValues, heartbeat.status); + monitorStatus.set(this.monitorLabelValues, heartbeat.status); } catch (e) { - console.error(e); + log.error("prometheus", "Caught error"); + log.error("prometheus", e); } try { if (typeof heartbeat.ping === "number") { - monitor_response_time.set(this.monitorLabelValues, heartbeat.ping); + monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping); } else { // Is it good? - monitor_response_time.set(this.monitorLabelValues, -1); + monitorResponseTime.set(this.monitorLabelValues, -1); } } catch (e) { - console.error(e); + log.error("prometheus", "Caught error"); + log.error("prometheus", e); } } remove() { try { - monitor_cert_days_remaining.remove(this.monitorLabelValues); - monitor_cert_is_valid.remove(this.monitorLabelValues); - monitor_response_time.remove(this.monitorLabelValues); - monitor_status.remove(this.monitorLabelValues); + monitorCertDaysRemaining.remove(this.monitorLabelValues); + monitorCertIsValid.remove(this.monitorLabelValues); + monitorResponseTime.remove(this.monitorLabelValues); + monitorStatus.remove(this.monitorLabelValues); } catch (e) { console.error(e); } diff --git a/server/proxy.js b/server/proxy.js index af72402d1..22c63b39a 100644 --- a/server/proxy.js +++ b/server/proxy.js @@ -3,11 +3,11 @@ const HttpProxyAgent = require("http-proxy-agent"); const HttpsProxyAgent = require("https-proxy-agent"); const SocksProxyAgent = require("socks-proxy-agent"); const { debug } = require("../src/util"); -const server = require("./server"); +const { UptimeKumaServer } = require("./uptime-kuma-server"); class Proxy { - static SUPPORTED_PROXY_PROTOCOLS = ["http", "https", "socks", "socks5", "socks4"] + static SUPPORTED_PROXY_PROTOCOLS = [ "http", "https", "socks", "socks5", "socks4" ]; /** * Saves and updates given proxy entity @@ -21,7 +21,7 @@ class Proxy { let bean; if (proxyID) { - bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [proxyID, userID]); + bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]); if (!bean) { throw new Error("proxy not found"); @@ -71,14 +71,14 @@ class Proxy { * @return {Promise} */ static async delete(proxyID, userID) { - const bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [proxyID, userID]); + const bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]); if (!bean) { throw new Error("proxy not found"); } // Delete removed proxy from monitors if exists - await R.exec("UPDATE monitor SET proxy_id = null WHERE proxy_id = ?", [proxyID]); + await R.exec("UPDATE monitor SET proxy_id = null WHERE proxy_id = ?", [ proxyID ]); // Delete proxy from list await R.trash(bean); @@ -151,6 +151,8 @@ class Proxy { * @returns {Promise} */ static async reloadProxy() { + const server = UptimeKumaServer.getInstance(); + let updatedList = await R.getAssoc("SELECT id, proxy_id FROM monitor"); for (let monitorID in server.monitorList) { @@ -172,12 +174,12 @@ class Proxy { */ async function applyProxyEveryMonitor(proxyID, userID) { // Find all monitors with id and proxy id - const monitors = await R.getAll("SELECT id, proxy_id FROM monitor WHERE user_id = ?", [userID]); + const monitors = await R.getAll("SELECT id, proxy_id FROM monitor WHERE user_id = ?", [ userID ]); // Update proxy id not match with given proxy id for (const monitor of monitors) { if (monitor.proxy_id !== proxyID) { - await R.exec("UPDATE monitor SET proxy_id = ? WHERE id = ?", [proxyID, monitor.id]); + await R.exec("UPDATE monitor SET proxy_id = ? WHERE id = ?", [ proxyID, monitor.id ]); } } } diff --git a/server/rate-limiter.js b/server/rate-limiter.js index 6422af8d2..6f185beb9 100644 --- a/server/rate-limiter.js +++ b/server/rate-limiter.js @@ -1,15 +1,30 @@ const { RateLimiter } = require("limiter"); -const { debug } = require("../src/util"); +const { log } = require("../src/util"); class KumaRateLimiter { + /** + * @param {Object} config Rate limiter configuration object + */ constructor(config) { this.errorMessage = config.errorMessage; this.rateLimiter = new RateLimiter(config); } + /** + * Callback for pass + * @callback passCB + * @param {Object} err Too many requests + */ + + /** + * Should the request be passed through + * @param {passCB} callback + * @param {number} [num=1] Number of tokens to remove + * @returns {Promise} + */ async pass(callback, num = 1) { const remainingRequests = await this.removeTokens(num); - debug("Rate Limit (remainingRequests):" + remainingRequests); + log.info("rate-limit", "remaining requests: " + remainingRequests); if (remainingRequests < 0) { if (callback) { callback({ @@ -22,6 +37,11 @@ class KumaRateLimiter { return true; } + /** + * Remove a given number of tokens + * @param {number} [num=1] Number of tokens to remove + * @returns {Promise} + */ async removeTokens(num = 1) { return await this.rateLimiter.removeTokens(num); } diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 6f463b6b0..872d6d8cf 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -1,15 +1,19 @@ let express = require("express"); -const { allowDevAllOrigin, getSettings, setting } = require("../util-server"); +const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin } = require("../util-server"); const { R } = require("redbean-node"); -const server = require("../server"); const apicache = require("../modules/apicache"); const Monitor = require("../model/monitor"); const dayjs = require("dayjs"); -const { UP, flipStatus, debug } = require("../../src/util"); +const { UP, DOWN, flipStatus, log } = require("../../src/util"); const StatusPage = require("../model/status_page"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +const { makeBadge } = require("badge-maker"); +const { badgeConstants } = require("../config"); + let router = express.Router(); let cache = apicache.middleware; +const server = UptimeKumaServer.getInstance(); let io = server.io; router.get("/api/entry-page", async (request, response) => { @@ -33,6 +37,8 @@ router.get("/api/push/:pushToken", async (request, response) => { let pushToken = request.params.pushToken; let msg = request.query.msg || "OK"; let ping = request.query.ping || null; + let statusString = request.query.status || "up"; + let status = (statusString === "up") ? UP : DOWN; let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [ pushToken @@ -44,7 +50,6 @@ router.get("/api/push/:pushToken", async (request, response) => { const previousHeartbeat = await Monitor.getPreviousHeartbeat(monitor.id); - let status = UP; if (monitor.isUpsideDown()) { status = flipStatus(status); } @@ -62,8 +67,8 @@ router.get("/api/push/:pushToken", async (request, response) => { duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second"); } - debug("PreviousStatus: " + previousStatus); - debug("Current Status: " + status); + log.debug("router", "PreviousStatus: " + previousStatus); + log.debug("router", "Current Status: " + status); bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status); bean.monitor_id = monitor.id; @@ -124,7 +129,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons // Public Group List const publicGroupList = []; const showTags = !!statusPage.show_tags; - debug("Show Tags???" + showTags); + const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [ statusPage.id ]); @@ -195,14 +200,187 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques } }); -/** - * Default is published - * @returns {Promise} - */ -async function isPublished() { - return true; -} +router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); + const { + label, + upLabel = "Up", + downLabel = "Down", + upColor = badgeConstants.defaultUpColor, + downColor = badgeConstants.defaultDownColor, + style = badgeConstants.defaultStyle, + value, // for demo purpose only + } = request.query; + + try { + const requestedMonitorId = parseInt(request.params.id, 10); + const overrideValue = value !== undefined ? parseInt(value) : undefined; + + let publicMonitor = await R.getRow(` + SELECT monitor_group.monitor_id FROM monitor_group, \`group\` + WHERE monitor_group.group_id = \`group\`.id + AND monitor_group.monitor_id = ? + AND public = 1 + `, + [ requestedMonitorId ] + ); + + const badgeValues = { style }; + + if (!publicMonitor) { + // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant + + badgeValues.message = "N/A"; + badgeValues.color = badgeConstants.naColor; + } else { + const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId); + const state = overrideValue !== undefined ? overrideValue : heartbeat.status === 1; + + badgeValues.color = state ? upColor : downColor; + badgeValues.message = label ?? state ? upLabel : downLabel; + } + + // build the svg based on given values + const svg = makeBadge(badgeValues); + + response.type("image/svg+xml"); + response.send(svg); + } catch (error) { + send403(response, error.message); + } +}); + +router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); + + const { + label, + labelPrefix, + labelSuffix = badgeConstants.defaultUptimeLabelSuffix, + prefix, + suffix = badgeConstants.defaultUptimeValueSuffix, + color, + labelColor, + style = badgeConstants.defaultStyle, + value, // for demo purpose only + } = request.query; + + try { + const requestedMonitorId = parseInt(request.params.id, 10); + // if no duration is given, set value to 24 (h) + const requestedDuration = request.params.duration !== undefined ? parseInt(request.params.duration, 10) : 24; + const overrideValue = value && parseFloat(value); + + let publicMonitor = await R.getRow(` + SELECT monitor_group.monitor_id FROM monitor_group, \`group\` + WHERE monitor_group.group_id = \`group\`.id + AND monitor_group.monitor_id = ? + AND public = 1 + `, + [ requestedMonitorId ] + ); + + const badgeValues = { style }; + + if (!publicMonitor) { + // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant + badgeValues.message = "N/A"; + badgeValues.color = badgeConstants.naColor; + } else { + const uptime = overrideValue ?? await Monitor.calcUptime( + requestedDuration, + requestedMonitorId + ); + + // limit the displayed uptime percentage to four (two, when displayed as percent) decimal digits + const cleanUptime = parseFloat(uptime.toPrecision(4)); + + // use a given, custom color or calculate one based on the uptime value + badgeValues.color = color ?? percentageToColor(uptime); + // use a given, custom labelColor or use the default badge label color (defined by badge-maker) + badgeValues.labelColor = labelColor ?? ""; + // build a lable string. If a custom label is given, override the default one (requestedDuration) + badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]); + badgeValues.message = filterAndJoin([ prefix, `${cleanUptime * 100}`, suffix ]); + } + + // build the SVG based on given values + const svg = makeBadge(badgeValues); + + response.type("image/svg+xml"); + response.send(svg); + } catch (error) { + send403(response, error.message); + } +}); + +router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); + + const { + label, + labelPrefix, + labelSuffix = badgeConstants.defaultPingLabelSuffix, + prefix, + suffix = badgeConstants.defaultPingValueSuffix, + color = badgeConstants.defaultPingColor, + labelColor, + style = badgeConstants.defaultStyle, + value, // for demo purpose only + } = request.query; + + try { + const requestedMonitorId = parseInt(request.params.id, 10); + + // Default duration is 24 (h) if not defined in queryParam, limited to 720h (30d) + const requestedDuration = Math.min(request.params.duration ? parseInt(request.params.duration, 10) : 24, 720); + const overrideValue = value && parseFloat(value); + + const publicAvgPing = parseInt(await R.getCell(` + SELECT AVG(ping) FROM monitor_group, \`group\`, heartbeat + WHERE monitor_group.group_id = \`group\`.id + AND heartbeat.time > DATETIME('now', ? || ' hours') + AND heartbeat.ping IS NOT NULL + AND public = 1 + AND heartbeat.monitor_id = ? + `, + [ -requestedDuration, requestedMonitorId ] + )); + + const badgeValues = { style }; + + if (!publicAvgPing) { + // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant + + badgeValues.message = "N/A"; + badgeValues.color = badgeConstants.naColor; + } else { + const avgPing = parseInt(overrideValue ?? publicAvgPing); + + badgeValues.color = color; + // use a given, custom labelColor or use the default badge label color (defined by badge-maker) + badgeValues.labelColor = labelColor ?? ""; + // build a lable string. If a custom label is given, override the default one (requestedDuration) + badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]); + badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]); + } + + // build the SVG based on given values + const svg = makeBadge(badgeValues); + + response.type("image/svg+xml"); + response.send(svg); + } catch (error) { + send403(response, error.message); + } +}); + +/** + * Send a 403 response + * @param {Object} res Express response object + * @param {string} [msg=""] Message to send + */ function send403(res, msg = "") { res.status(403).json({ "status": "fail", diff --git a/server/server.js b/server/server.js index 4323566a3..ff6d07c47 100644 --- a/server/server.js +++ b/server/server.js @@ -1,3 +1,8 @@ +/* + * Uptime Kuma Server + * node "server/server.js" + * DO NOT require("./server") in other modules, it likely creates circular dependency! + */ console.log("Welcome to Uptime Kuma"); // Check Node.js Version @@ -11,81 +16,63 @@ if (nodeVersion < requiredVersion) { } const args = require("args-parser")(process.argv); -const { sleep, debug, getRandomInt, genSecret } = require("../src/util"); +const { sleep, log, getRandomInt, genSecret, debug, isDev } = require("../src/util"); const config = require("./config"); -debug(args); +log.info("server", "Welcome to Uptime Kuma"); +log.debug("server", "Arguments"); +log.debug("server", args); if (! process.env.NODE_ENV) { process.env.NODE_ENV = "production"; } -console.log("Node Env: " + process.env.NODE_ENV); +log.info("server", "Node Env: " + process.env.NODE_ENV); -console.log("Importing Node libraries"); +log.info("server", "Importing Node libraries"); const fs = require("fs"); -const http = require("http"); -const https = require("https"); -console.log("Importing 3rd-party libraries"); -debug("Importing express"); +log.info("server", "Importing 3rd-party libraries"); +log.debug("server", "Importing express"); const express = require("express"); -debug("Importing socket.io"); -const { Server } = require("socket.io"); -debug("Importing redbean-node"); +log.debug("server", "Importing redbean-node"); const { R } = require("redbean-node"); -debug("Importing jsonwebtoken"); +log.debug("server", "Importing jsonwebtoken"); const jwt = require("jsonwebtoken"); -debug("Importing http-graceful-shutdown"); +log.debug("server", "Importing http-graceful-shutdown"); const gracefulShutdown = require("http-graceful-shutdown"); -debug("Importing prometheus-api-metrics"); +log.debug("server", "Importing prometheus-api-metrics"); const prometheusAPIMetrics = require("prometheus-api-metrics"); -debug("Importing compare-versions"); +log.debug("server", "Importing compare-versions"); const compareVersions = require("compare-versions"); const { passwordStrength } = require("check-password-strength"); -debug("Importing 2FA Modules"); +log.debug("server", "Importing 2FA Modules"); const notp = require("notp"); const base32 = require("thirty-two"); -/** - * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. - * @type {UptimeKumaServer} - */ -class UptimeKumaServer { - /** - * Main monitor list - * @type {{}} - */ - monitorList = {}; - entryPage = "dashboard"; +const { UptimeKumaServer } = require("./uptime-kuma-server"); +const server = UptimeKumaServer.getInstance(args); +const io = module.exports.io = server.io; +const app = server.app; - async sendMonitorList(socket) { - let list = await getMonitorJSONList(socket.userID); - io.to(socket.userID).emit("monitorList", list); - return list; - } -} - -const server = module.exports = new UptimeKumaServer(); - -console.log("Importing this project modules"); -debug("Importing Monitor"); +log.info("server", "Importing this project modules"); +log.debug("server", "Importing Monitor"); const Monitor = require("./model/monitor"); -debug("Importing Settings"); -const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog, doubleCheckPassword } = require("./util-server"); +log.debug("server", "Importing Settings"); +const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, doubleCheckPassword } = require("./util-server"); -debug("Importing Notification"); +log.debug("server", "Importing Notification"); const { Notification } = require("./notification"); Notification.init(); -debug("Importing Proxy"); +log.debug("server", "Importing Proxy"); const { Proxy } = require("./proxy"); -debug("Importing Database"); +log.debug("server", "Importing Database"); const Database = require("./database"); -debug("Importing Background Jobs"); +log.debug("server", "Importing Background Jobs"); const { initBackgroundJobs, stopBackgroundJobs } = require("./jobs"); const { loginRateLimiter, twoFaRateLimiter } = require("./rate-limiter"); @@ -94,7 +81,7 @@ const { login } = require("./auth"); const passwordHash = require("./password-hash"); const checkVersion = require("./check-version"); -console.info("Version: " + checkVersion.version); +log.info("server", "Version: " + checkVersion.version); // If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise. // Dual-stack support for (::) @@ -103,21 +90,18 @@ let hostEnv = FBSD ? null : process.env.HOST; let hostname = args.host || process.env.UPTIME_KUMA_HOST || hostEnv; if (hostname) { - console.log("Custom hostname: " + hostname); + log.info("server", "Custom hostname: " + hostname); } -const port = [args.port, process.env.UPTIME_KUMA_PORT, process.env.PORT, 3001] +const port = [ args.port, process.env.UPTIME_KUMA_PORT, process.env.PORT, 3001 ] .map(portValue => parseInt(portValue)) .find(portValue => !isNaN(portValue)); -// SSL -const sslKey = args["ssl-key"] || process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined; -const sslCert = args["ssl-cert"] || process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined; -const disableFrameSameOrigin = args["disable-frame-sameorigin"] || !!process.env.UPTIME_KUMA_DISABLE_FRAME_SAMEORIGIN || false; +const disableFrameSameOrigin = !!process.env.UPTIME_KUMA_DISABLE_FRAME_SAMEORIGIN || args["disable-frame-sameorigin"] || false; const cloudflaredToken = args["cloudflared-token"] || process.env.UPTIME_KUMA_CLOUDFLARED_TOKEN || undefined; // 2FA / notp verification defaults -const twofa_verification_opts = { +const twoFAVerifyOptions = { "window": 1, "time": 30 }; @@ -129,28 +113,9 @@ const twofa_verification_opts = { const testMode = !!args["test"] || false; if (config.demoMode) { - console.log("==== Demo Mode ===="); + log.info("server", "==== Demo Mode ===="); } -console.log("Creating express and socket.io instance"); -const app = express(); - -let httpServer; - -if (sslKey && sslCert) { - console.log("Server Type: HTTPS"); - httpServer = https.createServer({ - key: fs.readFileSync(sslKey), - cert: fs.readFileSync(sslCert) - }, app); -} else { - console.log("Server Type: HTTP"); - httpServer = http.createServer(app); -} - -const io = new Server(httpServer); -module.exports.io = io; - // Must be after io instantiation const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo, sendProxyList } = require("./client"); const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler"); @@ -171,12 +136,6 @@ app.use(function (req, res, next) { next(); }); -/** - * Total WebSocket client connected to server currently, no actual use - * @type {number} - */ -let totalClient = 0; - /** * Use for decode the auth object * @type {null} @@ -200,7 +159,7 @@ try { } catch (e) { // "dist/index.html" is not necessary for development if (process.env.NODE_ENV !== "development") { - console.error("Error: Cannot find 'dist/index.html', did you install correctly?"); + log.error("server", "Error: Cannot find 'dist/index.html', did you install correctly?"); process.exit(1); } } @@ -212,7 +171,7 @@ try { exports.entryPage = await setting("entryPage"); await StatusPage.loadDomainMappingList(); - console.log("Adding route"); + log.info("server", "Adding route"); // *************************** // Normal Router here @@ -232,6 +191,13 @@ try { } }); + if (isDev) { + app.post("/test-webhook", async (request, response) => { + log.debug("test", request.body); + response.send("OK"); + }); + } + // Robots.txt app.get("/robots.txt", async (_request, response) => { let txt = "User-agent: *\nDisallow:"; @@ -270,54 +236,55 @@ try { } }); - console.log("Adding socket handler"); + log.info("server", "Adding socket handler"); io.on("connection", async (socket) => { sendInfo(socket); - totalClient++; - if (needSetup) { - console.log("Redirect to setup page"); + log.info("server", "Redirect to setup page"); socket.emit("setup"); } - socket.on("disconnect", () => { - totalClient--; - }); - // *************************** // Public Socket API // *************************** socket.on("loginByToken", async (token, callback) => { + log.info("auth", `Login by token. IP=${getClientIp(socket)}`); try { let decoded = jwt.verify(token, jwtSecret); - console.log("Username from JWT: " + decoded.username); + log.info("auth", "Username from JWT: " + decoded.username); let user = await R.findOne("user", " username = ? AND active = 1 ", [ decoded.username, ]); if (user) { - debug("afterLogin"); - + log.debug("auth", "afterLogin"); afterLogin(socket, user); + log.debug("auth", "afterLogin ok"); - debug("afterLogin ok"); + log.info("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`); callback({ ok: true, }); } else { + + log.info("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: "The user is inactive or deleted.", }); } } catch (error) { + + log.error("auth", `Invalid token. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: "Invalid token.", @@ -327,7 +294,7 @@ try { }); socket.on("login", async (data, callback) => { - console.log("Login"); + log.info("auth", `Login by username + password. IP=${getClientIp(socket)}`); // Checking if (typeof callback !== "function") { @@ -340,14 +307,18 @@ try { // Login Rate Limit if (! await loginRateLimiter.pass(callback)) { + log.info("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`); return; } let user = await login(data.username, data.password); if (user) { - if (user.twofa_status == 0) { + if (user.twofa_status === 0) { afterLogin(socket, user); + + log.info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: true, token: jwt.sign({ @@ -356,14 +327,17 @@ try { }); } - if (user.twofa_status == 1 && !data.token) { + if (user.twofa_status === 1 && !data.token) { + + log.info("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`); + callback({ tokenRequired: true, }); } if (data.token) { - let verify = notp.totp.verify(data.token, user.twofa_secret, twofa_verification_opts); + let verify = notp.totp.verify(data.token, user.twofa_secret, twoFAVerifyOptions); if (user.twofa_last_token !== data.token && verify) { afterLogin(socket, user); @@ -373,6 +347,8 @@ try { socket.userID, ]); + log.info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: true, token: jwt.sign({ @@ -380,6 +356,9 @@ try { }, jwtSecret), }); } else { + + log.warn("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: "Invalid Token!", @@ -387,6 +366,9 @@ try { } } } else { + + log.warn("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: "Incorrect username or password.", @@ -422,7 +404,7 @@ try { socket.userID, ]); - if (user.twofa_status == 0) { + if (user.twofa_status === 0) { let newSecret = genSecret(); let encodedSecret = base32.encode(newSecret); @@ -469,11 +451,16 @@ try { socket.userID, ]); + log.info("auth", `Saved 2FA token. IP=${getClientIp(socket)}`); + callback({ ok: true, msg: "2FA Enabled.", }); } catch (error) { + + log.error("auth", `Error changing 2FA token. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: error.message, @@ -491,11 +478,16 @@ try { await doubleCheckPassword(socket, currentPassword); await TwoFA.disable2FA(socket.userID); + log.info("auth", `Disabled 2FA token. IP=${getClientIp(socket)}`); + callback({ ok: true, msg: "2FA Disabled.", }); } catch (error) { + + log.error("auth", `Error disabling 2FA token. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: error.message, @@ -512,7 +504,7 @@ try { socket.userID, ]); - let verify = notp.totp.verify(token, user.twofa_secret, twofa_verification_opts); + let verify = notp.totp.verify(token, user.twofa_secret, twoFAVerifyOptions); if (user.twofa_last_token !== token && verify) { callback({ @@ -543,7 +535,7 @@ try { socket.userID, ]); - if (user.twofa_status == 1) { + if (user.twofa_status === 1) { callback({ ok: true, status: true, @@ -622,6 +614,8 @@ try { await server.sendMonitorList(socket); await startMonitor(socket.userID, bean.id); + log.info("monitor", `Added Monitor: ${monitor.id} User ID: ${socket.userID}`); + callback({ ok: true, msg: "Added Successfully.", @@ -629,6 +623,9 @@ try { }); } catch (e) { + + log.error("monitor", `Error adding Monitor: ${monitor.id} User ID: ${socket.userID}`); + callback({ ok: false, msg: e.message, @@ -676,6 +673,10 @@ try { bean.docker_daemon = monitor.docker_daemon; bean.docker_type = monitor.docker_type; bean.proxyId = Number.isInteger(monitor.proxyId) ? monitor.proxyId : null; + bean.mqttUsername = monitor.mqttUsername; + bean.mqttPassword = monitor.mqttPassword; + bean.mqttTopic = monitor.mqttTopic; + bean.mqttSuccessMessage = monitor.mqttSuccessMessage; await R.store(bean); @@ -694,7 +695,7 @@ try { }); } catch (e) { - console.error(e); + log.error("monitor", e); callback({ ok: false, msg: e.message, @@ -710,7 +711,7 @@ try { ok: true, }); } catch (e) { - console.error(e); + log.error("monitor", e); callback({ ok: false, msg: e.message, @@ -722,7 +723,7 @@ try { try { checkLogin(socket); - console.log(`Get Monitor: ${monitorID} User ID: ${socket.userID}`); + log.info("monitor", `Get Monitor: ${monitorID} User ID: ${socket.userID}`); let bean = await R.findOne("monitor", " id = ? AND user_id = ? ", [ monitorID, @@ -746,7 +747,7 @@ try { try { checkLogin(socket); - console.log(`Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); + log.info("monitor", `Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); if (period == null) { throw new Error("Invalid period."); @@ -817,7 +818,7 @@ try { try { checkLogin(socket); - console.log(`Delete Monitor: ${monitorID} User ID: ${socket.userID}`); + log.info("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`); if (monitorID in server.monitorList) { server.monitorList[monitorID].stop(); @@ -1049,7 +1050,13 @@ try { try { checkLogin(socket); - if (data.disableAuth) { + // If currently is disabled auth, don't need to check + // Disabled Auth + Want to Disable Auth => No Check + // Disabled Auth + Want to Enable Auth => No Check + // Enabled Auth + Want to Disable Auth => Check!! + // Enabled Auth + Want to Enable Auth => No Check + const currentDisabledAuth = await setting("disableAuth"); + if (!currentDisabledAuth && data.disableAuth) { await doubleCheckPassword(socket, currentPassword); } @@ -1149,7 +1156,7 @@ try { let backupData = JSON.parse(uploadedJSON); - console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`); + log.info("manage", `Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`); let notificationListData = backupData.notificationList; let proxyListData = backupData.proxyList; @@ -1158,7 +1165,7 @@ try { let version17x = compareVersions.compare(backupData.version, "1.7.0", ">="); // If the import option is "overwrite" it'll clear most of the tables, except "settings" and "user" - if (importHandle == "overwrite") { + if (importHandle === "overwrite") { // Stops every monitor first, so it doesn't execute any heartbeat while importing for (let id in server.monitorList) { let monitor = server.monitorList[id]; @@ -1182,7 +1189,7 @@ try { for (let i = 0; i < notificationListData.length; i++) { // Only starts importing the notification if the import option is "overwrite", "keep" or "skip" but the notification doesn't exists - if ((importHandle == "skip" && notificationNameListString.includes(notificationListData[i].name) == false) || importHandle == "keep" || importHandle == "overwrite") { + if ((importHandle === "skip" && notificationNameListString.includes(notificationListData[i].name) === false) || importHandle === "keep" || importHandle === "overwrite") { let notification = JSON.parse(notificationListData[i].config); await Notification.save(notification, null, socket.userID); @@ -1192,7 +1199,7 @@ try { } // Only starts importing if the backup file contains at least one proxy - if (proxyListData.length >= 1) { + if (proxyListData && proxyListData.length >= 1) { const proxies = await R.findAll("proxy"); // Loop over proxy list and save proxies @@ -1200,7 +1207,7 @@ try { const exists = proxies.find(item => item.id === proxy.id); // Do not process when proxy already exists in import handle is skip and keep - if (["skip", "keep"].includes(importHandle) && !exists) { + if ([ "skip", "keep" ].includes(importHandle) && !exists) { return; } @@ -1217,7 +1224,7 @@ try { for (let i = 0; i < monitorListData.length; i++) { // Only starts importing the monitor if the import option is "overwrite", "keep" or "skip" but the notification doesn't exists - if ((importHandle == "skip" && monitorNameListString.includes(monitorListData[i].name) == false) || importHandle == "keep" || importHandle == "overwrite") { + if ((importHandle === "skip" && monitorNameListString.includes(monitorListData[i].name) === false) || importHandle === "keep" || importHandle === "overwrite") { // Define in here every new variable for monitors which where implemented after the first version of the Import/Export function (1.6.0) // --- Start --- @@ -1314,7 +1321,7 @@ try { await updateMonitorNotification(bean.id, notificationIDList); // If monitor was active start it immediately, otherwise pause it - if (monitorListData[i].active == 1) { + if (monitorListData[i].active === 1) { await startMonitor(socket.userID, bean.id); } else { await pauseMonitor(socket.userID, bean.id); @@ -1344,7 +1351,7 @@ try { try { checkLogin(socket); - console.log(`Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`); + log.info("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`); await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", [ "", @@ -1370,7 +1377,7 @@ try { try { checkLogin(socket); - console.log(`Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`); + log.info("manage", `Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`); await R.exec("DELETE FROM heartbeat WHERE monitor_id = ?", [ monitorID @@ -1394,7 +1401,7 @@ try { try { checkLogin(socket); - console.log(`Clear Statistics User ID: ${socket.userID}`); + log.info("manage", `Clear Statistics User ID: ${socket.userID}`); await R.exec("DELETE FROM heartbeat"); @@ -1416,35 +1423,35 @@ try { databaseSocketHandler(socket); proxySocketHandler(socket); - debug("added all socket handlers"); + log.debug("server", "added all socket handlers"); // *************************** // Better do anything after added all socket handlers here // *************************** - debug("check auto login"); + log.debug("auth", "check auto login"); if (await setting("disableAuth")) { - console.log("Disabled Auth: auto login to admin"); + log.info("auth", "Disabled Auth: auto login to admin"); afterLogin(socket, await R.findOne("user")); socket.emit("autoLogin"); } else { - debug("need auth"); + log.debug("auth", "need auth"); } }); - console.log("Init the server"); + log.info("server", "Init the server"); - httpServer.once("error", async (err) => { + server.httpServer.once("error", async (err) => { console.error("Cannot listen: " + err.message); await shutdownFunction(); }); - httpServer.listen(port, hostname, () => { + server.httpServer.listen(port, hostname, () => { if (hostname) { - console.log(`Listening on ${hostname}:${port}`); + log.info("server", `Listening on ${hostname}:${port}`); } else { - console.log(`Listening on ${port}`); + log.info("server", `Listening on ${port}`); } startMonitors(); checkVersion.startInterval(); @@ -1462,11 +1469,11 @@ try { })(); /** - * Adds or removes notifications from a monitor. - * @param {number} monitorID The ID of the monitor to add/remove notifications from. - * @param {Array.} notificationIDList An array of IDs for the notifications to add/remove. - * - * Generated by Trelent + * Update notifications for a given monitor + * @param {number} monitorID ID of monitor to update + * @param {number[]} notificationIDList List of new notification + * providers to add + * @returns {Promise} */ async function updateMonitorNotification(monitorID, notificationIDList) { await R.exec("DELETE FROM monitor_notification WHERE monitor_id = ? ", [ @@ -1484,11 +1491,11 @@ async function updateMonitorNotification(monitorID, notificationIDList) { } /** - * This function checks if the user owns a monitor with the given ID. - * @param {number} monitorID - The ID of the monitor to check ownership for. - * @param {number} userID - The ID of the user who is trying to access this data. - * - * Generated by Trelent + * Check if a given user owns a specific monitor + * @param {number} userID + * @param {number} monitorID + * @returns {Promise} + * @throws {Error} The specified user does not own the monitor */ async function checkOwner(userID, monitorID) { let row = await R.getRow("SELECT id FROM monitor WHERE id = ? AND user_id = ? ", [ @@ -1502,8 +1509,11 @@ async function checkOwner(userID, monitorID) { } /** + * Function called after user login * This function is used to send the heartbeat list of a monitor. - * @param {Socket} socket - The socket object that will be used to send the data. + * @param {Socket} socket Socket.io instance + * @param {Object} user User object + * @returns {Promise} */ async function afterLogin(socket, user) { socket.userID = user.id; @@ -1531,40 +1541,20 @@ async function afterLogin(socket, user) { } /** - * Get a list of monitors for the given user. - * @param {string} userID - The ID of the user to get monitors for. - * @returns {Promise} A promise that resolves to an object with monitor IDs as keys and monitor objects as values. - * - * Generated by Trelent - */ -async function getMonitorJSONList(userID) { - let result = {}; - - let monitorList = await R.find("monitor", " user_id = ? ORDER BY weight DESC, name", [ - userID, - ]); - - for (let monitor of monitorList) { - result[monitor.id] = await monitor.toJSON(); - } - - return result; -} - -/** - * Connect to the database and patch it if necessary. - * - * Generated by Trelent + * Initialize the database + * @param {boolean} [testMode=false] Should the connection be + * started in test mode? + * @returns {Promise} */ async function initDatabase(testMode = false) { if (! fs.existsSync(Database.path)) { - console.log("Copying Database"); + log.info("server", "Copying Database"); fs.copyFileSync(Database.templatePath, Database.path); } - console.log("Connecting to the Database"); + log.info("server", "Connecting to the Database"); await Database.connect(testMode); - console.log("Connected"); + log.info("server", "Connected"); // Patch the database await Database.patch(); @@ -1574,16 +1564,16 @@ async function initDatabase(testMode = false) { ]); if (! jwtSecretBean) { - console.log("JWT secret is not found, generate one."); + log.info("server", "JWT secret is not found, generate one."); jwtSecretBean = await initJWTSecret(); - console.log("Stored JWT secret into database"); + log.info("server", "Stored JWT secret into database"); } else { - console.log("Load JWT secret from database."); + log.info("server", "Load JWT secret from database."); } // If there is no record in user table, it is a new Uptime Kuma instance, need to setup if ((await R.count("user")) === 0) { - console.log("No user, need setup"); + log.info("server", "No user, need setup"); needSetup = true; } @@ -1591,16 +1581,15 @@ async function initDatabase(testMode = false) { } /** - * Resume a monitor. - * @param {string} userID - The ID of the user who owns the monitor. - * @param {string} monitorID - The ID of the monitor to resume. - * - * Generated by Trelent + * Start the specified monitor + * @param {number} userID ID of user who owns monitor + * @param {number} monitorID ID of monitor to start + * @returns {Promise} */ async function startMonitor(userID, monitorID) { await checkOwner(userID, monitorID); - console.log(`Resume Monitor: ${monitorID} User ID: ${userID}`); + log.info("manage", `Resume Monitor: ${monitorID} User ID: ${userID}`); await R.exec("UPDATE monitor SET active = 1 WHERE id = ? AND user_id = ? ", [ monitorID, @@ -1619,21 +1608,26 @@ async function startMonitor(userID, monitorID) { monitor.start(io); } +/** + * Restart a given monitor + * @param {number} userID ID of user who owns monitor + * @param {number} monitorID ID of monitor to start + * @returns {Promise} + */ async function restartMonitor(userID, monitorID) { return await startMonitor(userID, monitorID); } /** - * Pause a monitor. - * @param {string} userID - The ID of the user who owns the monitor. - * @param {string} monitorID - The ID of the monitor to pause. - * - * Generated by Trelent + * Pause a given monitor + * @param {number} userID ID of user who owns monitor + * @param {number} monitorID ID of monitor to start + * @returns {Promise} */ async function pauseMonitor(userID, monitorID) { await checkOwner(userID, monitorID); - console.log(`Pause Monitor: ${monitorID} User ID: ${userID}`); + log.info("manage", `Pause Monitor: ${monitorID} User ID: ${userID}`); await R.exec("UPDATE monitor SET active = 0 WHERE id = ? AND user_id = ? ", [ monitorID, @@ -1645,9 +1639,7 @@ async function pauseMonitor(userID, monitorID) { } } -/** - * Resume active monitors - */ +/** Resume active monitors */ async function startMonitors() { let list = await R.find("monitor", " active = 1 "); @@ -1663,16 +1655,16 @@ async function startMonitors() { } /** + * Shutdown the application * Stops all monitors and closes the database connection. * @param {string} signal The signal that triggered this function to be called. - * - * Generated by Trelent + * @returns {Promise} */ async function shutdownFunction(signal) { - console.log("Shutdown requested"); - console.log("Called signal: " + signal); + log.info("server", "Shutdown requested"); + log.info("server", "Called signal: " + signal); - console.log("Stopping all monitors"); + log.info("server", "Stopping all monitors"); for (let id in server.monitorList) { let monitor = server.monitorList[id]; monitor.stop(); @@ -1684,11 +1676,16 @@ async function shutdownFunction(signal) { await cloudflaredStop(); } -function finalFunction() { - console.log("Graceful shutdown successful!"); +function getClientIp(socket) { + return socket.client.conn.remoteAddress.replace(/^.*:/, ""); } -gracefulShutdown(httpServer, { +/** Final function called before application exits */ +function finalFunction() { + log.info("server", "Graceful shutdown successful!"); +} + +gracefulShutdown(server.httpServer, { signals: "SIGINT SIGTERM", timeout: 30000, // timeout: 30 secs development: false, // not in dev mode @@ -1700,6 +1697,6 @@ gracefulShutdown(httpServer, { // Catch unexpected errors here process.addListener("unhandledRejection", (error, promise) => { console.trace(error); - errorLog(error, false); + UptimeKumaServer.errorLog(error, false); console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues"); }); diff --git a/server/socket-handlers/cloudflared-socket-handler.js b/server/socket-handlers/cloudflared-socket-handler.js index 37c12256d..4c34f52f5 100644 --- a/server/socket-handlers/cloudflared-socket-handler.js +++ b/server/socket-handlers/cloudflared-socket-handler.js @@ -1,19 +1,33 @@ const { checkLogin, setSetting, setting, doubleCheckPassword } = require("../util-server"); const { CloudflaredTunnel } = require("node-cloudflared-tunnel"); -const { io } = require("../server"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +const io = UptimeKumaServer.getInstance().io; const prefix = "cloudflared_"; const cloudflared = new CloudflaredTunnel(); +/** + * Change running state + * @param {string} running Is it running? + * @param {string} message Message to pass + */ cloudflared.change = (running, message) => { io.to("cloudflared").emit(prefix + "running", running); io.to("cloudflared").emit(prefix + "message", message); }; +/** + * Emit an error message + * @param {string} errorMessage + */ cloudflared.error = (errorMessage) => { io.to("cloudflared").emit(prefix + "errorMessage", errorMessage); }; +/** + * Handler for cloudflared + * @param {Socket} socket Socket.io instance + */ module.exports.cloudflaredSocketHandler = (socket) => { socket.on(prefix + "join", async () => { @@ -68,6 +82,10 @@ module.exports.cloudflaredSocketHandler = (socket) => { }; +/** + * Automatically start cloudflared + * @param {string} token Cloudflared tunnel token + */ module.exports.autoStart = async (token) => { if (!token) { token = await setting("cloudflaredTunnelToken"); @@ -84,7 +102,10 @@ module.exports.autoStart = async (token) => { } }; +/** Stop cloudflared */ module.exports.stop = async () => { console.log("Stop cloudflared"); - cloudflared.stop(); + if (cloudflared) { + cloudflared.stop(); + } }; diff --git a/server/socket-handlers/database-socket-handler.js b/server/socket-handlers/database-socket-handler.js index 42fdb129c..041cbba06 100644 --- a/server/socket-handlers/database-socket-handler.js +++ b/server/socket-handlers/database-socket-handler.js @@ -1,6 +1,10 @@ const { checkLogin } = require("../util-server"); const Database = require("../database"); +/** + * Handlers for database + * @param {Socket} socket Socket.io instance + */ module.exports = (socket) => { // Post or edit incident diff --git a/server/socket-handlers/proxy-socket-handler.js b/server/socket-handlers/proxy-socket-handler.js index 817bdd49e..e67a829ff 100644 --- a/server/socket-handlers/proxy-socket-handler.js +++ b/server/socket-handlers/proxy-socket-handler.js @@ -1,8 +1,13 @@ const { checkLogin } = require("../util-server"); const { Proxy } = require("../proxy"); const { sendProxyList } = require("../client"); -const server = require("../server"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +const server = UptimeKumaServer.getInstance(); +/** + * Handlers for proxy + * @param {Socket} socket Socket.io instance + */ module.exports.proxySocketHandler = (socket) => { socket.on("addProxy", async (proxy, proxyID, callback) => { try { diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js index c844136ea..0a0dc6865 100644 --- a/server/socket-handlers/status-page-socket-handler.js +++ b/server/socket-handlers/status-page-socket-handler.js @@ -1,13 +1,17 @@ const { R } = require("redbean-node"); -const { checkLogin, setSettings, setSetting } = require("../util-server"); +const { checkLogin, setSetting } = require("../util-server"); const dayjs = require("dayjs"); -const { debug } = require("../../src/util"); +const { log } = require("../../src/util"); const ImageDataURI = require("../image-data-uri"); const Database = require("../database"); const apicache = require("../modules/apicache"); const StatusPage = require("../model/status_page"); -const server = require("../server"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +/** + * Socket handlers for status page + * @param {Socket} socket Socket.io instance to add listeners on + */ module.exports.statusPageSocketHandler = (socket) => { // Post or edit incident @@ -155,6 +159,9 @@ module.exports.statusPageSocketHandler = (socket) => { //statusPage.search_engine_index = ; statusPage.show_tags = config.showTags; //statusPage.password = null; + statusPage.footer_text = config.footerText; + statusPage.custom_css = config.customCSS; + statusPage.show_powered_by = config.showPoweredBy; statusPage.modified_date = R.isoDateTime(); await R.store(statusPage); @@ -202,8 +209,8 @@ module.exports.statusPageSocketHandler = (socket) => { group.id = groupBean.id; } - // Delete groups that not in the list - debug("Delete groups that not in the list"); + // Delete groups that are not in the list + log.debug("socket", "Delete groups that are not in the list"); const slots = groupIDList.map(() => "?").join(","); const data = [ @@ -212,6 +219,8 @@ module.exports.statusPageSocketHandler = (socket) => { ]; await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots}) AND status_page_id = ?`, data); + const server = UptimeKumaServer.getInstance(); + // Also change entry page to new slug if it is the default one, and slug is changed. if (server.entryPage === "statusPage-" + slug && statusPage.slug !== slug) { server.entryPage = "statusPage-" + statusPage.slug; @@ -226,7 +235,7 @@ module.exports.statusPageSocketHandler = (socket) => { }); } catch (error) { - console.error(error); + log.error("socket", error); callback({ ok: false, @@ -281,6 +290,8 @@ module.exports.statusPageSocketHandler = (socket) => { // Delete a status page socket.on("deleteStatusPage", async (slug, callback) => { + const server = UptimeKumaServer.getInstance(); + try { checkLogin(socket); @@ -331,6 +342,7 @@ module.exports.statusPageSocketHandler = (socket) => { /** * Check slug a-z, 0-9, - only * Regex from: https://stackoverflow.com/questions/22454258/js-regex-string-validation-for-slug + * @param {string} slug Slug to test */ function checkSlug(slug) { if (typeof slug !== "string") { diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js new file mode 100644 index 000000000..d0c968e73 --- /dev/null +++ b/server/uptime-kuma-server.js @@ -0,0 +1,117 @@ +const express = require("express"); +const https = require("https"); +const fs = require("fs"); +const http = require("http"); +const { Server } = require("socket.io"); +const { R } = require("redbean-node"); +const { log } = require("../src/util"); +const Database = require("./database"); +const util = require("util"); + +/** + * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. + * @type {UptimeKumaServer} + */ +class UptimeKumaServer { + /** + * + * @type {UptimeKumaServer} + */ + static instance = null; + + /** + * Main monitor list + * @type {{}} + */ + monitorList = {}; + entryPage = "dashboard"; + app = undefined; + httpServer = undefined; + io = undefined; + + static getInstance(args) { + if (UptimeKumaServer.instance == null) { + UptimeKumaServer.instance = new UptimeKumaServer(args); + } + return UptimeKumaServer.instance; + } + + constructor(args) { + // SSL + const sslKey = args["ssl-key"] || process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined; + const sslCert = args["ssl-cert"] || process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined; + + log.info("server", "Creating express and socket.io instance"); + this.app = express(); + + if (sslKey && sslCert) { + log.info("server", "Server Type: HTTPS"); + this.httpServer = https.createServer({ + key: fs.readFileSync(sslKey), + cert: fs.readFileSync(sslCert) + }, this.app); + } else { + log.info("server", "Server Type: HTTP"); + this.httpServer = http.createServer(this.app); + } + + this.io = new Server(this.httpServer); + } + + async sendMonitorList(socket) { + let list = await this.getMonitorJSONList(socket.userID); + this.io.to(socket.userID).emit("monitorList", list); + return list; + } + + /** + * Get a list of monitors for the given user. + * @param {string} userID - The ID of the user to get monitors for. + * @returns {Promise} A promise that resolves to an object with monitor IDs as keys and monitor objects as values. + * + * Generated by Trelent + */ + async getMonitorJSONList(userID) { + let result = {}; + + let monitorList = await R.find("monitor", " user_id = ? ORDER BY weight DESC, name", [ + userID, + ]); + + for (let monitor of monitorList) { + result[monitor.id] = await monitor.toJSON(); + } + + return result; + } + + /** + * Write error to log file + * @param {any} error The error to write + * @param {boolean} outputToConsole Should the error also be output to console? + */ + static errorLog(error, outputToConsole = true) { + const errorLogStream = fs.createWriteStream(Database.dataDir + "/error.log", { + flags: "a" + }); + + errorLogStream.on("error", () => { + log.info("", "Cannot write to error.log"); + }); + + if (errorLogStream) { + const dateTime = R.isoDateTime(); + errorLogStream.write(`[${dateTime}] ` + util.format(error) + "\n"); + + if (outputToConsole) { + console.error(error); + } + } + + errorLogStream.end(); + } +} + +module.exports = { + UptimeKumaServer +}; diff --git a/server/util-server.js b/server/util-server.js index b2c70d92f..54974e148 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -1,14 +1,15 @@ const tcpp = require("tcp-ping"); const Ping = require("./ping-lite"); const { R } = require("redbean-node"); -const { debug, genSecret } = require("../src/util"); +const { log, genSecret } = require("../src/util"); const passwordHash = require("./password-hash"); const { Resolver } = require("dns"); -const child_process = require("child_process"); +const childProcess = require("child_process"); const iconv = require("iconv-lite"); const chardet = require("chardet"); -const fs = require("fs"); -const nodeJsUtil = require("util"); +const mqtt = require("mqtt"); +const chroma = require("chroma-js"); +const { badgeConstants } = require("./config"); // From ping-lite exports.WIN = /^win/.test(process.platform); @@ -26,7 +27,7 @@ exports.initJWTSecret = async () => { "jwtSecret", ]); - if (! jwtSecretBean) { + if (!jwtSecretBean) { jwtSecretBean = R.dispense("setting"); jwtSecretBean.key = "jwtSecret"; } @@ -36,6 +37,12 @@ exports.initJWTSecret = async () => { return jwtSecretBean; }; +/** + * Send TCP request to specified hostname and port + * @param {string} hostname Hostname / address of machine + * @param {number} port TCP port to test + * @returns {Promise} Maximum time in ms rounded to nearest integer + */ exports.tcping = function (hostname, port) { return new Promise((resolve, reject) => { tcpp.ping({ @@ -57,6 +64,11 @@ exports.tcping = function (hostname, port) { }); }; +/** + * Ping the specified machine + * @param {string} hostname Hostname / address of machine + * @returns {Promise} Time for ping in ms rounded to nearest integer + */ exports.ping = async (hostname) => { try { return await exports.pingAsync(hostname); @@ -70,6 +82,12 @@ exports.ping = async (hostname) => { } }; +/** + * Ping the specified machine + * @param {string} hostname Hostname / address of machine to ping + * @param {boolean} ipv6 Should IPv6 be used? + * @returns {Promise} Time for ping in ms rounded to nearest integer + */ exports.pingAsync = function (hostname, ipv6 = false) { return new Promise((resolve, reject) => { const ping = new Ping(hostname, { @@ -88,11 +106,84 @@ exports.pingAsync = function (hostname, ipv6 = false) { }); }; -exports.dnsResolve = function (hostname, resolver_server, rrtype) { - const resolver = new Resolver(); - resolver.setServers([resolver_server]); +/** + * MQTT Monitor + * @param {string} hostname Hostname / address of machine to test + * @param {string} topic MQTT topic + * @param {string} okMessage Expected result + * @param {Object} [options={}] MQTT options. Contains port, username, + * password and interval (interval defaults to 20) + * @returns {Promise} + */ +exports.mqttAsync = function (hostname, topic, okMessage, options = {}) { return new Promise((resolve, reject) => { - if (rrtype == "PTR") { + const { port, username, password, interval = 20 } = options; + + // Adds MQTT protocol to the hostname if not already present + if (!/^(?:http|mqtt)s?:\/\//.test(hostname)) { + hostname = "mqtt://" + hostname; + } + + const timeoutID = setTimeout(() => { + log.debug("mqtt", "MQTT timeout triggered"); + client.end(); + reject(new Error("Timeout")); + }, interval * 1000 * 0.8); + + log.debug("mqtt", "MQTT connecting"); + + let client = mqtt.connect(hostname, { + port, + username, + password + }); + + client.on("connect", () => { + log.debug("mqtt", "MQTT connected"); + + try { + log.debug("mqtt", "MQTT subscribe topic"); + client.subscribe(topic); + } catch (e) { + client.end(); + clearTimeout(timeoutID); + reject(new Error("Cannot subscribe topic")); + } + }); + + client.on("error", (error) => { + client.end(); + clearTimeout(timeoutID); + reject(error); + }); + + client.on("message", (messageTopic, message) => { + if (messageTopic === topic) { + client.end(); + clearTimeout(timeoutID); + if (okMessage != null && okMessage !== "" && message.toString() !== okMessage) { + reject(new Error(`Message Mismatch - Topic: ${messageTopic}; Message: ${message.toString()}`)); + } else { + resolve(`Topic: ${messageTopic}; Message: ${message.toString()}`); + } + } + }); + + }); +}; + +/** + * Resolves a given record using the specified DNS server + * @param {string} hostname The hostname of the record to lookup + * @param {string} resolverServer The DNS server to use + * @param {string} rrtype The type of record to request + * @returns {Promise<(string[]|Object[]|Object)>} + */ +exports.dnsResolve = function (hostname, resolverServer, rrtype) { + const resolver = new Resolver(); + resolver.setServers([ resolverServer ]); + return new Promise((resolve, reject) => { + if (rrtype === "PTR") { resolver.reverse(hostname, (err, records) => { if (err) { reject(err); @@ -112,6 +203,11 @@ exports.dnsResolve = function (hostname, resolver_server, rrtype) { }); }; +/** + * Retrieve value of setting based on key + * @param {string} key Key of setting to retrieve + * @returns {Promise} Value + */ exports.setting = async function (key) { let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [ key, @@ -119,13 +215,20 @@ exports.setting = async function (key) { try { const v = JSON.parse(value); - debug(`Get Setting: ${key}: ${v}`); + log.debug("util", `Get Setting: ${key}: ${v}`); return v; } catch (e) { return value; } }; +/** + * Sets the specified setting to specifed value + * @param {string} key Key of setting to set + * @param {any} value Value to set to + * @param {?string} type Type of setting + * @returns {Promise} + */ exports.setSetting = async function (key, value, type = null) { let bean = await R.findOne("setting", " `key` = ? ", [ key, @@ -139,6 +242,11 @@ exports.setSetting = async function (key, value, type = null) { await R.store(bean); }; +/** + * Get settings based on type + * @param {?string} type The type of setting + * @returns {Promise} + */ exports.getSettings = async function (type) { let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [ type, @@ -157,6 +265,12 @@ exports.getSettings = async function (type) { return result; }; +/** + * Set settings based on type + * @param {?string} type Type of settings to set + * @param {Object} data Values of settings + * @returns {Promise} + */ exports.setSettings = async function (type, data) { let keyList = Object.keys(data); @@ -183,12 +297,23 @@ exports.setSettings = async function (type, data) { }; // ssl-checker by @dyaa -// param: res - response object from axios -// return an object containing the certificate information +//https://github.com/dyaa/ssl-checker/blob/master/src/index.ts +/** + * Get number of days between two dates + * @param {Date} validFrom Start date + * @param {Date} validTo End date + * @returns {number} + */ const getDaysBetween = (validFrom, validTo) => Math.round(Math.abs(+validFrom - +validTo) / 8.64e7); +/** + * Get days remaining from a time range + * @param {Date} validFrom Start date + * @param {Date} validTo End date + * @returns {number} + */ const getDaysRemaining = (validFrom, validTo) => { const daysRemaining = getDaysBetween(validFrom, validTo); if (new Date(validTo).getTime() < new Date().getTime()) { @@ -197,8 +322,11 @@ const getDaysRemaining = (validFrom, validTo) => { return daysRemaining; }; -// Fix certificate Info for display -// param: info - the chain obtained from getPeerCertificate() +/** + * Fix certificate info for display + * @param {Object} info The chain obtained from getPeerCertificate() + * @returns {Object} An object representing certificate information + */ const parseCertificateInfo = function (info) { let link = info; let i = 0; @@ -206,7 +334,7 @@ const parseCertificateInfo = function (info) { const existingList = {}; while (link) { - debug(`[${i}] ${link.fingerprint}`); + log.debug("cert", `[${i}] ${link.fingerprint}`); if (!link.valid_from || !link.valid_to) { break; @@ -221,7 +349,7 @@ const parseCertificateInfo = function (info) { if (link.issuerCertificate == null) { break; } else if (link.issuerCertificate.fingerprint in existingList) { - debug(`[Last] ${link.issuerCertificate.fingerprint}`); + log.debug("cert", `[Last] ${link.issuerCertificate.fingerprint}`); link.issuerCertificate = null; break; } else { @@ -238,11 +366,16 @@ const parseCertificateInfo = function (info) { return info; }; +/** + * Check if certificate is valid + * @param {Object} res Response object from axios + * @returns {Object} Object containing certificate information + */ exports.checkCertificate = function (res) { const info = res.request.res.socket.getPeerCertificate(true); const valid = res.request.res.socket.authorized || false; - debug("Parsing Certificate Info"); + log.debug("cert", "Parsing Certificate Info"); const parsedInfo = parseCertificateInfo(info); return { @@ -251,25 +384,26 @@ exports.checkCertificate = function (res) { }; }; -// Check if the provided status code is within the accepted ranges -// Param: status - the status code to check -// Param: accepted_codes - an array of accepted status codes -// Return: true if the status code is within the accepted ranges, false otherwise -// Will throw an error if the provided status code is not a valid range string or code string - -exports.checkStatusCode = function (status, accepted_codes) { - if (accepted_codes == null || accepted_codes.length === 0) { +/** + * Check if the provided status code is within the accepted ranges + * @param {string} status The status code to check + * @param {string[]} acceptedCodes An array of accepted status codes + * @returns {boolean} True if status code within range, false otherwise + * @throws {Error} Will throw an error if the provided status code is not a valid range string or code string + */ +exports.checkStatusCode = function (status, acceptedCodes) { + if (acceptedCodes == null || acceptedCodes.length === 0) { return false; } - for (const code_range of accepted_codes) { - const code_range_split = code_range.split("-").map(string => parseInt(string)); - if (code_range_split.length === 1) { - if (status === code_range_split[0]) { + for (const codeRange of acceptedCodes) { + const codeRangeSplit = codeRange.split("-").map(string => parseInt(string)); + if (codeRangeSplit.length === 1) { + if (status === codeRangeSplit[0]) { return true; } - } else if (code_range_split.length === 2) { - if (status >= code_range_split[0] && status <= code_range_split[1]) { + } else if (codeRangeSplit.length === 2) { + if (status >= codeRangeSplit[0] && status <= codeRangeSplit[1]) { return true; } } else { @@ -280,17 +414,23 @@ exports.checkStatusCode = function (status, accepted_codes) { return false; }; +/** + * Get total number of clients in room + * @param {Server} io Socket server instance + * @param {string} roomName Name of room to check + * @returns {number} + */ exports.getTotalClientInRoom = (io, roomName) => { const sockets = io.sockets; - if (! sockets) { + if (!sockets) { return 0; } const adapter = sockets.adapter; - if (! adapter) { + if (!adapter) { return 0; } @@ -303,27 +443,39 @@ exports.getTotalClientInRoom = (io, roomName) => { } }; +/** + * Allow CORS all origins if development + * @param {Object} res Response object from axios + */ exports.allowDevAllOrigin = (res) => { if (process.env.NODE_ENV === "development") { exports.allowAllOrigin(res); } }; +/** + * Allow CORS all origins + * @param {Object} res Response object from axios + */ exports.allowAllOrigin = (res) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); }; +/** + * Check if a user is logged in + * @param {Socket} socket Socket instance + */ exports.checkLogin = (socket) => { - if (! socket.userID) { + if (!socket.userID) { throw new Error("You are not logged in."); } }; /** * For logged-in users, double-check the password - * @param socket - * @param currentPassword + * @param {Socket} socket Socket.io instance + * @param {string} currentPassword * @returns {Promise} */ exports.doubleCheckPassword = async (socket, currentPassword) => { @@ -342,10 +494,11 @@ exports.doubleCheckPassword = async (socket, currentPassword) => { return user; }; +/** Start Unit tests */ exports.startUnitTest = async () => { console.log("Starting unit test..."); const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm"; - const child = child_process.spawn(npm, ["run", "jest"]); + const child = childProcess.spawn(npm, [ "run", "jest" ]); child.stdout.on("data", (data) => { console.log(data.toString()); @@ -362,33 +515,42 @@ exports.startUnitTest = async () => { }; /** - * @param body : Buffer + * Convert unknown string to UTF8 + * @param {Uint8Array} body Buffer * @returns {string} */ exports.convertToUTF8 = (body) => { const guessEncoding = chardet.detect(body); - //debug("Guess Encoding: " + guessEncoding); const str = iconv.decode(body, guessEncoding); return str.toString(); }; -let logFile; - -try { - logFile = fs.createWriteStream("./data/error.log", { - flags: "a" - }); -} catch (_) { } - -exports.errorLog = (error, outputToConsole = true) => { +/** + * Returns a color code in hex format based on a given percentage: + * 0% => hue = 10 => red + * 100% => hue = 90 => green + * + * @param {number} percentage float, 0 to 1 + * @param {number} maxHue + * @param {number} minHue, int + * @returns {string}, hex value + */ +exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => { + const hue = percentage * (maxHue - minHue) + minHue; try { - if (logFile) { - const dateTime = R.isoDateTime(); - logFile.write(`[${dateTime}] ` + nodeJsUtil.format(error) + "\n"); - - if (outputToConsole) { - console.error(error); - } - } - } catch (_) { } + return chroma(`hsl(${hue}, 90%, 40%)`).hex(); + } catch (err) { + return badgeConstants.naColor; + } +}; + +/** + * Joins and array of string to one string after filtering out empty values + * + * @param {string[]} parts + * @param {string} connector + * @returns {string} + */ +exports.filterAndJoin = (parts, connector = "") => { + return parts.filter((part) => !!part && part !== "").join(connector); }; diff --git a/src/App.vue b/src/App.vue index 099450d41..f102360c1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,12 +1,12 @@ diff --git a/src/assets/app.scss b/src/assets/app.scss index 0b27c6a6e..c3f2fa798 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -469,6 +469,10 @@ textarea.form-control { color: $primary; } +.prism-editor__textarea { + outline: none !important; +} + // Localization @import "localization.scss"; diff --git a/src/components/Confirm.vue b/src/components/Confirm.vue index 391155f43..1bfe7fe4a 100644 --- a/src/components/Confirm.vue +++ b/src/components/Confirm.vue @@ -25,7 +25,7 @@ diff --git a/src/components/CopyableInput.vue b/src/components/CopyableInput.vue index 1fe898028..1bccfa2ce 100644 --- a/src/components/CopyableInput.vue +++ b/src/components/CopyableInput.vue @@ -57,6 +57,7 @@ export default { default: undefined, }, }, + emits: [ "update:modelValue" ], data() { return { visibility: "password", diff --git a/src/components/CountUp.vue b/src/components/CountUp.vue index b321fde19..df1d1ac6c 100644 --- a/src/components/CountUp.vue +++ b/src/components/CountUp.vue @@ -5,12 +5,15 @@ diff --git a/src/components/Datetime.vue b/src/components/Datetime.vue index 1df982cb1..fa68d02c7 100644 --- a/src/components/Datetime.vue +++ b/src/components/Datetime.vue @@ -4,16 +4,19 @@ diff --git a/src/components/HeartbeatBar.vue b/src/components/HeartbeatBar.vue index be0b122ed..ce888a989 100644 --- a/src/components/HeartbeatBar.vue +++ b/src/components/HeartbeatBar.vue @@ -38,7 +38,7 @@ export default { beatMargin: 4, move: false, maxBeat: -1, - } + }; }, computed: { @@ -69,12 +69,12 @@ export default { if (start < 0) { // Add empty placeholder for (let i = start; i < 0; i++) { - placeholders.push(0) + placeholders.push(0); } start = 0; } - return placeholders.concat(this.beatList.slice(start)) + return placeholders.concat(this.beatList.slice(start)); }, wrapStyle() { @@ -84,7 +84,7 @@ export default { return { padding: `${topBottom}px ${leftRight}px`, width: "100%", - } + }; }, barStyle() { @@ -94,12 +94,12 @@ export default { return { transition: "all ease-in-out 0.25s", transform: `translateX(${width}px)`, - } + }; } return { transform: "translateX(0)", - } + }; }, @@ -109,7 +109,7 @@ export default { height: this.beatHeight + "px", margin: this.beatMargin + "px", "--hover-scale": this.hoverScale, - } + }; }, }, @@ -120,7 +120,7 @@ export default { setTimeout(() => { this.move = false; - }, 300) + }, 300); }, deep: true, }, @@ -162,15 +162,16 @@ export default { methods: { resize() { if (this.$refs.wrap) { - this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2)) + this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2)); } }, getBeatTitle(beat) { - return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : ``); - } + return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : ""); + }, + }, -} +}; diff --git a/src/components/settings/MonitorHistory.vue b/src/components/settings/MonitorHistory.vue index 9b5b8bd78..0092727f4 100644 --- a/src/components/settings/MonitorHistory.vue +++ b/src/components/settings/MonitorHistory.vue @@ -52,7 +52,7 @@ - - diff --git a/src/components/settings/Security.vue b/src/components/settings/Security.vue index 1459519f5..87bb745a1 100644 --- a/src/components/settings/Security.vue +++ b/src/components/settings/Security.vue @@ -4,7 +4,7 @@