diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9829c96..12fd6ed4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ The frontend code build into "dist" directory. The server (express.js) exposes t ## Can I create a pull request for Uptime Kuma? -Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create empty draft pull request or open an issue, so we can discuss first**. Especially for a large pull request or you don't know it will be merged or not. +Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can discuss first**. Especially for a large pull request or you don't know it will be merged or not. Here are some references: @@ -48,7 +48,7 @@ Here are some references: - UI/UX is not close to Uptime Kuma - Existing logic is completely modified or deleted for no reason - A function that is completely out of scope -- Unnesscary large code changes (Hard to review, casuse code conflicts to other pull requests) +- Unnecessary large code changes (Hard to review, causes code conflicts to other pull requests) I will mark your pull request in the [milestones](https://github.com/louislam/uptime-kuma/milestones), if I am plan to review and merge it. @@ -183,7 +183,7 @@ By default, the Chromium window will be shown up during the test. Specifying `HE ## Dependencies -Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not be used in production environment, because it is usually also baked into dist files. So: +Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not used in the production environment, because it is usually also baked into dist files. So: - Frontend dependencies = "devDependencies" - Examples: vue, chart.js diff --git a/README.md b/README.md index b81c0be2..55a6ec50 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,10 @@ It is a self-hosted monitoring tool like "Uptime Robot". Try it! -https://demo.uptime.kuma.pet +- Tokyo Demo Server: https://demo.uptime.kuma.pet (Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors)) +- Europe Demo Server: https://demo.uptime-kuma.karimi.dev:27000 (Provided by [@mhkarimi1383](https://github.com/mhkarimi1383)) -It is a temporary live demo, all data will be deleted after 10 minutes. The server is located in Tokyo, so if you live far from there, it may affect your experience. I suggest that you should install and try it out for the best demo experience. - -VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollective.com/uptime-kuma)! Thank you so much! +It is a temporary live demo, all data will be deleted after 10 minutes. Use the one that is closer to you, but I suggest that you should install and try it out for the best demo experience. ## ⭐ Features diff --git a/config/cypress.config.js b/config/cypress.config.js new file mode 100644 index 00000000..26784e88 --- /dev/null +++ b/config/cypress.config.js @@ -0,0 +1,28 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + projectId: "vyjuem", + e2e: { + experimentalStudio: true, + setupNodeEvents(on, config) { + + }, + fixturesFolder: "test/cypress/fixtures", + screenshotsFolder: "test/cypress/screenshots", + videosFolder: "test/cypress/videos", + downloadsFolder: "test/cypress/downloads", + supportFile: "test/cypress/support/e2e.js", + baseUrl: "http://localhost:3002", + defaultCommandTimeout: 10000, + pageLoadTimeout: 60000, + viewportWidth: 1920, + viewportHeight: 1080, + specPattern: [ + "test/cypress/e2e/setup.cy.js", + "test/cypress/e2e/**/*.js" + ], + }, + env: { + baseUrl: "http://localhost:3002", + }, +}); diff --git a/config/jest-debug-env.js b/config/jest-debug-env.js deleted file mode 100644 index 74f6d783..00000000 --- a/config/jest-debug-env.js +++ /dev/null @@ -1,33 +0,0 @@ -const PuppeteerEnvironment = require("jest-environment-puppeteer"); -const util = require("util"); - -class DebugEnv extends PuppeteerEnvironment { - async handleTestEvent(event, state) { - const ignoredEvents = [ - "setup", - "add_hook", - "start_describe_definition", - "add_test", - "finish_describe_definition", - "run_start", - "run_describe_start", - "test_start", - "hook_start", - "hook_success", - "test_fn_start", - "test_fn_success", - "test_done", - "run_describe_finish", - "run_finish", - "teardown", - "test_fn_failure", - ]; - if (!ignoredEvents.includes(event.name)) { - console.log( - new Date().toString() + ` Unhandled event [${event.name}] ` + util.inspect(event) - ); - } - } -} - -module.exports = DebugEnv; diff --git a/config/jest-frontend.config.js b/config/jest-frontend.config.js deleted file mode 100644 index ab6af7f1..00000000 --- a/config/jest-frontend.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - "rootDir": "..", - "testRegex": "./test/frontend.spec.js", -}; - diff --git a/config/jest-puppeteer.config.js b/config/jest-puppeteer.config.js deleted file mode 100644 index dc4f7b34..00000000 --- a/config/jest-puppeteer.config.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - "launch": { - "dumpio": true, - "slowMo": 500, - "headless": process.env.HEADLESS_TEST || false, - "userDataDir": "./data/test-chrome-profile", - args: [ - "--disable-setuid-sandbox", - "--disable-gpu", - "--disable-dev-shm-usage", - "--no-default-browser-check", - "--no-experiments", - "--no-first-run", - "--no-pings", - "--no-sandbox", - "--no-zygote", - "--single-process", - ], - } -}; diff --git a/config/jest.config.js b/config/jest.config.js deleted file mode 100644 index 2d3f585e..00000000 --- a/config/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - "verbose": true, - "preset": "jest-puppeteer", - "globals": { - "__DEV__": true - }, - "testRegex": "./test/e2e.spec.js", - "testEnvironment": "./config/jest-debug-env.js", - "rootDir": "..", - "testTimeout": 30000, -}; - diff --git a/cypress.config.ts b/cypress.config.ts deleted file mode 100644 index d97e0875..00000000 --- a/cypress.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from "cypress"; - -export default defineConfig({ - e2e: { - baseUrl: "http://localhost:3002", - defaultCommandTimeout: 10000, - pageLoadTimeout: 60000, - viewportWidth: 1920, - viewportHeight: 1080, - specPattern: ["cypress/e2e/setup.cy.ts", "cypress/e2e/**/*.ts"], - }, - env: { - baseUrl: "http://localhost:3002", - }, -}); diff --git a/cypress/e2e/setup.cy.ts b/cypress/e2e/setup.cy.ts deleted file mode 100644 index 94e18ede..00000000 --- a/cypress/e2e/setup.cy.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { actor } from "../support/actors/actor"; -import { DEFAULT_USER_DATA } from "../support/const/user-data"; -import { DashboardPage } from "../support/pages/dasboard-page"; -import { SetupPage } from "../support/pages/setup-page"; - -describe("user can create a new account on setup page", () => { - before(() => { - cy.visit("/setup"); - }); - - it("user can create new account", () => { - cy.url().should("be.equal", SetupPage.url); - actor.setupTask.fillAndSubmitSetupForm( - DEFAULT_USER_DATA.username, - DEFAULT_USER_DATA.password, - DEFAULT_USER_DATA.password - ); - - cy.url().should("be.equal", DashboardPage.url); - cy.get('[role="alert"]') - .should("be.visible") - .and("contain.text", "Added Successfully."); - }); -}); diff --git a/cypress/support/actors/actor.ts b/cypress/support/actors/actor.ts deleted file mode 100644 index 680c26ce..00000000 --- a/cypress/support/actors/actor.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SetupTask } from "../tasks/setup-task"; - -class Actor { - setupTask: SetupTask = new SetupTask(); -} - -const actor = new Actor(); -export { actor }; diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts deleted file mode 100644 index f887c29a..00000000 --- a/cypress/support/e2e.ts +++ /dev/null @@ -1 +0,0 @@ -import "./commands"; diff --git a/cypress/support/tasks/setup-task.ts b/cypress/support/tasks/setup-task.ts deleted file mode 100644 index 866e3ca5..00000000 --- a/cypress/support/tasks/setup-task.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { SetupPage } from "../pages/setup-page"; - -export class SetupTask { - fillAndSubmitSetupForm( - username: string, - password: string, - passwordRepeat: string - ) { - cy.get(SetupPage.usernameInput).type(username); - cy.get(SetupPage.passWordInput).type(password); - cy.get(SetupPage.passwordRepeatInput).type(passwordRepeat); - - cy.get(SetupPage.submitSetupForm).click(); - } -} diff --git a/db/patch-maintenance-table2.sql b/db/patch-maintenance-table2.sql new file mode 100644 index 00000000..96b2ebde --- /dev/null +++ b/db/patch-maintenance-table2.sql @@ -0,0 +1,83 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +-- Just for someone who tested maintenance before (patch-maintenance-table.sql) +DROP TABLE IF EXISTS maintenance_status_page; +DROP TABLE IF EXISTS monitor_maintenance; +DROP TABLE IF EXISTS maintenance; +DROP TABLE IF EXISTS maintenance_timeslot; + +-- maintenance +CREATE TABLE [maintenance] ( + [id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + [title] VARCHAR(150) NOT NULL, + [description] TEXT NOT NULL, + [user_id] INTEGER REFERENCES [user]([id]) ON DELETE SET NULL ON UPDATE CASCADE, + [active] BOOLEAN NOT NULL DEFAULT 1, + [strategy] VARCHAR(50) NOT NULL DEFAULT 'single', + [start_date] DATETIME, + [end_date] DATETIME, + [start_time] TIME, + [end_time] TIME, + [weekdays] VARCHAR2(250) DEFAULT '[]', + [days_of_month] TEXT DEFAULT '[]', + [interval_day] INTEGER +); + +CREATE INDEX [manual_active] ON [maintenance] ( + [strategy], + [active] +); + +CREATE INDEX [active] ON [maintenance] ([active]); + +CREATE INDEX [maintenance_user_id] ON [maintenance] ([user_id]); + +-- maintenance_status_page +CREATE TABLE maintenance_status_page ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + status_page_id INTEGER NOT NULL, + maintenance_id INTEGER NOT NULL, + CONSTRAINT FK_maintenance FOREIGN KEY (maintenance_id) REFERENCES maintenance (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_status_page FOREIGN KEY (status_page_id) REFERENCES status_page (id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX [status_page_id_index] + ON [maintenance_status_page]([status_page_id]); + +CREATE INDEX [maintenance_id_index] + ON [maintenance_status_page]([maintenance_id]); + +-- maintenance_timeslot +CREATE TABLE [maintenance_timeslot] ( + [id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + [maintenance_id] INTEGER NOT NULL CONSTRAINT [FK_maintenance] REFERENCES [maintenance]([id]) ON DELETE CASCADE ON UPDATE CASCADE, + [start_date] DATETIME NOT NULL, + [end_date] DATETIME, + [generated_next] BOOLEAN DEFAULT 0 +); + +CREATE INDEX [maintenance_id] ON [maintenance_timeslot] ([maintenance_id] DESC); + +CREATE INDEX [active_timeslot_index] ON [maintenance_timeslot] ( + [maintenance_id] DESC, + [start_date] DESC, + [end_date] DESC +); + +CREATE INDEX [generated_next_index] ON [maintenance_timeslot] ([generated_next]); + +-- monitor_maintenance +CREATE TABLE monitor_maintenance ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + monitor_id INTEGER NOT NULL, + maintenance_id INTEGER NOT NULL, + CONSTRAINT FK_maintenance FOREIGN KEY (maintenance_id) REFERENCES maintenance (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_monitor FOREIGN KEY (monitor_id) REFERENCES monitor (id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX [maintenance_id_index2] ON [monitor_maintenance]([maintenance_id]); + +CREATE INDEX [monitor_id_index] ON [monitor_maintenance]([monitor_id]); + +COMMIT; diff --git a/extra/update-language-files/index.js b/extra/update-language-files/index.js index e449fe34..078c4e6f 100644 --- a/extra/update-language-files/index.js +++ b/extra/update-language-files/index.js @@ -1,51 +1,45 @@ // Need to use ES6 to read language files import fs from "fs"; -import path from "path"; import util from "util"; import rmSync from "../fs-rmSync.js"; -// https://stackoverflow.com/questions/13786160/copy-folder-recursively-in-node-js /** - * Look ma, it's cp -R. - * @param {string} src The path to the thing to copy. - * @param {string} dest The path to the new copy. + * Copy across the required language files + * Creates a local directory (./languages) and copies the required files + * into it. + * @param {string} langCode Code of language to update. A file will be + * created with this code if one does not already exist + * @param {string} baseLang The second base language file to copy. This + * will be ignored if set to "en" as en.js is copied by default */ -const copyRecursiveSync = function (src, dest) { - let exists = fs.existsSync(src); - let stats = exists && fs.statSync(src); - let isDirectory = exists && stats.isDirectory(); +function copyFiles(langCode, baseLang) { + if (fs.existsSync("./languages")) { + rmSync("./languages", { recursive: true }); + } + fs.mkdirSync("./languages"); - if (isDirectory) { - fs.mkdirSync(dest); - fs.readdirSync(src).forEach(function (childItemName) { - copyRecursiveSync(path.join(src, childItemName), - path.join(dest, childItemName)); - }); + if (!fs.existsSync(`../../src/languages/${langCode}.js`)) { + fs.closeSync(fs.openSync(`./languages/${langCode}.js`, "a")); } else { - fs.copyFileSync(src, dest); + fs.copyFileSync(`../../src/languages/${langCode}.js`, `./languages/${langCode}.js`); + } + fs.copyFileSync("../../src/languages/en.js", "./languages/en.js"); + if (baseLang !== "en") { + fs.copyFileSync(`../../src/languages/${baseLang}.js`, `./languages/${baseLang}.js`); } -}; - -console.log("Arguments:", process.argv); -const baseLangCode = process.argv[2] || "en"; -console.log("Base Lang: " + baseLangCode); -if (fs.existsSync("./languages")) { - rmSync("./languages", { recursive: true }); } -copyRecursiveSync("../../src/languages", "./languages"); -const en = (await import("./languages/en.js")).default; -const baseLang = (await import(`./languages/${baseLangCode}.js`)).default; -const files = fs.readdirSync("./languages"); -console.log("Files:", files); - -for (const file of files) { - if (! file.endsWith(".js")) { - console.log("Skipping " + file); - continue; - } +/** + * Update the specified language file + * @param {string} langCode Language code to update + * @param {string} baseLang Second language to copy keys from + */ +async function updateLanguage(langCode, baseLangCode) { + const en = (await import("./languages/en.js")).default; + const baseLang = (await import(`./languages/${baseLangCode}.js`)).default; + let file = langCode + ".js"; console.log("Processing " + file); const lang = await import("./languages/" + file); @@ -83,5 +77,20 @@ for (const file of files) { fs.writeFileSync(`../../src/languages/${file}`, code); } +// Get command line arguments +const baseLangCode = process.env.npm_config_baselang || "en"; +const langCode = process.env.npm_config_language; + +// We need the file to edit +if (langCode == null) { + throw new Error("Argument --language= must be provided"); +} + +console.log("Base Lang: " + baseLangCode); +console.log("Updating: " + langCode); + +copyFiles(langCode, baseLangCode); +await updateLanguage(langCode, baseLangCode); rmSync("./languages", { recursive: true }); + console.log("Done. Fixing formatting by ESLint..."); diff --git a/package-lock.json b/package-lock.json index 65e380d1..5adb1841 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,57 +1,58 @@ { "name": "uptime-kuma", - "version": "1.18.0", + "version": "1.19.0-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.18.0", + "version": "1.19.0-beta.0", "license": "MIT", "dependencies": { - "@louislam/sqlite3": "~15.0.6", + "@louislam/sqlite3": "15.1.2", "args-parser": "~1.3.0", "axios": "~0.27.0", - "axios-ntlm": "^1.3.0", - "badge-maker": "^3.3.1", + "axios-ntlm": "~1.3.0", + "badge-maker": "~3.3.1", "bcryptjs": "~2.4.3", "bree": "~7.1.5", "cacheable-lookup": "~6.0.4", - "chardet": "^1.3.0", + "chardet": "~1.4.0", "check-password-strength": "^2.0.5", - "cheerio": "^1.0.0-rc.10", - "chroma-js": "^2.1.2", + "cheerio": "~1.0.0-rc.12", + "chroma-js": "~2.4.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", - "compression": "^1.7.4", - "dayjs": "^1.11.0", + "compression": "~1.7.4", + "dayjs": "~1.11.5", "express": "~4.17.3", "express-basic-auth": "~1.2.1", - "express-static-gzip": "^2.1.7", + "express-static-gzip": "~2.1.7", "form-data": "~4.0.0", "http-graceful-shutdown": "~3.1.7", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "iconv-lite": "^0.6.3", + "http-proxy-agent": "~5.0.0", + "https-proxy-agent": "~5.0.1", + "iconv-lite": "~0.6.3", + "jsesc": "~3.0.2", "jsonwebtoken": "~8.5.1", - "jwt-decode": "^3.1.2", - "limiter": "^2.1.0", - "mqtt": "^4.2.8", - "mssql": "^8.1.0", + "jwt-decode": "~3.1.2", + "limiter": "~2.1.0", + "mqtt": "~4.3.7", + "mssql": "~8.1.4", "node-cloudflared-tunnel": "~1.0.9", - "node-radius-client": "^1.0.0", + "node-radius-client": "~1.0.0", "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", - "pg": "^8.7.3", - "pg-connection-string": "^2.5.0", + "pg": "~8.8.0", + "pg-connection-string": "~2.5.0", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", "redbean-node": "0.1.4", - "socket.io": "~4.4.1", - "socket.io-client": "~4.4.1", + "socket.io": "~4.5.3", + "socket.io-client": "~4.5.3", "socks-proxy-agent": "6.1.1", - "tar": "^6.1.11", + "tar": "~6.1.11", "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2" }, @@ -68,6 +69,7 @@ "@vitejs/plugin-legacy": "~2.1.0", "@vitejs/plugin-vue": "~3.1.0", "@vue/compiler-sfc": "~3.2.36", + "@vuepic/vue-datepicker": "~3.4.8", "aedes": "^0.46.3", "babel-plugin-rewire": "~1.2.0", "bootstrap": "5.1.3", @@ -81,20 +83,18 @@ "dns2": "~2.0.1", "eslint": "~8.14.0", "eslint-plugin-vue": "~8.7.1", - "favico.js": "^0.3.10", + "favico.js": "~0.3.10", "jest": "~27.2.5", - "jest-puppeteer": "~6.0.3", "postcss-html": "~1.5.0", "postcss-rtlcss": "~3.7.2", "postcss-scss": "~4.0.4", - "prismjs": "^1.27.0", - "puppeteer": "~13.1.3", + "prismjs": "~1.29.0", "qrcode": "~1.5.0", "rollup-plugin-visualizer": "^5.6.0", "sass": "~1.42.1", "stylelint": "~14.7.1", "stylelint-config-standard": "~25.0.0", - "terser": "^5.15.0", + "terser": "~5.15.0", "timezones-list": "~3.0.1", "typescript": "~4.4.4", "v-pagination-3": "~0.1.7", @@ -104,10 +104,10 @@ "vue-chart-3": "3.0.9", "vue-confirm-dialog": "~1.0.2", "vue-contenteditable": "~3.0.4", - "vue-i18n": "~9.1.9", + "vue-i18n": "~9.2.2", "vue-image-crop-upload": "~3.0.3", "vue-multiselect": "~3.0.0-alpha.2", - "vue-prism-editor": "^2.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", @@ -476,6 +476,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", @@ -2327,92 +2339,65 @@ "dev": true }, "node_modules/@intlify/core-base": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz", - "integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz", + "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==", "dev": true, "dependencies": { - "@intlify/devtools-if": "9.1.10", - "@intlify/message-compiler": "9.1.10", - "@intlify/message-resolver": "9.1.10", - "@intlify/runtime": "9.1.10", - "@intlify/shared": "9.1.10", - "@intlify/vue-devtools": "9.1.10" + "@intlify/devtools-if": "9.2.2", + "@intlify/message-compiler": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/@intlify/devtools-if": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz", - "integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz", + "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==", "dev": true, "dependencies": { - "@intlify/shared": "9.1.10" + "@intlify/shared": "9.2.2" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/@intlify/message-compiler": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz", - "integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz", + "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==", "dev": true, "dependencies": { - "@intlify/message-resolver": "9.1.10", - "@intlify/shared": "9.1.10", + "@intlify/shared": "9.2.2", "source-map": "0.6.1" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/@intlify/message-resolver": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz", - "integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@intlify/runtime": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz", - "integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==", - "dev": true, - "dependencies": { - "@intlify/message-compiler": "9.1.10", - "@intlify/message-resolver": "9.1.10", - "@intlify/shared": "9.1.10" - }, - "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/@intlify/shared": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz", - "integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz", + "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==", "dev": true, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/@intlify/vue-devtools": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz", - "integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz", + "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==", "dev": true, "dependencies": { - "@intlify/message-resolver": "9.1.10", - "@intlify/runtime": "9.1.10", - "@intlify/shared": "9.1.10" + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/@istanbuljs/load-nyc-config": { @@ -3131,9 +3116,9 @@ "integrity": "sha512-iHHyIRLEfXLqBN+BkyH8u8imMYr4ihRbFDEk8toqTwUECETVQFCTh2U59Sw2oMoRVaS3XRIb7pyCulltq2jFVA==" }, "node_modules/@louislam/sqlite3": { - "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==", + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.1.2.tgz", + "integrity": "sha512-VRquWrCKKwfOnzwVh6hOud8lHPvv2R7Jic3gyZCL5kiZpNfmJ71DLCV9SNgLaMDloU+mVWymLev8vehlf7xf5g==", "hasInstallScript": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", @@ -3381,9 +3366,9 @@ } }, "node_modules/@socket.io/component-emitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", - "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@tediousjs/connection-string": { "version": "0.3.0", @@ -3465,11 +3450,6 @@ "@popperjs/core": "^2.9.2" } }, - "node_modules/@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" - }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -3941,6 +3921,21 @@ "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==", "dev": true }, + "node_modules/@vuepic/vue-datepicker": { + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-3.4.8.tgz", + "integrity": "sha512-nbuMA7IgjtT99LqcjSTSUcl7omTZSB+7vYSWQ9gQm31Frm/1wn54fT1Q0HaRD9nHXX982AACbqeND4K80SKONw==", + "dev": true, + "dependencies": { + "date-fns": "^2.29.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "vue": ">=3.2.0" + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -4231,15 +4226,6 @@ "resolved": "https://registry.npmjs.org/args-parser/-/args-parser-1.3.0.tgz", "integrity": "sha512-If3Zi4BSjlQIJ9fgAhSiKi0oJtgMzSqh0H4wvl7XSeO16FKx7QqaHld8lZeEajPX7y1C5qKKeNgyrfyvmjmjUQ==" }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4602,11 +4588,6 @@ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" - }, "node_modules/badge-maker": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz", @@ -5317,34 +5298,6 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/clone-deep": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", - "integrity": "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==", - "dev": true, - "dependencies": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clone-regexp": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", @@ -5481,11 +5434,6 @@ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -5935,19 +5883,6 @@ "resolved": "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz", "integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==" }, - "node_modules/cwd": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", - "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", - "dev": true, - "dependencies": { - "find-pkg": "^0.1.2", - "fs-exists-sync": "^0.1.0" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/cypress": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.7.0.tgz", @@ -6400,12 +6335,6 @@ "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==" }, - "node_modules/devtools-protocol": { - "version": "0.0.948846", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.948846.tgz", - "integrity": "sha512-5fGyt9xmMqUl2VI7+rnUkKCiAQIpLns8sfQtTENy5L70ktbNw0Z3TFJ1JoFNYdx/jffz4YXU45VF75wKZD7sZQ==", - "dev": true - }, "node_modules/diff-sequences": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", @@ -6603,9 +6532,9 @@ } }, "node_modules/engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -6623,19 +6552,15 @@ } }, "node_modules/engine.io-client": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", - "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz", + "integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==", "dependencies": { - "@socket.io/component-emitter": "~3.0.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", - "has-cors": "1.1.0", - "parseqs": "0.0.6", - "parseuri": "0.0.6", + "engine.io-parser": "~5.0.3", "ws": "~8.2.3", - "xmlhttprequest-ssl": "~2.0.0", - "yeast": "0.1.2" + "xmlhttprequest-ssl": "~2.0.0" } }, "node_modules/engine.io-client/node_modules/ws": { @@ -7717,18 +7642,6 @@ "node": ">= 0.8.0" } }, - "node_modules/expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expect": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", @@ -7744,12 +7657,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/expect-puppeteer": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-6.1.1.tgz", - "integrity": "sha512-cnQF96qdoEcOD63j5NQMc0RtW9WRMW/WHKXEKsuDQ2tszhVH3qC7zkXXS4D0LTt9qCB3DEExioqylsQXvqPrUw==", - "dev": true - }, "node_modules/express": { "version": "4.17.3", "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", @@ -8073,115 +7980,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/find-file-up": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", - "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", - "dev": true, - "dependencies": { - "fs-exists-sync": "^0.1.0", - "resolve-dir": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-pkg": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", - "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", - "dev": true, - "dependencies": { - "find-file-up": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-process": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.7.tgz", - "integrity": "sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "commander": "^5.1.0", - "debug": "^4.1.1" - }, - "bin": { - "find-process": "bin/find-process.js" - } - }, - "node_modules/find-process/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/find-process/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/find-process/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/find-process/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/find-process/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/find-process/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/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -8233,27 +8031,6 @@ } } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", - "dev": true, - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "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", @@ -8326,21 +8103,6 @@ "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", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -8606,46 +8368,6 @@ "node": ">=10" } }, - "node_modules/global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", - "dev": true, - "dependencies": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -8752,11 +8474,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -8822,18 +8539,6 @@ "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -9186,12 +8891,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "node_modules/is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", @@ -9254,15 +8953,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9545,15 +9235,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -9588,15 +9269,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "devOptional": true }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -10064,91 +9736,6 @@ "node": ">=8" } }, - "node_modules/jest-dev-server": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-6.1.1.tgz", - "integrity": "sha512-z5LnaGDvlIkdMv/rppSO4+rq+GyQKf1xI9oiBxf9/2EBeN2hxRaWiMvaLNDnHPZj2PAhBXsycrKslDDoZO2Xtw==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "find-process": "^1.4.7", - "prompts": "^2.4.2", - "spawnd": "^6.0.2", - "tree-kill": "^1.2.2", - "wait-on": "^6.0.1" - } - }, - "node_modules/jest-dev-server/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/jest-dev-server/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/jest-dev-server/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/jest-dev-server/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/jest-dev-server/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/jest-dev-server/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/jest-diff": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", @@ -10367,89 +9954,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-puppeteer": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jest-environment-puppeteer/-/jest-environment-puppeteer-6.1.1.tgz", - "integrity": "sha512-Ces37g8Gdj7QaVxszeoXlvmsZxcEJN9EPUdJt8fGMLA+6ARVFKyVmFgP9xVeGyjTvzsXdtIiJdeOKMLMeD8r2A==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "jest-dev-server": "^6.1.1", - "jest-environment-node": "^27.4.4", - "merge-deep": "^3.0.3" - } - }, - "node_modules/jest-environment-puppeteer/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/jest-environment-puppeteer/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/jest-environment-puppeteer/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/jest-environment-puppeteer/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/jest-environment-puppeteer/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/jest-environment-puppeteer/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/jest-get-type": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", @@ -10801,19 +10305,6 @@ } } }, - "node_modules/jest-puppeteer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/jest-puppeteer/-/jest-puppeteer-6.0.3.tgz", - "integrity": "sha512-6GRdbkWwNu8dfzo4icpwc50+K5ECYpWyD9sxpRa03PA8Hi3byl0dcAx+NjCivSezWjAl2Iwwhujqb+bczei0Bg==", - "dev": true, - "dependencies": { - "expect-puppeteer": "^6.0.2", - "jest-environment-puppeteer": "^6.0.3" - }, - "peerDependencies": { - "puppeteer": ">= 1.5.0" - } - }, "node_modules/jest-regex-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", @@ -11716,15 +11207,14 @@ "dev": true }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { @@ -11863,18 +11353,6 @@ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -11982,15 +11460,6 @@ "node": "> 0.8" } }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -12454,20 +11923,6 @@ "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, - "node_modules/merge-deep": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", - "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -12619,28 +12074,6 @@ "node": ">= 8" } }, - "node_modules/mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", - "dev": true, - "dependencies": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-object/node_modules/for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -12652,12 +12085,6 @@ "node": ">=10" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "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", @@ -13292,15 +12719,6 @@ "node": ">= 0.8.0" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", @@ -13426,15 +12844,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parse5": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", @@ -13458,16 +12867,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" - }, - "node_modules/parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -13910,15 +13309,6 @@ "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", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/prom-client": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.2.0.tgz", @@ -13984,12 +13374,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -14013,87 +13397,6 @@ "node": ">=6" } }, - "node_modules/puppeteer": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.1.3.tgz", - "integrity": "sha512-nqcJNThLUG0Dgo++2mMtGR2FCyg7olJJhj/rm0A65muyN3nrH6lGvnNRzEaNmSnHWvjaDIG9ox5kxQB+nXTg5A==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "debug": "4.3.2", - "devtools-protocol": "0.0.948846", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", - "node-fetch": "2.6.7", - "pkg-dir": "4.2.0", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.2.3" - }, - "engines": { - "node": ">=10.18.1" - } - }, - "node_modules/puppeteer/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/puppeteer/node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/puppeteer/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/puppeteer/node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/qlobber": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/qlobber/-/qlobber-5.0.3.tgz", @@ -14728,19 +14031,6 @@ "node": ">=8" } }, - "node_modules/resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", - "dev": true, - "dependencies": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -15070,42 +14360,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone/node_modules/kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==", - "dev": true, - "dependencies": { - "is-buffer": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone/node_modules/lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15226,61 +14480,46 @@ } }, "node_modules/socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" }, "node_modules/socket.io-client": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", - "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.3.tgz", + "integrity": "sha512-I/hqDYpQ6JKwtJOf5ikM+Qz+YujZPMEl6qBLhxiP0nX+TfXKhW4KZZG8lamrD6Y5ngjmYHreESVasVCgi5Kl3A==", "dependencies": { - "@socket.io/component-emitter": "~3.0.0", - "backo2": "~1.0.2", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", - "engine.io-client": "~6.1.1", - "parseuri": "0.0.6", - "socket.io-parser": "~4.1.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-client/node_modules/socket.io-parser": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.2.tgz", - "integrity": "sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog==", - "dependencies": { - "@socket.io/component-emitter": "~3.0.0", - "debug": "~4.3.1" + "engine.io-client": "~6.2.3", + "socket.io-parser": "~4.2.0" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-parser": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", - "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", "dependencies": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" }, "engines": { @@ -15359,17 +14598,6 @@ "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", "dev": true }, - "node_modules/spawnd": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-6.0.2.tgz", - "integrity": "sha512-+YJtx0dvy2wt304MrHD//tASc84zinBUYU1jacPBzrjhZUd7RsDo25krxr4HUHAQzEQFuMAs4/p+yLYU5ciZ1w==", - "dev": true, - "dependencies": { - "exit": "^0.1.2", - "signal-exit": "^3.0.6", - "tree-kill": "^1.2.2" - } - }, "node_modules/spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -15914,40 +15142,6 @@ "node": ">= 10" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tarn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", @@ -16349,16 +15543,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -16863,18 +16047,18 @@ } }, "node_modules/vue-i18n": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz", - "integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz", + "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==", "dev": true, "dependencies": { - "@intlify/core-base": "9.1.10", - "@intlify/shared": "9.1.10", - "@intlify/vue-devtools": "9.1.10", - "@vue/devtools-api": "^6.0.0-beta.7" + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2", + "@vue/devtools-api": "^6.2.1" }, "engines": { - "node": ">= 10" + "node": ">= 14" }, "peerDependencies": { "vue": "^3.0.0" @@ -17403,11 +16587,6 @@ "fd-slicer": "~1.1.0" } }, - "node_modules/yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -17725,6 +16904,14 @@ "@babel/types": "^7.18.13", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + } } }, "@babel/helper-annotate-as-pure": { @@ -19027,71 +18214,50 @@ "dev": true }, "@intlify/core-base": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz", - "integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz", + "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==", "dev": true, "requires": { - "@intlify/devtools-if": "9.1.10", - "@intlify/message-compiler": "9.1.10", - "@intlify/message-resolver": "9.1.10", - "@intlify/runtime": "9.1.10", - "@intlify/shared": "9.1.10", - "@intlify/vue-devtools": "9.1.10" + "@intlify/devtools-if": "9.2.2", + "@intlify/message-compiler": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2" } }, "@intlify/devtools-if": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz", - "integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz", + "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==", "dev": true, "requires": { - "@intlify/shared": "9.1.10" + "@intlify/shared": "9.2.2" } }, "@intlify/message-compiler": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz", - "integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz", + "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==", "dev": true, "requires": { - "@intlify/message-resolver": "9.1.10", - "@intlify/shared": "9.1.10", + "@intlify/shared": "9.2.2", "source-map": "0.6.1" } }, - "@intlify/message-resolver": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz", - "integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==", - "dev": true - }, - "@intlify/runtime": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz", - "integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==", - "dev": true, - "requires": { - "@intlify/message-compiler": "9.1.10", - "@intlify/message-resolver": "9.1.10", - "@intlify/shared": "9.1.10" - } - }, "@intlify/shared": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz", - "integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz", + "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==", "dev": true }, "@intlify/vue-devtools": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz", - "integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz", + "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==", "dev": true, "requires": { - "@intlify/message-resolver": "9.1.10", - "@intlify/runtime": "9.1.10", - "@intlify/shared": "9.1.10" + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2" } }, "@istanbuljs/load-nyc-config": { @@ -19647,9 +18813,9 @@ "integrity": "sha512-iHHyIRLEfXLqBN+BkyH8u8imMYr4ihRbFDEk8toqTwUECETVQFCTh2U59Sw2oMoRVaS3XRIb7pyCulltq2jFVA==" }, "@louislam/sqlite3": { - "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==", + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.1.2.tgz", + "integrity": "sha512-VRquWrCKKwfOnzwVh6hOud8lHPvv2R7Jic3gyZCL5kiZpNfmJ71DLCV9SNgLaMDloU+mVWymLev8vehlf7xf5g==", "requires": { "@mapbox/node-pre-gyp": "^1.0.0", "node-addon-api": "^4.2.0", @@ -19860,9 +19026,9 @@ } }, "@socket.io/component-emitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", - "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "@tediousjs/connection-string": { "version": "0.3.0", @@ -19941,11 +19107,6 @@ "@popperjs/core": "^2.9.2" } }, - "@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" - }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -20409,6 +19570,15 @@ "integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==", "dev": true }, + "@vuepic/vue-datepicker": { + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-3.4.8.tgz", + "integrity": "sha512-nbuMA7IgjtT99LqcjSTSUcl7omTZSB+7vYSWQ9gQm31Frm/1wn54fT1Q0HaRD9nHXX982AACbqeND4K80SKONw==", + "dev": true, + "requires": { + "date-fns": "^2.29.2" + } + }, "abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -20628,12 +19798,6 @@ "resolved": "https://registry.npmjs.org/args-parser/-/args-parser-1.3.0.tgz", "integrity": "sha512-If3Zi4BSjlQIJ9fgAhSiKi0oJtgMzSqh0H4wvl7XSeO16FKx7QqaHld8lZeEajPX7y1C5qKKeNgyrfyvmjmjUQ==" }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "dev": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -20931,11 +20095,6 @@ } } }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" - }, "badge-maker": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz", @@ -21462,30 +20621,6 @@ "wrap-ansi": "^7.0.0" } }, - "clone-deep": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", - "integrity": "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==", - "dev": true, - "requires": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, "clone-regexp": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", @@ -21599,11 +20734,6 @@ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -21950,16 +21080,6 @@ "resolved": "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz", "integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==" }, - "cwd": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", - "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", - "dev": true, - "requires": { - "find-pkg": "^0.1.2", - "fs-exists-sync": "^0.1.0" - } - }, "cypress": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.7.0.tgz", @@ -22299,12 +21419,6 @@ "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==" }, - "devtools-protocol": { - "version": "0.0.948846", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.948846.tgz", - "integrity": "sha512-5fGyt9xmMqUl2VI7+rnUkKCiAQIpLns8sfQtTENy5L70ktbNw0Z3TFJ1JoFNYdx/jffz4YXU45VF75wKZD7sZQ==", - "dev": true - }, "diff-sequences": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", @@ -22462,9 +21576,9 @@ } }, "engine.io": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.3.tgz", - "integrity": "sha512-rqs60YwkvWTLLnfazqgZqLa/aKo+9cueVfEi/dZ8PyGyaf8TLOxj++4QMIgeG3Gn0AhrWiFXvghsoY9L9h25GA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", "requires": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -22486,19 +21600,15 @@ } }, "engine.io-client": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", - "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz", + "integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==", "requires": { - "@socket.io/component-emitter": "~3.0.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", - "has-cors": "1.1.0", - "parseqs": "0.0.6", - "parseuri": "0.0.6", + "engine.io-parser": "~5.0.3", "ws": "~8.2.3", - "xmlhttprequest-ssl": "~2.0.0", - "yeast": "0.1.2" + "xmlhttprequest-ssl": "~2.0.0" }, "dependencies": { "ws": { @@ -23167,15 +22277,6 @@ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", - "dev": true, - "requires": { - "os-homedir": "^1.0.1" - } - }, "expect": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", @@ -23188,12 +22289,6 @@ "jest-message-util": "^27.5.1" } }, - "expect-puppeteer": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-6.1.1.tgz", - "integrity": "sha512-cnQF96qdoEcOD63j5NQMc0RtW9WRMW/WHKXEKsuDQ2tszhVH3qC7zkXXS4D0LTt9qCB3DEExioqylsQXvqPrUw==", - "dev": true - }, "express": { "version": "4.17.3", "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", @@ -23464,87 +22559,6 @@ } } }, - "find-file-up": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", - "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", - "dev": true, - "requires": { - "fs-exists-sync": "^0.1.0", - "resolve-dir": "^0.1.0" - } - }, - "find-pkg": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", - "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", - "dev": true, - "requires": { - "find-file-up": "^0.1.2" - } - }, - "find-process": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.7.tgz", - "integrity": "sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "commander": "^5.1.0", - "debug": "^4.1.1" - }, - "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" - } - }, - "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 - }, - "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" - } - } - } - }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -23576,21 +22590,6 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -23653,18 +22652,6 @@ } } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", - "dev": true - }, "fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -23858,39 +22845,6 @@ } } }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", - "dev": true, - "requires": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" - } - }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -23966,11 +22920,6 @@ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==" - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -24017,15 +22966,6 @@ "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, "hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -24275,12 +23215,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", @@ -24316,12 +23250,6 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -24510,12 +23438,6 @@ "call-bind": "^1.0.2" } }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", - "dev": true - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -24544,12 +23466,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "devOptional": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -24893,72 +23809,6 @@ } } }, - "jest-dev-server": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-6.1.1.tgz", - "integrity": "sha512-z5LnaGDvlIkdMv/rppSO4+rq+GyQKf1xI9oiBxf9/2EBeN2hxRaWiMvaLNDnHPZj2PAhBXsycrKslDDoZO2Xtw==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "find-process": "^1.4.7", - "prompts": "^2.4.2", - "spawnd": "^6.0.2", - "tree-kill": "^1.2.2", - "wait-on": "^6.0.1" - }, - "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" - } - }, - "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 - }, - "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" - } - } - } - }, "jest-diff": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", @@ -25124,70 +23974,6 @@ "jest-util": "^27.5.1" } }, - "jest-environment-puppeteer": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jest-environment-puppeteer/-/jest-environment-puppeteer-6.1.1.tgz", - "integrity": "sha512-Ces37g8Gdj7QaVxszeoXlvmsZxcEJN9EPUdJt8fGMLA+6ARVFKyVmFgP9xVeGyjTvzsXdtIiJdeOKMLMeD8r2A==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "jest-dev-server": "^6.1.1", - "jest-environment-node": "^27.4.4", - "merge-deep": "^3.0.3" - }, - "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" - } - }, - "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 - }, - "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" - } - } - } - }, "jest-get-type": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", @@ -25448,16 +24234,6 @@ "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", "dev": true }, - "jest-puppeteer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/jest-puppeteer/-/jest-puppeteer-6.0.3.tgz", - "integrity": "sha512-6GRdbkWwNu8dfzo4icpwc50+K5ECYpWyD9sxpRa03PA8Hi3byl0dcAx+NjCivSezWjAl2Iwwhujqb+bczei0Bg==", - "dev": true, - "requires": { - "expect-puppeteer": "^6.0.2", - "jest-environment-puppeteer": "^6.0.3" - } - }, "jest-regex-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", @@ -26153,10 +24929,9 @@ } }, "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==" }, "json-parse-even-better-errors": { "version": "2.3.1", @@ -26277,15 +25052,6 @@ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -26349,12 +25115,6 @@ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "dev": true - }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -26722,17 +25482,6 @@ "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, - "merge-deep": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", - "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" - } - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -26844,35 +25593,11 @@ "yallist": "^4.0.0" } }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", - "dev": true, - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==", - "dev": true - } - } - }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, "mqemitter": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/mqemitter/-/mqemitter-4.5.0.tgz", @@ -27381,12 +26106,6 @@ "word-wrap": "^1.2.3" } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true - }, "ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", @@ -27473,12 +26192,6 @@ "lines-and-columns": "^1.1.6" } }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true - }, "parse5": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", @@ -27496,16 +26209,6 @@ "parse5": "^7.0.0" } }, - "parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" - }, - "parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" - }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -27811,12 +26514,6 @@ "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", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "prom-client": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.2.0.tgz", @@ -27872,12 +26569,6 @@ "ipaddr.js": "1.9.1" } }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -27898,59 +26589,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "puppeteer": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.1.3.tgz", - "integrity": "sha512-nqcJNThLUG0Dgo++2mMtGR2FCyg7olJJhj/rm0A65muyN3nrH6lGvnNRzEaNmSnHWvjaDIG9ox5kxQB+nXTg5A==", - "dev": true, - "requires": { - "debug": "4.3.2", - "devtools-protocol": "0.0.948846", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", - "node-fetch": "2.6.7", - "pkg-dir": "4.2.0", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.2.3" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true - } - } - }, "qlobber": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/qlobber/-/qlobber-5.0.3.tgz", @@ -28447,16 +27085,6 @@ } } }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", - "dev": true, - "requires": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" - } - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -28698,35 +27326,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==", - "dev": true, - "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==", - "dev": true, - "requires": { - "is-buffer": "^1.0.2" - } - }, - "lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==", - "dev": true - } - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -28818,54 +27417,40 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socket.io": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", - "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.1.0", - "socket.io-adapter": "~2.3.3", - "socket.io-parser": "~4.0.4" + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" } }, "socket.io-adapter": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", - "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" }, "socket.io-client": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", - "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.3.tgz", + "integrity": "sha512-I/hqDYpQ6JKwtJOf5ikM+Qz+YujZPMEl6qBLhxiP0nX+TfXKhW4KZZG8lamrD6Y5ngjmYHreESVasVCgi5Kl3A==", "requires": { - "@socket.io/component-emitter": "~3.0.0", - "backo2": "~1.0.2", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", - "engine.io-client": "~6.1.1", - "parseuri": "0.0.6", - "socket.io-parser": "~4.1.1" - }, - "dependencies": { - "socket.io-parser": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.2.tgz", - "integrity": "sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog==", - "requires": { - "@socket.io/component-emitter": "~3.0.0", - "debug": "~4.3.1" - } - } + "engine.io-client": "~6.2.3", + "socket.io-parser": "~4.2.0" } }, "socket.io-parser": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", - "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", "requires": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, @@ -28928,17 +27513,6 @@ "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", "dev": true }, - "spawnd": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-6.0.2.tgz", - "integrity": "sha512-+YJtx0dvy2wt304MrHD//tASc84zinBUYU1jacPBzrjhZUd7RsDo25krxr4HUHAQzEQFuMAs4/p+yLYU5ciZ1w==", - "dev": true, - "requires": { - "exit": "^0.1.2", - "signal-exit": "^3.0.6", - "tree-kill": "^1.2.2" - } - }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -29363,39 +27937,6 @@ "yallist": "^4.0.0" } }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - }, - "dependencies": { - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - } - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, "tarn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", @@ -29704,16 +28245,6 @@ "which-boxed-primitive": "^1.0.2" } }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -30139,15 +28670,15 @@ } }, "vue-i18n": { - "version": "9.1.10", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz", - "integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz", + "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==", "dev": true, "requires": { - "@intlify/core-base": "9.1.10", - "@intlify/shared": "9.1.10", - "@intlify/vue-devtools": "9.1.10", - "@vue/devtools-api": "^6.0.0-beta.7" + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2", + "@vue/devtools-api": "^6.2.1" } }, "vue-image-crop-upload": { @@ -30490,11 +29021,6 @@ "fd-slicer": "~1.1.0" } }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==" - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 219042aa..c7de137e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.18.0", + "version": "1.19.0-beta.0", "license": "MIT", "repository": { "type": "git", @@ -22,12 +22,11 @@ "start": "npm run start-server", "start-server": "node server/server.js", "start-server-dev": "cross-env NODE_ENV=development node server/server.js", + "start-server-watch-dev": "cross-env NODE_ENV=development node --watch server/server.js", "build": "vite build --config ./config/vite.config.js", - "test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test", + "test": "node test/prepare-test-server.js && npm run jest-backend", "test-with-build": "npm run build && npm test", - "jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend", - "jest-frontend": "cross-env TEST_FRONTEND=1 jest --config=./config/jest-frontend.config.js", - "jest-backend": "cross-env TEST_BACKEND=1 jest --config=./config/jest-backend.config.js", + "jest-backend": "cross-env TEST_BACKEND=1 jest --runInBand --detectOpenHandles --forceExit --config=./config/jest-backend.config.js", "tsc": "tsc", "vite-preview-dist": "vite preview --host --config ./config/vite.config.js", "build-docker": "npm run build && npm run build-docker-debian && npm run build-docker-alpine", @@ -40,7 +39,7 @@ "build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain", "build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push", "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.18.0 && npm ci --production && npm run download-dist", + "setup": "git checkout 1.18.5 && 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", @@ -53,8 +52,7 @@ "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", + "update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix", "ncu-patch": "npm-check-updates -u -t patch", "release-final": "node extra/update-version.js && npm run build-docker && node ./extra/press-any-key.js && npm run upload-artifacts && node ./extra/update-wiki-version.js", "release-beta": "node extra/beta/update-version.js && npm run build && node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:beta . --target release --push && node ./extra/press-any-key.js && npm run upload-artifacts", @@ -62,52 +60,54 @@ "build-dist-and-restart": "npm run build && npm run start-server-dev", "start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev", "cy:test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --e2e", - "cy:run": "npx cypress run --browser chrome --headless" + "cy:run": "npx cypress run --browser chrome --headless --config-file ./config/cypress.config.js", + "cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"" }, "dependencies": { - "@louislam/sqlite3": "~15.0.6", + "@louislam/sqlite3": "15.1.2", "args-parser": "~1.3.0", "axios": "~0.27.0", - "axios-ntlm": "^1.3.0", - "badge-maker": "^3.3.1", + "axios-ntlm": "~1.3.0", + "badge-maker": "~3.3.1", "bcryptjs": "~2.4.3", "bree": "~7.1.5", "cacheable-lookup": "~6.0.4", - "chardet": "^1.3.0", + "chardet": "~1.4.0", "check-password-strength": "^2.0.5", - "cheerio": "^1.0.0-rc.10", - "chroma-js": "^2.1.2", + "cheerio": "~1.0.0-rc.12", + "chroma-js": "~2.4.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", - "compression": "^1.7.4", - "dayjs": "^1.11.0", + "compression": "~1.7.4", + "dayjs": "~1.11.5", "express": "~4.17.3", "express-basic-auth": "~1.2.1", - "express-static-gzip": "^2.1.7", + "express-static-gzip": "~2.1.7", "form-data": "~4.0.0", "http-graceful-shutdown": "~3.1.7", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "iconv-lite": "^0.6.3", + "http-proxy-agent": "~5.0.0", + "https-proxy-agent": "~5.0.1", + "iconv-lite": "~0.6.3", + "jsesc": "~3.0.2", "jsonwebtoken": "~8.5.1", - "jwt-decode": "^3.1.2", - "limiter": "^2.1.0", - "mqtt": "^4.2.8", - "mssql": "^8.1.0", + "jwt-decode": "~3.1.2", + "limiter": "~2.1.0", + "mqtt": "~4.3.7", + "mssql": "~8.1.4", "node-cloudflared-tunnel": "~1.0.9", - "node-radius-client": "^1.0.0", + "node-radius-client": "~1.0.0", "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", - "pg": "^8.7.3", - "pg-connection-string": "^2.5.0", + "pg": "~8.8.0", + "pg-connection-string": "~2.5.0", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", "redbean-node": "0.1.4", - "socket.io": "~4.4.1", - "socket.io-client": "~4.4.1", + "socket.io": "~4.5.3", + "socket.io-client": "~4.5.3", "socks-proxy-agent": "6.1.1", - "tar": "^6.1.11", + "tar": "~6.1.11", "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2" }, @@ -124,6 +124,7 @@ "@vitejs/plugin-legacy": "~2.1.0", "@vitejs/plugin-vue": "~3.1.0", "@vue/compiler-sfc": "~3.2.36", + "@vuepic/vue-datepicker": "~3.4.8", "aedes": "^0.46.3", "babel-plugin-rewire": "~1.2.0", "bootstrap": "5.1.3", @@ -137,20 +138,18 @@ "dns2": "~2.0.1", "eslint": "~8.14.0", "eslint-plugin-vue": "~8.7.1", - "favico.js": "^0.3.10", + "favico.js": "~0.3.10", "jest": "~27.2.5", - "jest-puppeteer": "~6.0.3", "postcss-html": "~1.5.0", "postcss-rtlcss": "~3.7.2", "postcss-scss": "~4.0.4", - "prismjs": "^1.27.0", - "puppeteer": "~13.1.3", + "prismjs": "~1.29.0", "qrcode": "~1.5.0", "rollup-plugin-visualizer": "^5.6.0", "sass": "~1.42.1", "stylelint": "~14.7.1", "stylelint-config-standard": "~25.0.0", - "terser": "^5.15.0", + "terser": "~5.15.0", "timezones-list": "~3.0.1", "typescript": "~4.4.4", "v-pagination-3": "~0.1.7", @@ -160,10 +159,10 @@ "vue-chart-3": "3.0.9", "vue-confirm-dialog": "~1.0.2", "vue-contenteditable": "~3.0.4", - "vue-i18n": "~9.1.9", + "vue-i18n": "~9.2.2", "vue-image-crop-upload": "~3.0.3", "vue-multiselect": "~3.0.0-alpha.2", - "vue-prism-editor": "^2.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", diff --git a/server/client.js b/server/client.js index a0c52e1e..ef96c7f4 100644 --- a/server/client.js +++ b/server/client.js @@ -4,7 +4,8 @@ const { TimeLogger } = require("../src/util"); const { R } = require("redbean-node"); const { UptimeKumaServer } = require("./uptime-kuma-server"); -const io = UptimeKumaServer.getInstance().io; +const server = UptimeKumaServer.getInstance(); +const io = server.io; const { setting } = require("./util-server"); const checkVersion = require("./check-version"); @@ -121,7 +122,9 @@ async function sendInfo(socket) { socket.emit("info", { version: checkVersion.version, latestVersion: checkVersion.latestVersion, - primaryBaseURL: await setting("primaryBaseURL") + primaryBaseURL: await setting("primaryBaseURL"), + serverTimezone: await server.getTimezone(), + serverTimezoneOffset: server.getTimezoneOffset(), }); } diff --git a/server/database.js b/server/database.js index b1a23a47..16f12445 100644 --- a/server/database.js +++ b/server/database.js @@ -64,6 +64,7 @@ class Database { "patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] }, "patch-add-radius-monitor.sql": true, "patch-monitor-add-resend-interval.sql": true, + "patch-maintenance-table2.sql": true, }; /** diff --git a/server/docker.js b/server/docker.js index 177fa6cb..ff231502 100644 --- a/server/docker.js +++ b/server/docker.js @@ -75,7 +75,7 @@ class DockerHost { if (dockerHost.dockerType === "socket") { options.socketPath = dockerHost.dockerDaemon; } else if (dockerHost.dockerType === "tcp") { - options.baseURL = dockerHost.dockerDaemon; + options.baseURL = DockerHost.patchDockerURL(dockerHost.dockerDaemon); } let res = await axios.request(options); @@ -99,6 +99,18 @@ class DockerHost { } } + + /** + * Since axios 0.27.X, it does not accept `tcp://` protocol. + * Change it to `http://` on the fly in order to fix it. (https://github.com/louislam/uptime-kuma/issues/2165) + */ + static patchDockerURL(url) { + if (typeof url === "string") { + // Replace the first occurrence only with g + return url.replace(/tcp:\/\//g, "http://"); + } + return url; + } } module.exports = { diff --git a/server/model/heartbeat.js b/server/model/heartbeat.js index a0b40d08..b7847f87 100644 --- a/server/model/heartbeat.js +++ b/server/model/heartbeat.js @@ -1,8 +1,3 @@ -const dayjs = require("dayjs"); -const utc = require("dayjs/plugin/utc"); -let timezone = require("dayjs/plugin/timezone"); -dayjs.extend(utc); -dayjs.extend(timezone); const { BeanModel } = require("redbean-node/dist/bean-model"); /** @@ -10,6 +5,7 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); * 0 = DOWN * 1 = UP * 2 = PENDING + * 3 = MAINTENANCE */ class Heartbeat extends BeanModel { diff --git a/server/model/maintenance.js b/server/model/maintenance.js new file mode 100644 index 00000000..35030801 --- /dev/null +++ b/server/model/maintenance.js @@ -0,0 +1,215 @@ +const { BeanModel } = require("redbean-node/dist/bean-model"); +const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC, log } = require("../../src/util"); +const { timeObjectToUTC, timeObjectToLocal } = require("../util-server"); +const { R } = require("redbean-node"); +const dayjs = require("dayjs"); + +class Maintenance extends BeanModel { + + /** + * Return an object that ready to parse to JSON for public + * Only show necessary data to public + * @returns {Object} + */ + async toPublicJSON() { + + let dateRange = []; + if (this.start_date) { + dateRange.push(utcToLocal(this.start_date)); + if (this.end_date) { + dateRange.push(utcToLocal(this.end_date)); + } + } + + let timeRange = []; + let startTime = timeObjectToLocal(parseTimeObject(this.start_time)); + timeRange.push(startTime); + let endTime = timeObjectToLocal(parseTimeObject(this.end_time)); + timeRange.push(endTime); + + let obj = { + id: this.id, + title: this.title, + description: this.description, + strategy: this.strategy, + intervalDay: this.interval_day, + active: !!this.active, + dateRange: dateRange, + timeRange: timeRange, + weekdays: (this.weekdays) ? JSON.parse(this.weekdays) : [], + daysOfMonth: (this.days_of_month) ? JSON.parse(this.days_of_month) : [], + timeslotList: [], + }; + + const timeslotList = await this.getTimeslotList(); + + for (let timeslot of timeslotList) { + obj.timeslotList.push(await timeslot.toPublicJSON()); + } + + if (!Array.isArray(obj.weekdays)) { + obj.weekdays = []; + } + + if (!Array.isArray(obj.daysOfMonth)) { + obj.daysOfMonth = []; + } + + // Maintenance Status + if (!obj.active) { + obj.status = "inactive"; + } else if (obj.strategy === "manual") { + obj.status = "under-maintenance"; + } else if (obj.timeslotList.length > 0) { + let currentTimestamp = dayjs().unix(); + + for (let timeslot of obj.timeslotList) { + if (dayjs.utc(timeslot.startDate).unix() <= currentTimestamp && dayjs.utc(timeslot.endDate).unix() >= currentTimestamp) { + log.debug("timeslot", "Timeslot ID: " + timeslot.id); + log.debug("timeslot", "currentTimestamp:" + currentTimestamp); + log.debug("timeslot", "timeslot.start_date:" + dayjs.utc(timeslot.startDate).unix()); + log.debug("timeslot", "timeslot.end_date:" + dayjs.utc(timeslot.endDate).unix()); + + obj.status = "under-maintenance"; + break; + } + } + + if (!obj.status) { + obj.status = "scheduled"; + } + } else if (obj.timeslotList.length === 0) { + obj.status = "ended"; + } else { + obj.status = "unknown"; + } + + return obj; + } + + /** + * Only get future or current timeslots only + * @returns {Promise<[]>} + */ + async getTimeslotList() { + return R.convertToBeans("maintenance_timeslot", await R.getAll(` + SELECT maintenance_timeslot.* + FROM maintenance_timeslot, maintenance + WHERE maintenance_timeslot.maintenance_id = maintenance.id + AND maintenance.id = ? + AND ${Maintenance.getActiveAndFutureMaintenanceSQLCondition()} + `, [ + this.id + ])); + } + + /** + * Return an object that ready to parse to JSON + * @param {string} timezone If not specified, the timeRange will be in UTC + * @returns {Object} + */ + async toJSON(timezone = null) { + return this.toPublicJSON(timezone); + } + + getDayOfWeekList() { + log.debug("timeslot", "List: " + this.weekdays); + return JSON.parse(this.weekdays).sort(function (a, b) { + return a - b; + }); + } + + getDayOfMonthList() { + return JSON.parse(this.days_of_month).sort(function (a, b) { + return a - b; + }); + } + + getStartDateTime() { + let startOfTheDay = dayjs.utc(this.start_date).format("HH:mm"); + log.debug("timeslot", "startOfTheDay: " + startOfTheDay); + + // Start Time + let startTimeSecond = dayjs.utc(this.start_time, "HH:mm").diff(dayjs.utc(startOfTheDay, "HH:mm"), "second"); + log.debug("timeslot", "startTime: " + startTimeSecond); + + // Bake StartDate + StartTime = Start DateTime + return dayjs.utc(this.start_date).add(startTimeSecond, "second"); + } + + getDuration() { + let duration = dayjs.utc(this.end_time, "HH:mm").diff(dayjs.utc(this.start_time, "HH:mm"), "second"); + // Add 24hours if it is across day + if (duration < 0) { + duration += 24 * 3600; + } + return duration; + } + + static jsonToBean(bean, obj) { + if (obj.id) { + bean.id = obj.id; + } + + // Apply timezone offset to timeRange, as it cannot apply automatically. + if (obj.timeRange[0]) { + timeObjectToUTC(obj.timeRange[0]); + if (obj.timeRange[1]) { + timeObjectToUTC(obj.timeRange[1]); + } + } + + bean.title = obj.title; + bean.description = obj.description; + bean.strategy = obj.strategy; + bean.interval_day = obj.intervalDay; + bean.active = obj.active; + + if (obj.dateRange[0]) { + bean.start_date = localToUTC(obj.dateRange[0]); + + if (obj.dateRange[1]) { + bean.end_date = localToUTC(obj.dateRange[1]); + } + } + + bean.start_time = parseTimeFromTimeObject(obj.timeRange[0]); + bean.end_time = parseTimeFromTimeObject(obj.timeRange[1]); + + bean.weekdays = JSON.stringify(obj.weekdays); + bean.days_of_month = JSON.stringify(obj.daysOfMonth); + + return bean; + } + + /** + * SQL conditions for active maintenance + * @returns {string} + */ + static getActiveMaintenanceSQLCondition() { + return ` + + (maintenance_timeslot.start_date <= DATETIME('now') + AND maintenance_timeslot.end_date >= DATETIME('now') + AND maintenance.active = 1) + OR + (maintenance.strategy = 'manual' AND active = 1) + + `; + } + + /** + * SQL conditions for active and future maintenance + * @returns {string} + */ + static getActiveAndFutureMaintenanceSQLCondition() { + return ` + ((maintenance_timeslot.end_date >= DATETIME('now') + AND maintenance.active = 1) + OR + (maintenance.strategy = 'manual' AND active = 1)) + `; + } +} + +module.exports = Maintenance; diff --git a/server/model/maintenance_timeslot.js b/server/model/maintenance_timeslot.js new file mode 100644 index 00000000..2babe6bc --- /dev/null +++ b/server/model/maintenance_timeslot.js @@ -0,0 +1,189 @@ +const { BeanModel } = require("redbean-node/dist/bean-model"); +const { R } = require("redbean-node"); +const dayjs = require("dayjs"); +const { log, utcToLocal, SQL_DATETIME_FORMAT_WITHOUT_SECOND, localToUTC } = require("../../src/util"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); + +class MaintenanceTimeslot extends BeanModel { + + async toPublicJSON() { + const serverTimezoneOffset = UptimeKumaServer.getInstance().getTimezoneOffset(); + + const obj = { + id: this.id, + startDate: this.start_date, + endDate: this.end_date, + startDateServerTimezone: utcToLocal(this.start_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND), + endDateServerTimezone: utcToLocal(this.end_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND), + serverTimezoneOffset, + }; + + return obj; + } + + async toJSON() { + return await this.toPublicJSON(); + } + + /** + * @param {Maintenance} maintenance + * @param {dayjs} minDate (For recurring type only) Generate a next timeslot from this date. + * @param {boolean} removeExist Remove existing timeslot before create + * @returns {Promise} + */ + static async generateTimeslot(maintenance, minDate = null, removeExist = false) { + if (removeExist) { + await R.exec("DELETE FROM maintenance_timeslot WHERE maintenance_id = ? ", [ + maintenance.id + ]); + } + + if (maintenance.strategy === "manual") { + log.debug("maintenance", "No need to generate timeslot for manual type"); + + } else if (maintenance.strategy === "single") { + let bean = R.dispense("maintenance_timeslot"); + bean.maintenance_id = maintenance.id; + bean.start_date = maintenance.start_date; + bean.end_date = maintenance.end_date; + bean.generated_next = true; + return await R.store(bean); + + } else if (maintenance.strategy === "recurring-interval") { + // Prevent dead loop, in case interval_day is not set + if (!maintenance.interval_day || maintenance.interval_day <= 0) { + maintenance.interval_day = 1; + } + + return await this.handleRecurringType(maintenance, minDate, (startDateTime) => { + return startDateTime.add(maintenance.interval_day, "day"); + }, () => { + return true; + }); + + } else if (maintenance.strategy === "recurring-weekday") { + let dayOfWeekList = maintenance.getDayOfWeekList(); + log.debug("timeslot", dayOfWeekList); + + if (dayOfWeekList.length <= 0) { + log.debug("timeslot", "No weekdays selected?"); + return null; + } + + const isValid = (startDateTime) => { + log.debug("timeslot", "nextDateTime: " + startDateTime); + + let day = startDateTime.local().day(); + log.debug("timeslot", "nextDateTime.day(): " + day); + + return dayOfWeekList.includes(day); + }; + + return await this.handleRecurringType(maintenance, minDate, (startDateTime) => { + while (true) { + startDateTime = startDateTime.add(1, "day"); + + if (isValid(startDateTime)) { + return startDateTime; + } + } + }, isValid); + + } else if (maintenance.strategy === "recurring-day-of-month") { + let dayOfMonthList = maintenance.getDayOfMonthList(); + if (dayOfMonthList.length <= 0) { + log.debug("timeslot", "No day selected?"); + return null; + } + + const isValid = (startDateTime) => { + let day = parseInt(startDateTime.local().format("D")); + + log.debug("timeslot", "day: " + day); + + // Check 1-31 + if (dayOfMonthList.includes(day)) { + return startDateTime; + } + + // Check "lastDay1","lastDay2"... + let daysInMonth = startDateTime.daysInMonth(); + let lastDayList = []; + + // Small first, e.g. 28 > 29 > 30 > 31 + for (let i = 4; i >= 1; i--) { + if (dayOfMonthList.includes("lastDay" + i)) { + lastDayList.push(daysInMonth - i + 1); + } + } + log.debug("timeslot", lastDayList); + return lastDayList.includes(day); + }; + + return await this.handleRecurringType(maintenance, minDate, (startDateTime) => { + while (true) { + startDateTime = startDateTime.add(1, "day"); + if (isValid(startDateTime)) { + return startDateTime; + } + } + }, isValid); + } else { + throw new Error("Unknown maintenance strategy"); + } + } + + /** + * Generate a next timeslot for all recurring types + * @param maintenance + * @param minDate + * @param {function} nextDayCallback The logic how to get the next possible day + * @param {function} isValidCallback Check the day whether is matched the current strategy + * @returns {Promise} + */ + static async handleRecurringType(maintenance, minDate, nextDayCallback, isValidCallback) { + let bean = R.dispense("maintenance_timeslot"); + + let duration = maintenance.getDuration(); + let startDateTime = maintenance.getStartDateTime(); + let endDateTime; + + // Keep generating from the first possible date, until it is ok + while (true) { + log.debug("timeslot", "startDateTime: " + startDateTime.format()); + + // Handling out of effective date range + if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) { + log.debug("timeslot", "Out of effective date range"); + return null; + } + + endDateTime = startDateTime.add(duration, "second"); + + // If endDateTime is out of effective date range, use the end datetime from effective date range + if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) { + endDateTime = dayjs.utc(maintenance.end_date); + } + + // If minDate is set, the endDateTime must be bigger than it. + // And the endDateTime must be bigger current time + // Is valid under current recurring strategy + if ( + (!minDate || endDateTime.diff(minDate) > 0) && + endDateTime.diff(dayjs()) > 0 && + isValidCallback(startDateTime) + ) { + break; + } + startDateTime = nextDayCallback(startDateTime); + } + + bean.maintenance_id = maintenance.id; + bean.start_date = localToUTC(startDateTime); + bean.end_date = localToUTC(endDateTime); + bean.generated_next = false; + return await R.store(bean); + } +} + +module.exports = MaintenanceTimeslot; diff --git a/server/model/monitor.js b/server/model/monitor.js index f96b4df0..e8342b09 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -1,12 +1,8 @@ const https = require("https"); const dayjs = require("dayjs"); -const utc = require("dayjs/plugin/utc"); -let timezone = require("dayjs/plugin/timezone"); -dayjs.extend(utc); -dayjs.extend(timezone); const axios = require("axios"); const { Prometheus } = require("../prometheus"); -const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); +const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util"); const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm, radius } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); @@ -17,12 +13,15 @@ const version = require("../../package.json").version; const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent"); +const { DockerHost } = require("../docker"); +const Maintenance = require("./maintenance"); /** * status: * 0 = DOWN * 1 = UP * 2 = PENDING + * 3 = MAINTENANCE */ class Monitor extends BeanModel { @@ -36,6 +35,7 @@ class Monitor extends BeanModel { id: this.id, name: this.name, sendUrl: this.sendUrl, + maintenance: await Monitor.isUnderMaintenance(this.id), }; if (this.sendUrl) { @@ -95,6 +95,7 @@ class Monitor extends BeanModel { proxyId: this.proxy_id, notificationIDList, tags: tags, + maintenance: await Monitor.isUnderMaintenance(this.id), mqttUsername: this.mqttUsername, mqttPassword: this.mqttPassword, mqttTopic: this.mqttTopic, @@ -229,7 +230,10 @@ class Monitor extends BeanModel { } try { - if (this.type === "http" || this.type === "keyword") { + if (await Monitor.isUnderMaintenance(this.id)) { + bean.msg = "Monitor under maintenance"; + bean.status = MAINTENANCE; + } else if (this.type === "http" || this.type === "keyword") { // Do not do any queries/high loading things before the "bean.ping" let startTime = dayjs().valueOf(); @@ -498,7 +502,7 @@ class Monitor extends BeanModel { if (dockerHost._dockerType === "socket") { options.socketPath = dockerHost._dockerDaemon; } else if (dockerHost._dockerType === "tcp") { - options.baseURL = dockerHost._dockerDaemon; + options.baseURL = DockerHost.patchDockerURL(dockerHost._dockerDaemon); } log.debug(`[${this.name}] Axios Request`); @@ -533,6 +537,17 @@ class Monitor extends BeanModel { bean.ping = dayjs().valueOf() - startTime; } else if (this.type === "radius") { let startTime = dayjs().valueOf(); + + // Handle monitors that were created before the + // update and as such don't have a value for + // this.port. + let port; + if (this.port == null) { + port = 1812; + } else { + port = this.port; + } + try { const resp = await radius( this.hostname, @@ -540,7 +555,8 @@ class Monitor extends BeanModel { this.radiusPassword, this.radiusCalledStationId, this.radiusCallingStationId, - this.radiusSecret + this.radiusSecret, + port ); if (resp.code) { bean.msg = resp.code; @@ -593,8 +609,12 @@ class Monitor extends BeanModel { if (isImportant) { bean.important = true; - log.debug("monitor", `[${this.name}] sendNotification`); - await Monitor.sendNotification(isFirstBeat, this, bean); + if (Monitor.isImportantForNotification(isFirstBeat, previousBeat?.status, bean.status)) { + log.debug("monitor", `[${this.name}] sendNotification`); + await Monitor.sendNotification(isFirstBeat, this, bean); + } else { + log.debug("monitor", `[${this.name}] will not sendNotification because it is (or was) under maintenance`); + } // Reset down count bean.downCount = 0; @@ -603,6 +623,8 @@ class Monitor extends BeanModel { log.debug("monitor", `[${this.name}] apicache clear`); apicache.clear(); + UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id); + } else { bean.important = false; @@ -626,6 +648,8 @@ class Monitor extends BeanModel { beatInterval = this.retryInterval; } 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 if (bean.status === MAINTENANCE) { + log.warn("monitor", `Monitor #${this.id} '${this.name}': Under Maintenance | Type: ${this.type}`); } else { log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type} | Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`); } @@ -836,7 +860,7 @@ class Monitor extends BeanModel { -- SUM all uptime duration, also trim off the beat out of time window SUM( CASE - WHEN (status = 1) + WHEN (status = 1 OR status = 3) THEN CASE WHEN (JULIANDAY(\`time\`) - JULIANDAY(?)) * 86400 < duration @@ -907,11 +931,49 @@ class Monitor extends BeanModel { // DOWN -> PENDING = this case not exists // DOWN -> DOWN = not important // * DOWN -> UP = important - let isImportant = isFirstBeat || + // MAINTENANCE -> MAINTENANCE = not important + // * MAINTENANCE -> UP = important + // * MAINTENANCE -> DOWN = important + // * DOWN -> MAINTENANCE = important + // * UP -> MAINTENANCE = important + return isFirstBeat || + (previousBeatStatus === DOWN && currentBeatStatus === MAINTENANCE) || + (previousBeatStatus === UP && currentBeatStatus === MAINTENANCE) || + (previousBeatStatus === MAINTENANCE && currentBeatStatus === DOWN) || + (previousBeatStatus === MAINTENANCE && currentBeatStatus === UP) || + (previousBeatStatus === UP && currentBeatStatus === DOWN) || + (previousBeatStatus === DOWN && currentBeatStatus === UP) || + (previousBeatStatus === PENDING && currentBeatStatus === DOWN); + } + + /** + * Is this beat important for notifications? + * @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 isImportantForNotification(isFirstBeat, previousBeatStatus, currentBeatStatus) { + // * ? -> ANY STATUS = important [isFirstBeat] + // UP -> PENDING = not important + // * UP -> DOWN = important + // UP -> UP = not important + // PENDING -> PENDING = not important + // * PENDING -> DOWN = important + // PENDING -> UP = not important + // DOWN -> PENDING = this case not exists + // DOWN -> DOWN = not important + // * DOWN -> UP = important + // MAINTENANCE -> MAINTENANCE = not important + // MAINTENANCE -> UP = not important + // * MAINTENANCE -> DOWN = important + // DOWN -> MAINTENANCE = not important + // UP -> MAINTENANCE = not important + return isFirstBeat || + (previousBeatStatus === MAINTENANCE && currentBeatStatus === DOWN) || (previousBeatStatus === UP && currentBeatStatus === DOWN) || (previousBeatStatus === DOWN && currentBeatStatus === UP) || (previousBeatStatus === PENDING && currentBeatStatus === DOWN); - return isImportant; } /** @@ -1048,6 +1110,26 @@ class Monitor extends BeanModel { monitorID ]); } + + /** + * Check if monitor is under maintenance + * @param {number} monitorID ID of monitor to check + * @returns {Promise} + */ + static async isUnderMaintenance(monitorID) { + let activeCondition = Maintenance.getActiveMaintenanceSQLCondition(); + const maintenance = await R.getRow(` + SELECT COUNT(*) AS count + FROM monitor_maintenance mm + JOIN maintenance + ON mm.maintenance_id = maintenance.id + AND mm.monitor_id = ? + LEFT JOIN maintenance_timeslot + ON maintenance_timeslot.maintenance_id = maintenance.id + WHERE ${activeCondition} + LIMIT 1`, [ monitorID ]); + return maintenance.count !== 0; + } } module.exports = Monitor; diff --git a/server/model/status_page.js b/server/model/status_page.js index 82d184bf..4e7b38cf 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -2,6 +2,8 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); const { R } = require("redbean-node"); const cheerio = require("cheerio"); const { UptimeKumaServer } = require("../uptime-kuma-server"); +const jsesc = require("jsesc"); +const Maintenance = require("./maintenance"); class StatusPage extends BeanModel { @@ -56,13 +58,19 @@ class StatusPage extends BeanModel { head.append(``); // Preload data - const json = JSON.stringify(await StatusPage.getStatusPageData(statusPage)); - head.append(` - `); + head.append(script); + // manifest.json $("link[rel=manifest]").attr("href", `/api/status-page/${statusPage.slug}/manifest.json`); @@ -83,6 +91,8 @@ class StatusPage extends BeanModel { incident = incident.toPublicJSON(); } + let maintenanceList = await StatusPage.getMaintenanceList(statusPage.id); + // Public Group List const publicGroupList = []; const showTags = !!statusPage.show_tags; @@ -100,7 +110,8 @@ class StatusPage extends BeanModel { return { config: await statusPage.toPublicJSON(), incident, - publicGroupList + publicGroupList, + maintenanceList, }; } @@ -259,6 +270,36 @@ class StatusPage extends BeanModel { } } + /** + * Get list of maintenances + * @param {number} statusPageId ID of status page to get maintenance for + * @returns {Object} Object representing maintenances sanitized for public + */ + static async getMaintenanceList(statusPageId) { + try { + const publicMaintenanceList = []; + + let activeCondition = Maintenance.getActiveMaintenanceSQLCondition(); + let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(` + SELECT maintenance.* + FROM maintenance, maintenance_status_page msp, maintenance_timeslot + WHERE msp.maintenance_id = maintenance.id + AND maintenance_timeslot.maintenance_id = maintenance.id + AND msp.status_page_id = ? + AND ${activeCondition} + ORDER BY maintenance.end_date + `, [ statusPageId ])); + + for (const bean of maintenanceBeanList) { + publicMaintenanceList.push(await bean.toPublicJSON()); + } + + return publicMaintenanceList; + + } catch (error) { + return []; + } + } } module.exports = StatusPage; diff --git a/server/notification-providers/freemobile.js b/server/notification-providers/freemobile.js new file mode 100644 index 00000000..919150fa --- /dev/null +++ b/server/notification-providers/freemobile.js @@ -0,0 +1,24 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +class FreeMobile extends NotificationProvider { + + name = "FreeMobile"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + try { + await axios.post(`https://smsapi.free-mobile.fr/sendmsg?msg=${encodeURIComponent(msg.replace("🔴", "⛔️"))}`, { + "user": notification.freemobileUser, + "pass": notification.freemobilePass, + }); + + return okMsg; + + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = FreeMobile; diff --git a/server/notification-providers/ntfy.js b/server/notification-providers/ntfy.js index 64064f57..521137cd 100644 --- a/server/notification-providers/ntfy.js +++ b/server/notification-providers/ntfy.js @@ -7,18 +7,26 @@ class Ntfy extends NotificationProvider { async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { let okMsg = "Sent Successfully."; - var ntfyparams = { + try { + let headers = {}; + if (notification.ntfyusername) { + headers = { + "Authorization": "Basic " + Buffer.from(notification.ntfyusername + ":" + notification.ntfypassword).toString("base64"), + }; + } + let data = { "topic": notification.ntfytopic, "message": msg, "priority": notification.ntfyPriority || 4, "title": "Uptime-Kuma", - }; - if (notification.ntfyIcon) { - ntfyparams.icon = notification.ntfyIcon; - } + }; + + if (notification.ntfyIcon) { + data.icon = notification.ntfyIcon; + } + + await axios.post(`${notification.ntfyserverurl}`, data, { headers: headers }); - try { - await axios.post(`${notification.ntfyserverurl}`, ntfyparams); return okMsg; } catch (error) { diff --git a/server/notification-providers/octopush.js b/server/notification-providers/octopush.js index 0eda940b..d5c475d3 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, @@ -31,7 +31,7 @@ class Octopush extends NotificationProvider { "sender": notification.octopushSenderName }; await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config); - } else if (notification.octopushVersion === 1) { + } else if (notification.octopushVersion === "1") { let data = { "user_login": notification.octopushDMLogin, "api_key": notification.octopushDMAPIKey, @@ -49,7 +49,15 @@ class Octopush extends NotificationProvider { }, params: data }; - await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config); + + // V1 API returns 200 even on error so we must check + // response data + let response = await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config); + if ("error_code" in response.data) { + if (response.data.error_code !== "000") { + this.throwGeneralAxiosError(`Octopush error ${JSON.stringify(response.data)}`); + } + } } else { throw new Error("Unknown Octopush version!"); } diff --git a/server/notification-providers/smseagle.js b/server/notification-providers/smseagle.js new file mode 100644 index 00000000..c431297e --- /dev/null +++ b/server/notification-providers/smseagle.js @@ -0,0 +1,71 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +class SMSEagle extends NotificationProvider { + + name = "SMSEagle"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + + try { + let config = { + headers: { + "Content-Type": "application/json", + } + }; + + let postData; + let sendMethod; + let recipientType; + + let encoding = (notification.smseagleEncoding) ? "1" : "0"; + let priority = (notification.smseaglePriority) ? notification.smseaglePriority : "0"; + + if (notification.smseagleRecipientType === "smseagle-contact") { + recipientType = "contactname"; + sendMethod = "sms.send_tocontact"; + } + if (notification.smseagleRecipientType === "smseagle-group") { + recipientType = "groupname"; + sendMethod = "sms.send_togroup"; + } + if (notification.smseagleRecipientType === "smseagle-to") { + recipientType = "to"; + sendMethod = "sms.send_sms"; + } + + let params = { + access_token: notification.smseagleToken, + [recipientType]: notification.smseagleRecipient, + message: msg, + responsetype: "extended", + unicode: encoding, + highpriority: priority + }; + + postData = { + method: sendMethod, + params: params + }; + + let resp = await axios.post(notification.smseagleUrl + "/jsonrpc/sms", postData, config); + + if ((JSON.stringify(resp.data)).indexOf("message_id") === -1) { + let error = ""; + if (resp.data.result && resp.data.result.error_text) { + error = `SMSEagle API returned error: ${JSON.stringify(resp.data.result.error_text)}`; + } else { + error = "SMSEagle API returned an unexpected response"; + } + throw new Error(error); + } + + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = SMSEagle; diff --git a/server/notification-providers/squadcast.js b/server/notification-providers/squadcast.js new file mode 100644 index 00000000..15553ff7 --- /dev/null +++ b/server/notification-providers/squadcast.js @@ -0,0 +1,76 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +const { DOWN } = require("../../src/util"); + +class Squadcast extends NotificationProvider { + + name = "squadcast"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + + try { + + let config = {}; + let data = { + message: msg, + description: "", + tags: {}, + heartbeat: heartbeatJSON, + source: "uptime-kuma" + }; + + if (heartbeatJSON !== null) { + data.description = heartbeatJSON["msg"]; + data.event_id = heartbeatJSON["monitorID"]; + + if (heartbeatJSON["status"] === DOWN) { + data.message = `${monitorJSON["name"]} is DOWN`; + data.status = "trigger"; + } else { + data.message = `${monitorJSON["name"]} is UP`; + data.status = "resolve"; + } + + let address; + 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; + } + + data.tags["AlertAddress"] = address; + + monitorJSON["tags"].forEach(tag => { + data.tags[tag["name"]] = { + value: tag["value"] + }; + if (tag["color"] !== null) { + data.tags[tag["name"]]["color"] = tag["color"]; + } + }); + } + + await axios.post(notification.squadcastWebhookURL, data, config); + return okMsg; + + } catch (error) { + this.throwGeneralAxiosError(error); + } + + } + +} + +module.exports = Squadcast; diff --git a/server/notification-providers/teams.js b/server/notification-providers/teams.js index c398e03c..bcfc82c2 100644 --- a/server/notification-providers/teams.js +++ b/server/notification-providers/teams.js @@ -63,7 +63,7 @@ class Teams extends NotificationProvider { }); } - if (monitorUrl) { + if (monitorUrl && monitorUrl !== "https://") { facts.push({ name: "URL", value: monitorUrl, @@ -127,13 +127,17 @@ class Teams extends NotificationProvider { let url; - if (monitorJSON["type"] === "port") { - url = monitorJSON["hostname"]; - if (monitorJSON["port"]) { - url += ":" + monitorJSON["port"]; - } - } else { - url = monitorJSON["url"]; + switch (monitorJSON["type"]) { + case "http": + case "keywork": + url = monitorJSON["url"]; + break; + case "docker": + url = monitorJSON["docker_host"]; + break; + default: + url = monitorJSON["hostname"]; + break; } const payload = this._notificationPayloadFactory({ diff --git a/server/notification.js b/server/notification.js index 3bf51243..9069601b 100644 --- a/server/notification.js +++ b/server/notification.js @@ -9,6 +9,7 @@ const ClickSendSMS = require("./notification-providers/clicksendsms"); const DingDing = require("./notification-providers/dingding"); const Discord = require("./notification-providers/discord"); const Feishu = require("./notification-providers/feishu"); +const FreeMobile = require("./notification-providers/freemobile"); const GoogleChat = require("./notification-providers/google-chat"); const Gorush = require("./notification-providers/gorush"); const Gotify = require("./notification-providers/gotify"); @@ -31,7 +32,9 @@ const RocketChat = require("./notification-providers/rocket-chat"); const SerwerSMS = require("./notification-providers/serwersms"); const Signal = require("./notification-providers/signal"); const Slack = require("./notification-providers/slack"); +const SMSEagle = require("./notification-providers/smseagle"); const SMTP = require("./notification-providers/smtp"); +const Squadcast = require("./notification-providers/squadcast"); const Stackfield = require("./notification-providers/stackfield"); const Teams = require("./notification-providers/teams"); const TechulusPush = require("./notification-providers/techulus-push"); @@ -62,6 +65,7 @@ class Notification { new DingDing(), new Discord(), new Feishu(), + new FreeMobile(), new GoogleChat(), new Gorush(), new Gotify(), @@ -86,7 +90,9 @@ class Notification { new Signal(), new SMSManager(), new Slack(), + new SMSEagle(), new SMTP(), + new Squadcast(), new Stackfield(), new Teams(), new TechulusPush(), diff --git a/server/ping-lite.js b/server/ping-lite.js index b7d003b8..05dff31d 100644 --- a/server/ping-lite.js +++ b/server/ping-lite.js @@ -105,7 +105,7 @@ Ping.prototype.send = function (callback) { let _exited; let _errored; - this._ping = spawn(this._bin, this._args); // spawn the binary + this._ping = spawn(this._bin, this._args, { windowsHide: true }); // spawn the binary this._ping.on("error", function (err) { // handle binary errors _errored = true; diff --git a/server/routers/api-router.js b/server/routers/api-router.js index d71f903a..bbecbced 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -4,7 +4,7 @@ const { R } = require("redbean-node"); const apicache = require("../modules/apicache"); const Monitor = require("../model/monitor"); const dayjs = require("dayjs"); -const { UP, DOWN, flipStatus, log } = require("../../src/util"); +const { UP, MAINTENANCE, DOWN, flipStatus, log } = require("../../src/util"); const StatusPage = require("../model/status_page"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const { makeBadge } = require("badge-maker"); @@ -67,6 +67,11 @@ router.get("/api/push/:pushToken", async (request, response) => { duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second"); } + if (await Monitor.isUnderMaintenance(monitor.id)) { + msg = "Monitor under maintenance"; + status = MAINTENANCE; + } + log.debug("router", `/api/push/ called at ${dayjs().format("YYYY-MM-DD HH:mm:ss.SSS")}`); log.debug("router", "PreviousStatus: " + previousStatus); log.debug("router", "Current Status: " + status); @@ -87,7 +92,7 @@ router.get("/api/push/:pushToken", async (request, response) => { ok: true, }); - if (bean.important) { + if (Monitor.isImportantForNotification(isFirstBeat, previousStatus, status)) { await Monitor.sendNotification(isFirstBeat, monitor, bean); } diff --git a/server/server.js b/server/server.js index 0c9a45e6..888294b1 100644 --- a/server/server.js +++ b/server/server.js @@ -5,6 +5,12 @@ */ console.log("Welcome to Uptime Kuma"); +// As the log function need to use dayjs, it should be very top +const dayjs = require("dayjs"); +dayjs.extend(require("dayjs/plugin/utc")); +dayjs.extend(require("dayjs/plugin/timezone")); +dayjs.extend(require("dayjs/plugin/customParseFormat")); + // Check Node.js Version const nodeVersion = parseInt(process.versions.node.split(".")[0]); const requiredVersion = 14; @@ -33,6 +39,7 @@ log.info("server", "Importing Node libraries"); const fs = require("fs"); log.info("server", "Importing 3rd-party libraries"); + log.debug("server", "Importing express"); const express = require("express"); const expressStaticGzip = require("express-static-gzip"); @@ -127,6 +134,8 @@ const StatusPage = require("./model/status_page"); const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler"); const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler"); const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler"); +const { maintenanceSocketHandler } = require("./socket-handlers/maintenance-socket-handler"); +const { Settings } = require("./settings"); app.use(express.json()); @@ -154,8 +163,9 @@ let needSetup = false; (async () => { Database.init(args); await initDatabase(testMode); + await server.initAfterDatabaseReady(); - exports.entryPage = await setting("entryPage"); + server.entryPage = await Settings.get("entryPage"); await StatusPage.loadDomainMappingList(); log.info("server", "Adding route"); @@ -176,14 +186,15 @@ let needSetup = false; log.debug("entry", `Request Domain: ${hostname}`); + const uptimeKumaEntryPage = server.entryPage; if (hostname in StatusPage.domainMappingList) { log.debug("entry", "This is a status page domain"); let slug = StatusPage.domainMappingList[hostname]; await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug); - } else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) { - response.redirect("/status/" + exports.entryPage.replace("statusPage-", "")); + } else if (uptimeKumaEntryPage && uptimeKumaEntryPage.startsWith("statusPage-")) { + response.redirect("/status/" + uptimeKumaEntryPage.replace("statusPage-", "")); } else { response.redirect("/dashboard"); @@ -200,7 +211,7 @@ let needSetup = false; // Robots.txt app.get("/robots.txt", async (_request, response) => { let txt = "User-agent: *\nDisallow:"; - if (! await setting("searchEngineIndex")) { + if (!await setting("searchEngineIndex")) { txt += " /"; } response.setHeader("Content-Type", "text/plain"); @@ -1055,10 +1066,15 @@ let needSetup = false; socket.on("getSettings", async (callback) => { try { checkLogin(socket); + const data = await getSettings("general"); + + if (!data.serverTimezone) { + data.serverTimezone = await server.getTimezone(); + } callback({ ok: true, - data: await getSettings("general"), + data: data, }); } catch (e) { @@ -1084,7 +1100,12 @@ let needSetup = false; } await setSettings("general", data); - exports.entryPage = data.entryPage; + server.entryPage = data.entryPage; + + // Also need to apply timezone globally + if (data.serverTimezone) { + await server.setTimezone(data.serverTimezone); + } callback({ ok: true, @@ -1092,6 +1113,7 @@ let needSetup = false; }); sendInfo(socket); + server.sendMaintenanceList(socket); } catch (e) { callback({ @@ -1450,6 +1472,7 @@ let needSetup = false; databaseSocketHandler(socket); proxySocketHandler(socket); dockerSocketHandler(socket); + maintenanceSocketHandler(socket); log.debug("server", "added all socket handlers"); @@ -1552,6 +1575,7 @@ async function afterLogin(socket, user) { socket.join(user.id); let monitorList = await server.sendMonitorList(socket); + server.sendMaintenanceList(socket); sendNotificationList(socket); sendProxyList(socket); sendDockerHostList(socket); @@ -1697,6 +1721,8 @@ async function shutdownFunction(signal) { log.info("server", "Shutdown requested"); log.info("server", "Called signal: " + signal); + await server.stop(); + log.info("server", "Stopping all monitors"); for (let id in server.monitorList) { let monitor = server.monitorList[id]; diff --git a/server/socket-handlers/docker-socket-handler.js b/server/socket-handlers/docker-socket-handler.js index 5a53494d..542f18ce 100644 --- a/server/socket-handlers/docker-socket-handler.js +++ b/server/socket-handlers/docker-socket-handler.js @@ -56,7 +56,7 @@ module.exports.dockerSocketHandler = (socket) => { let amount = await DockerHost.testDockerHost(dockerHost); let msg; - if (amount > 1) { + if (amount >= 1) { msg = "Connected Successfully. Amount of containers: " + amount; } else { msg = "Connected Successfully, but there are no containers?"; diff --git a/server/socket-handlers/maintenance-socket-handler.js b/server/socket-handlers/maintenance-socket-handler.js new file mode 100644 index 00000000..5294050c --- /dev/null +++ b/server/socket-handlers/maintenance-socket-handler.js @@ -0,0 +1,311 @@ +const { checkLogin } = require("../util-server"); +const { log } = require("../../src/util"); +const { R } = require("redbean-node"); +const apicache = require("../modules/apicache"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +const Maintenance = require("../model/maintenance"); +const server = UptimeKumaServer.getInstance(); +const MaintenanceTimeslot = require("../model/maintenance_timeslot"); + +/** + * Handlers for Maintenance + * @param {Socket} socket Socket.io instance + */ +module.exports.maintenanceSocketHandler = (socket) => { + // Add a new maintenance + socket.on("addMaintenance", async (maintenance, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", maintenance); + + let bean = Maintenance.jsonToBean(R.dispense("maintenance"), maintenance); + bean.user_id = socket.userID; + let maintenanceID = await R.store(bean); + await MaintenanceTimeslot.generateTimeslot(bean); + + await server.sendMaintenanceList(socket); + + callback({ + ok: true, + msg: "Added Successfully.", + maintenanceID, + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Edit a maintenance + socket.on("editMaintenance", async (maintenance, callback) => { + try { + checkLogin(socket); + + let bean = await R.findOne("maintenance", " id = ? ", [ maintenance.id ]); + + if (bean.user_id !== socket.userID) { + throw new Error("Permission denied."); + } + + Maintenance.jsonToBean(bean, maintenance); + + await R.store(bean); + await MaintenanceTimeslot.generateTimeslot(bean, null, true); + + await server.sendMaintenanceList(socket); + + callback({ + ok: true, + msg: "Saved.", + maintenanceID: bean.id, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Add a new monitor_maintenance + socket.on("addMonitorMaintenance", async (maintenanceID, monitors, callback) => { + try { + checkLogin(socket); + + await R.exec("DELETE FROM monitor_maintenance WHERE maintenance_id = ?", [ + maintenanceID + ]); + + for await (const monitor of monitors) { + let bean = R.dispense("monitor_maintenance"); + + bean.import({ + monitor_id: monitor.id, + maintenance_id: maintenanceID + }); + await R.store(bean); + } + + apicache.clear(); + + callback({ + ok: true, + msg: "Added Successfully.", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Add a new monitor_maintenance + socket.on("addMaintenanceStatusPage", async (maintenanceID, statusPages, callback) => { + try { + checkLogin(socket); + + await R.exec("DELETE FROM maintenance_status_page WHERE maintenance_id = ?", [ + maintenanceID + ]); + + for await (const statusPage of statusPages) { + let bean = R.dispense("maintenance_status_page"); + + bean.import({ + status_page_id: statusPage.id, + maintenance_id: maintenanceID + }); + await R.store(bean); + } + + apicache.clear(); + + callback({ + ok: true, + msg: "Added Successfully.", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", `Get Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + let bean = await R.findOne("maintenance", " id = ? AND user_id = ? ", [ + maintenanceID, + socket.userID, + ]); + + callback({ + ok: true, + maintenance: await bean.toJSON(), + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMaintenanceList", async (callback) => { + try { + checkLogin(socket); + await server.sendMaintenanceList(socket); + callback({ + ok: true, + }); + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMonitorMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", `Get Monitors for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + let monitors = await R.getAll("SELECT monitor.id, monitor.name FROM monitor_maintenance mm JOIN monitor ON mm.monitor_id = monitor.id WHERE mm.maintenance_id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + monitors, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMaintenanceStatusPage", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", `Get Status Pages for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + let statusPages = await R.getAll("SELECT status_page.id, status_page.title FROM maintenance_status_page msp JOIN status_page ON msp.status_page_id = status_page.id WHERE msp.maintenance_id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + statusPages, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("deleteMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", `Delete Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + if (maintenanceID in server.maintenanceList) { + delete server.maintenanceList[maintenanceID]; + } + + await R.exec("DELETE FROM maintenance WHERE id = ? AND user_id = ? ", [ + maintenanceID, + socket.userID, + ]); + + callback({ + ok: true, + msg: "Deleted Successfully.", + }); + + await server.sendMaintenanceList(socket); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("pauseMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", `Pause Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + await R.exec("UPDATE maintenance SET active = 0 WHERE id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + msg: "Paused Successfully.", + }); + + await server.sendMaintenanceList(socket); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("resumeMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + log.debug("maintenance", `Resume Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + await R.exec("UPDATE maintenance SET active = 1 WHERE id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + msg: "Resume Successfully", + }); + + await server.sendMaintenanceList(socket); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); +}; diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 98de65a4..078cc31d 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -9,6 +9,8 @@ const Database = require("./database"); const util = require("util"); const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); const { Settings } = require("./settings"); +const dayjs = require("dayjs"); +// DO NOT IMPORT HERE IF THE MODULES USED `UptimeKumaServer.getInstance()` /** * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. @@ -26,6 +28,13 @@ class UptimeKumaServer { * @type {{}} */ monitorList = {}; + + /** + * Main maintenance list + * @type {{}} + */ + maintenanceList = {}; + entryPage = "dashboard"; app = undefined; httpServer = undefined; @@ -37,6 +46,8 @@ class UptimeKumaServer { */ indexHTML = ""; + generateMaintenanceTimeslotsInterval = undefined; + static getInstance(args) { if (UptimeKumaServer.instance == null) { UptimeKumaServer.instance = new UptimeKumaServer(args); @@ -77,6 +88,16 @@ class UptimeKumaServer { this.io = new Server(this.httpServer); } + async initAfterDatabaseReady() { + process.env.TZ = await this.getTimezone(); + dayjs.tz.setDefault(process.env.TZ); + log.debug("DEBUG", "Timezone: " + process.env.TZ); + log.debug("DEBUG", "Current Time: " + dayjs.tz().format()); + + await this.generateMaintenanceTimeslots(); + this.generateMaintenanceTimeslotsInterval = setInterval(this.generateMaintenanceTimeslots, 60 * 1000); + } + async sendMonitorList(socket) { let list = await this.getMonitorJSONList(socket.userID); this.io.to(socket.userID).emit("monitorList", list); @@ -104,6 +125,40 @@ class UptimeKumaServer { return result; } + /** + * Send maintenance list to client + * @param {Socket} socket Socket.io instance to send to + * @returns {Object} + */ + async sendMaintenanceList(socket) { + return await this.sendMaintenanceListByUserID(socket.userID); + } + + async sendMaintenanceListByUserID(userID) { + let list = await this.getMaintenanceJSONList(userID); + this.io.to(userID).emit("maintenanceList", list); + return list; + } + + /** + * Get a list of maintenances for the given user. + * @param {string} userID - The ID of the user to get maintenances for. + * @returns {Promise} A promise that resolves to an object with maintenance IDs as keys and maintenances objects as values. + */ + async getMaintenanceJSONList(userID) { + let result = {}; + + let maintenanceList = await R.find("maintenance", " user_id = ? ORDER BY end_date DESC, title", [ + userID, + ]); + + for (let maintenance of maintenanceList) { + result[maintenance.id] = await maintenance.toJSON(); + } + + return result; + } + /** * Write error to log file * @param {any} error The error to write @@ -138,15 +193,58 @@ class UptimeKumaServer { } if (await Settings.get("trustProxy")) { - return socket.client.conn.request.headers["x-forwarded-for"] + const forwardedFor = socket.client.conn.request.headers["x-forwarded-for"]; + + return (typeof forwardedFor === "string" ? forwardedFor.split(",")[0].trim() : null) || socket.client.conn.request.headers["x-real-ip"] || clientIP.replace(/^.*:/, ""); } else { return clientIP.replace(/^.*:/, ""); } } + + async getTimezone() { + let timezone = await Settings.get("serverTimezone"); + if (timezone) { + return timezone; + } else if (process.env.TZ) { + return process.env.TZ; + } else { + return dayjs.tz.guess(); + } + } + + getTimezoneOffset() { + return dayjs().format("Z"); + } + + async setTimezone(timezone) { + await Settings.set("serverTimezone", timezone, "general"); + process.env.TZ = timezone; + dayjs.tz.setDefault(timezone); + } + + async generateMaintenanceTimeslots() { + + let list = await R.find("maintenance_timeslot", " generated_next = 0 AND start_date <= DATETIME('now') "); + + for (let maintenanceTimeslot of list) { + let maintenance = await maintenanceTimeslot.maintenance; + await MaintenanceTimeslot.generateTimeslot(maintenance, maintenanceTimeslot.end_date, false); + maintenanceTimeslot.generated_next = true; + await R.store(maintenanceTimeslot); + } + + } + + async stop() { + clearTimeout(this.generateMaintenanceTimeslotsInterval); + } } module.exports = { UptimeKumaServer }; + +// Must be at the end +const MaintenanceTimeslot = require("./model/maintenance_timeslot"); diff --git a/server/util-server.js b/server/util-server.js index 1517bcfe..39adcccd 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -21,6 +21,7 @@ const { rfc2865: { file, attributes }, }, } = require("node-radius-utils"); +const dayjs = require("dayjs"); // From ping-lite exports.WIN = /^win/.test(process.platform); @@ -291,6 +292,17 @@ exports.postgresQuery = function (connectionString, query) { }); }; +/** + * Query radius server + * @param {string} hostname Hostname of radius server + * @param {string} username Username to use + * @param {string} password Password to use + * @param {string} calledStationId ID of called station + * @param {string} callingStationId ID of calling station + * @param {string} secret Secret to use + * @param {number} [port=1812] Port to contact radius server on + * @returns {Promise} + */ exports.radius = function ( hostname, username, @@ -298,9 +310,11 @@ exports.radius = function ( calledStationId, callingStationId, secret, + port = 1812, ) { const client = new radiusClient({ host: hostname, + hostPort: port, dictionaries: [ file ], }); @@ -557,7 +571,7 @@ exports.doubleCheckPassword = async (socket, currentPassword) => { exports.startUnitTest = async () => { console.log("Starting unit test..."); const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm"; - const child = childProcess.spawn(npm, [ "run", "jest" ]); + const child = childProcess.spawn(npm, [ "run", "jest-backend" ]); child.stdout.on("data", (data) => { console.log(data.toString()); @@ -645,3 +659,64 @@ module.exports.send403 = (res, msg = "") => { "msg": msg, }); }; + +function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) { + let offsetString; + + if (timezone) { + offsetString = dayjs().tz(timezone).format("Z"); + } else { + offsetString = dayjs().format("Z"); + } + + let hours = parseInt(offsetString.substring(1, 3)); + let minutes = parseInt(offsetString.substring(4, 6)); + + if ( + (timeObjectToUTC && offsetString.startsWith("+")) || + (!timeObjectToUTC && offsetString.startsWith("-")) + ) { + hours *= -1; + minutes *= -1; + } + + obj.hours += hours; + obj.minutes += minutes; + + // Handle out of bound + if (obj.minutes < 0) { + obj.minutes += 60; + obj.hours--; + } else if (obj.minutes > 60) { + obj.minutes -= 60; + obj.hours++; + } + + if (obj.hours < 0) { + obj.hours += 24; + } else if (obj.hours > 24) { + obj.hours -= 24; + } + + return obj; +} + +/** + * + * @param {object} obj + * @param {string} timezone + * @returns {object} + */ +module.exports.timeObjectToUTC = (obj, timezone = undefined) => { + return timeObjectConvertTimezone(obj, timezone, true); +}; + +/** + * + * @param {object} obj + * @param {string} timezone + * @returns {object} + */ +module.exports.timeObjectToLocal = (obj, timezone = undefined) => { + return timeObjectConvertTimezone(obj, timezone, false); +}; diff --git a/src/assets/app.scss b/src/assets/app.scss index bf8e7004..7da76fff 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -22,6 +22,19 @@ textarea.form-control { width: 10px; } +.bg-maintenance { + color: white !important; + background-color: $maintenance !important; +} + +.bg-dark { + color: white; +} + +.text-maintenance { + color: $maintenance !important; +} + .list-group { border-radius: 0.75rem; @@ -107,6 +120,19 @@ optgroup { } } +.btn-normal { + $bg-color: #F5F5F5; + + background-color: $bg-color; + border-color: $bg-color; + + &:hover { + $hover-color: darken($bg-color, 3%); + background-color: $hover-color; + border-color: $hover-color; + } +} + .btn-warning { color: white; @@ -256,6 +282,20 @@ optgroup { color: white; } + .btn-normal { + $bg-color: $dark-header-bg; + + color: $dark-font-color; + background-color: $bg-color; + border-color: $bg-color; + + &:hover { + $hover-color: darken($bg-color, 3%); + background-color: $hover-color; + border-color: $hover-color; + } + } + .btn-warning { color: $dark-font-color2; @@ -323,6 +363,7 @@ optgroup { &.bg-info, &.bg-warning, &.bg-danger, + &.bg-maintenance, &.bg-light { color: $dark-font-color2; } diff --git a/src/assets/vars.scss b/src/assets/vars.scss index 91ab917e..e48a6efb 100644 --- a/src/assets/vars.scss +++ b/src/assets/vars.scss @@ -1,6 +1,7 @@ $primary: #5cdd8b; $danger: #dc3545; $warning: #f8a306; +$maintenance: #1747f5; $link-color: #111; $border-radius: 50rem; diff --git a/src/assets/vue-datepicker.scss b/src/assets/vue-datepicker.scss new file mode 100644 index 00000000..dedbc080 --- /dev/null +++ b/src/assets/vue-datepicker.scss @@ -0,0 +1,39 @@ +@import "@vuepic/vue-datepicker/dist/main.css"; +@import "vars.scss"; + +// Must use #{ } +// Remark: https://stackoverflow.com/questions/50202991/unable-to-set-scss-variable-to-css-variable +.dp__theme_dark { + --dp-background-color: #{$dark-bg2}; + --dp-text-color: #{$dark-font-color}; + --dp-hover-color: #484848; + --dp-hover-text-color: #ffffff; + --dp-hover-icon-color: #959595; + --dp-primary-color: #{#5cdd8b}; + --dp-primary-text-color: #ffffff; + --dp-secondary-color: #494949; + --dp-border-color: #{$dark-border-color}; + --dp-menu-border-color: #2d2d2d; + --dp-border-color-hover: #{$dark-border-color}; + --dp-disabled-color: #212121; + --dp-scroll-bar-background: #212121; + --dp-scroll-bar-color: #484848; + --dp-success-color: #{$primary}; + --dp-success-color-disabled: #428f59; + --dp-icon-color: #959595; + --dp-danger-color: #e53935; + --dp-highlight-color: rgba(0, 92, 178, 0.2); +} + +.dp__input { + border-radius: $border-radius; +} + +// Fix: Full width of text input when using "inline textInput inlineWithInput" mode +.dp__main > div[aria-label="Datepicker input"] { + width: 100%; +} + +.dp__main > div[aria-label="Datepicker menu"]:nth-child(2) { + margin-top: 20px; +} diff --git a/src/components/Datetime.vue b/src/components/Datetime.vue index b24ab0b3..0d4e182c 100644 --- a/src/components/Datetime.vue +++ b/src/components/Datetime.vue @@ -3,14 +3,6 @@ + + diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue index e472d898..2733e68c 100644 --- a/src/components/PingChart.vue +++ b/src/components/PingChart.vue @@ -16,18 +16,14 @@ - diff --git a/src/components/notifications/SMSManager.vue b/src/components/notifications/SMSManager.vue index 25db624f..1be952ae 100644 --- a/src/components/notifications/SMSManager.vue +++ b/src/components/notifications/SMSManager.vue @@ -2,7 +2,7 @@
- {{ $t("SMSManager API Docs ") }} + {{ $t("SMSManager API Docs") }} {{ $t("here") }}
diff --git a/src/components/notifications/SMTP.vue b/src/components/notifications/SMTP.vue index 899f8f9b..54470796 100644 --- a/src/components/notifications/SMTP.vue +++ b/src/components/notifications/SMTP.vue @@ -34,7 +34,7 @@
- +
diff --git a/src/components/notifications/ServerChan.vue b/src/components/notifications/ServerChan.vue index cec75675..c7476c20 100644 --- a/src/components/notifications/ServerChan.vue +++ b/src/components/notifications/ServerChan.vue @@ -1,7 +1,7 @@ diff --git a/src/components/notifications/SerwerSMS.vue b/src/components/notifications/SerwerSMS.vue index f2c3463b..32a0ff7a 100644 --- a/src/components/notifications/SerwerSMS.vue +++ b/src/components/notifications/SerwerSMS.vue @@ -5,7 +5,7 @@
- +
diff --git a/src/components/notifications/Squadcast.vue b/src/components/notifications/Squadcast.vue new file mode 100644 index 00000000..6650c44d --- /dev/null +++ b/src/components/notifications/Squadcast.vue @@ -0,0 +1,6 @@ + diff --git a/src/components/notifications/TechulusPush.vue b/src/components/notifications/TechulusPush.vue index 86d4e5fe..bece17e2 100644 --- a/src/components/notifications/TechulusPush.vue +++ b/src/components/notifications/TechulusPush.vue @@ -1,7 +1,7 @@