From 5f70fa6bafb7c98ec772259016d967f5fa0ee5d4 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Mon, 23 Oct 2023 19:30:58 +0800 Subject: [PATCH] wip --- .editorconfig | 24 + .eslintrc.cjs | 96 + .gitignore | 8 + README.md | 20 + backend/check-version.ts | 71 + backend/database.ts | 247 + backend/docker.ts | 3 + backend/dockge-server.ts | 381 ++ backend/index.ts | 6 + backend/log.ts | 208 + .../2023-10-20-0829-setting-table.ts | 14 + .../migrations/2023-10-20-0829-user-table.ts | 19 + backend/models/user.ts | 44 + backend/password-hash.ts | 47 + backend/rate-limiter.ts | 75 + backend/router.ts | 6 + backend/routers/main-router.ts | 16 + backend/settings.ts | 174 + backend/socket-handler.ts | 6 + .../socket-handlers/docker-socket-handler.ts | 61 + .../socket-handlers/main-socket-handler.ts | 220 + backend/terminal.ts | 43 + backend/util-common.ts | 118 + backend/util-server.ts | 11 + backend/utils/limit-queue.ts | 24 + docker/Base.Dockerfile | 20 + docker/Dockerfile | 15 + frontend/components.d.ts | 20 + frontend/index.html | 33 + frontend/public/favicon.ico | Bin 0 -> 15086 bytes frontend/public/icon-192x192.png | Bin 0 -> 2707 bytes frontend/public/icon-512x512.png | Bin 0 -> 9739 bytes frontend/public/icon.svg | 14 + frontend/public/manifest.json | 19 + frontend/src/App.vue | 9 + frontend/src/components/Confirm.vue | 84 + frontend/src/components/Login.vue | 146 + frontend/src/components/StackList.vue | 455 ++ frontend/src/components/StackListItem.vue | 261 + frontend/src/i18n.ts | 35 + frontend/src/icon.ts | 107 + frontend/src/lang/en.json | 12 + frontend/src/layouts/EmptyLayout.vue | 8 + frontend/src/layouts/Layout.vue | 326 ++ frontend/src/main.ts | 118 + frontend/src/mixins/lang.ts | 39 + frontend/src/mixins/socket.ts | 281 + frontend/src/mixins/theme.ts | 80 + frontend/src/pages/Compose.vue | 16 + frontend/src/pages/Console.vue | 35 + frontend/src/pages/Dashboard.vue | 42 + frontend/src/pages/DashboardHome.vue | 158 + frontend/src/pages/EditStack.vue | 14 + frontend/src/pages/Setup.vue | 138 + frontend/src/router.ts | 49 + frontend/src/styles/localization.scss | 9 + frontend/src/styles/main.scss | 664 +++ frontend/src/styles/vars.scss | 26 + frontend/src/util-frontend.ts | 214 + frontend/src/vite-env.d.ts | 7 + frontend/vite.config.ts | 33 + package.json | 66 + pnpm-lock.yaml | 4928 +++++++++++++++++ tsconfig.json | 8 + 64 files changed, 10431 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintrc.cjs create mode 100644 .gitignore create mode 100644 backend/check-version.ts create mode 100644 backend/database.ts create mode 100644 backend/docker.ts create mode 100644 backend/dockge-server.ts create mode 100644 backend/index.ts create mode 100644 backend/log.ts create mode 100644 backend/migrations/2023-10-20-0829-setting-table.ts create mode 100644 backend/migrations/2023-10-20-0829-user-table.ts create mode 100644 backend/models/user.ts create mode 100644 backend/password-hash.ts create mode 100644 backend/rate-limiter.ts create mode 100644 backend/router.ts create mode 100644 backend/routers/main-router.ts create mode 100644 backend/settings.ts create mode 100644 backend/socket-handler.ts create mode 100644 backend/socket-handlers/docker-socket-handler.ts create mode 100644 backend/socket-handlers/main-socket-handler.ts create mode 100644 backend/terminal.ts create mode 100644 backend/util-common.ts create mode 100644 backend/util-server.ts create mode 100644 backend/utils/limit-queue.ts create mode 100644 docker/Base.Dockerfile create mode 100644 docker/Dockerfile create mode 100644 frontend/components.d.ts create mode 100644 frontend/index.html create mode 100644 frontend/public/favicon.ico create mode 100644 frontend/public/icon-192x192.png create mode 100644 frontend/public/icon-512x512.png create mode 100644 frontend/public/icon.svg create mode 100644 frontend/public/manifest.json create mode 100644 frontend/src/App.vue create mode 100644 frontend/src/components/Confirm.vue create mode 100644 frontend/src/components/Login.vue create mode 100644 frontend/src/components/StackList.vue create mode 100644 frontend/src/components/StackListItem.vue create mode 100644 frontend/src/i18n.ts create mode 100644 frontend/src/icon.ts create mode 100644 frontend/src/lang/en.json create mode 100644 frontend/src/layouts/EmptyLayout.vue create mode 100644 frontend/src/layouts/Layout.vue create mode 100644 frontend/src/main.ts create mode 100644 frontend/src/mixins/lang.ts create mode 100644 frontend/src/mixins/socket.ts create mode 100644 frontend/src/mixins/theme.ts create mode 100644 frontend/src/pages/Compose.vue create mode 100644 frontend/src/pages/Console.vue create mode 100644 frontend/src/pages/Dashboard.vue create mode 100644 frontend/src/pages/DashboardHome.vue create mode 100644 frontend/src/pages/EditStack.vue create mode 100644 frontend/src/pages/Setup.vue create mode 100644 frontend/src/router.ts create mode 100644 frontend/src/styles/localization.scss create mode 100644 frontend/src/styles/main.scss create mode 100644 frontend/src/styles/vars.scss create mode 100644 frontend/src/util-frontend.ts create mode 100644 frontend/src/vite-env.d.ts create mode 100644 frontend/vite.config.ts create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..47bf476 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.yaml] +indent_size = 2 + +[*.yml] +indent_size = 2 + +[*.vue] +trim_trailing_whitespace = false + +[*.go] +indent_style = tab diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..6ac287f --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,96 @@ +module.exports = { + root: true, + env: { + browser: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:vue/vue3-recommended", + ], + parser: "vue-eslint-parser", + parserOptions: { + "parser": "@typescript-eslint/parser", + }, + plugins: [ + "@typescript-eslint", + "jsdoc" + ], + rules: { + "yoda": "error", + "linebreak-style": [ "error", "unix" ], + "camelcase": [ "warn", { + "properties": "never", + "ignoreImports": true + }], + "no-unused-vars": [ "warn", { + "args": "none" + }], + indent: [ + "error", + 4, + { + ignoredNodes: [ "TemplateLiteral" ], + SwitchCase: 1, + }, + ], + quotes: [ "error", "double" ], + semi: "error", + "vue/html-indent": [ "error", 4 ], // default: 2 + "vue/max-attributes-per-line": "off", + "vue/singleline-html-element-content-newline": "off", + "vue/html-self-closing": "off", + "vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675 + "vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly + "vue/multi-word-component-names": "off", + "no-multi-spaces": [ "error", { + ignoreEOLComments: true, + }], + "array-bracket-spacing": [ "warn", "always", { + "singleValue": true, + "objectsInArrays": false, + "arraysInArrays": false + }], + "space-before-function-paren": [ "error", { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + }], + "curly": "error", + "object-curly-spacing": [ "error", "always" ], + "object-curly-newline": "off", + "object-property-newline": "error", + "comma-spacing": "error", + "brace-style": "error", + "no-var": "error", + "key-spacing": "warn", + "keyword-spacing": "warn", + "space-infix-ops": "error", + "arrow-spacing": "warn", + "no-trailing-spaces": "error", + "no-constant-condition": [ "error", { + "checkLoops": false, + }], + "space-before-blocks": "warn", + "no-extra-boolean-cast": "off", + "no-multiple-empty-lines": [ "warn", { + "max": 1, + "maxBOF": 0, + }], + "lines-between-class-members": [ "warn", "always", { + exceptAfterSingleLine: true, + }], + "no-unneeded-ternary": "error", + "array-bracket-newline": [ "error", "consistent" ], + "eol-last": [ "error", "always" ], + "comma-dangle": [ "warn", "only-multiline" ], + "no-empty": [ "error", { + "allowEmptyCatch": true + }], + "no-control-regex": "off", + "one-var": [ "error", "never" ], + "max-statements-per-line": [ "error", { "max": 1 }], + "@typescript-eslint/ban-ts-comment": "off", + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..25b978e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# dotenv environment variable files +.env +node_modules +dist +.idea +data +tmp + diff --git a/README.md b/README.md index cd7e17a..f87f6a6 100644 --- a/README.md +++ b/README.md @@ -1 +1,21 @@ # Dockge + +## Features + +- Easy-to-use +- Fancy UI +- Focus on `docker-compose` stack management +- Interactive editor for `docker-compose.yml` files +- Easy to expose your service to the internet with https + + +## Motivations + +- Want to build my dream web-based container manager +- Want to try next gen runtime like Deno or Bun, but I chose Deno because at this moment, Deno is more stable and Jetbrains IDE support is better. +- Full TypeScript and ES module +- Try DaisyUI + TailwindCSS + +## Dockge? + +Naming idea is coming from Twitch emotes. There are many emotes sound like this such as `bedge` and `sadge`. diff --git a/backend/check-version.ts b/backend/check-version.ts new file mode 100644 index 0000000..6c4e319 --- /dev/null +++ b/backend/check-version.ts @@ -0,0 +1,71 @@ +import { log } from "./log"; +import compareVersions from "compare-versions"; +import packageJSON from "../package.json"; +import { Settings } from "./settings"; + +export const obj = { + version: packageJSON.version, + latestVersion: null, +}; +export default obj; + +// How much time in ms to wait between update checks +const UPDATE_CHECKER_INTERVAL_MS = 1000 * 60 * 60 * 48; +const CHECK_URL = "https://uptime.kuma.pet/version"; + +let interval : NodeJS.Timeout; + +export function startInterval() { + const check = async () => { + if (await Settings.get("checkUpdate") === false) { + return; + } + + log.debug("update-checker", "Retrieving latest versions"); + + try { + const res = await fetch(CHECK_URL); + const data = await res.json(); + + // For debug + if (process.env.TEST_CHECK_VERSION === "1") { + data.slow = "1000.0.0"; + } + + const checkBeta = await Settings.get("checkBeta"); + + if (checkBeta && data.beta) { + if (compareVersions.compare(data.beta, data.slow, ">")) { + obj.latestVersion = data.beta; + return; + } + } + + if (data.slow) { + obj.latestVersion = data.slow; + } + + } catch (_) { + log.info("update-checker", "Failed to check for new versions"); + } + + }; + + check(); + interval = setInterval(check, UPDATE_CHECKER_INTERVAL_MS); +} + +/** + * Enable the check update feature + * @param value Should the check update feature be enabled? + * @returns + */ +export async function enableCheckUpdate(value : boolean) { + await Settings.set("checkUpdate", value); + + clearInterval(interval); + + if (value) { + startInterval(); + } +} diff --git a/backend/database.ts b/backend/database.ts new file mode 100644 index 0000000..d5282e5 --- /dev/null +++ b/backend/database.ts @@ -0,0 +1,247 @@ +import { log } from "./log"; +import { R } from "redbean-node"; +import { DockgeServer } from "./dockge-server"; +import fs from "fs"; +import path from "path"; +import knex from "knex"; + +import Dialect from "knex/lib/dialects/sqlite3/index.js"; + +import sqlite from "@louislam/sqlite3"; +import { sleep } from "./util-common"; + +interface DBConfig { + type?: "sqlite" | "mysql"; +} + +export class Database { + /** + * SQLite file path (Default: ./data/kuma.db) + * @type {string} + */ + static sqlitePath; + + static noReject = true; + + static dbConfig: DBConfig = {}; + + static knexMigrationsPath = "./backend/migrations"; + + private static server : DockgeServer; + + /** + * Use for decode the auth object + */ + jwtSecret? : string; + + static async init(server : DockgeServer) { + this.server = server; + + log.debug("server", "Connecting to the database"); + await Database.connect(); + log.info("server", "Connected to the database"); + + // Patch the database + await Database.patch(); + } + + /** + * Read the database config + * @throws {Error} If the config is invalid + * @typedef {string|undefined} envString + * @returns {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} Database config + */ + static readDBConfig() { + const dbConfigString = fs.readFileSync(path.join(this.server.config.dataDir, "db-config.json")).toString("utf-8"); + const dbConfig = JSON.parse(dbConfigString); + + if (typeof dbConfig !== "object") { + throw new Error("Invalid db-config.json, it must be an object"); + } + + if (typeof dbConfig.type !== "string") { + throw new Error("Invalid db-config.json, type must be a string"); + } + return dbConfig; + } + + /** + * @typedef {string|undefined} envString + * @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} dbConfig the database configuration that should be written + * @returns {void} + */ + static writeDBConfig(dbConfig) { + fs.writeFileSync(path.join(this.server.config.dataDir, "db-config.json"), JSON.stringify(dbConfig, null, 4)); + } + + /** + * Connect to the database + * @param {boolean} autoloadModels Should models be automatically loaded? + * @param {boolean} noLog Should logs not be output? + * @returns {Promise} + */ + static async connect(autoloadModels = true, noLog = false) { + const acquireConnectionTimeout = 120 * 1000; + let dbConfig; + try { + dbConfig = this.readDBConfig(); + Database.dbConfig = dbConfig; + } catch (err) { + log.warn("db", err.message); + dbConfig = { + type: "sqlite", + }; + this.writeDBConfig(dbConfig); + } + + let config = {}; + + log.info("db", `Database Type: ${dbConfig.type}`); + + if (dbConfig.type === "sqlite") { + this.sqlitePath = path.join(this.server.config.dataDir, "dockge.db"); + Dialect.prototype._driver = () => sqlite; + + config = { + client: Dialect, + connection: { + filename: Database.sqlitePath, + acquireConnectionTimeout: acquireConnectionTimeout, + }, + useNullAsDefault: true, + pool: { + min: 1, + max: 1, + idleTimeoutMillis: 120 * 1000, + propagateCreateError: false, + acquireTimeoutMillis: acquireConnectionTimeout, + } + }; + } else { + throw new Error("Unknown Database type: " + dbConfig.type); + } + + const knexInstance = knex(config); + + // @ts-ignore + R.setup(knexInstance); + + if (process.env.SQL_LOG === "1") { + R.debug(true); + } + + // Auto map the model to a bean object + R.freeze(true); + + if (autoloadModels) { + await R.autoloadModels("./server/model"); + } + + if (dbConfig.type === "sqlite") { + await this.initSQLite(); + } + } + + /** + @returns {Promise} + */ + static async initSQLite() { + await R.exec("PRAGMA foreign_keys = ON"); + // Change to WAL + await R.exec("PRAGMA journal_mode = WAL"); + await R.exec("PRAGMA cache_size = -12000"); + await R.exec("PRAGMA auto_vacuum = INCREMENTAL"); + + // This ensures that an operating system crash or power failure will not corrupt the database. + // FULL synchronous is very safe, but it is also slower. + // Read more: https://sqlite.org/pragma.html#pragma_synchronous + await R.exec("PRAGMA synchronous = NORMAL"); + + log.debug("db", "SQLite config:"); + log.debug("db", await R.getAll("PRAGMA journal_mode")); + log.debug("db", await R.getAll("PRAGMA cache_size")); + log.debug("db", "SQLite Version: " + await R.getCell("SELECT sqlite_version()")); + } + + /** + * Patch the database + * @returns {void} + */ + static async patch() { + // Using knex migrations + // https://knexjs.org/guide/migrations.html + // https://gist.github.com/NigelEarle/70db130cc040cc2868555b29a0278261 + try { + await R.knex.migrate.latest({ + directory: Database.knexMigrationsPath, + }); + } catch (e) { + // Allow missing patch files for downgrade or testing pr. + if (e.message.includes("the following files are missing:")) { + log.warn("db", e.message); + log.warn("db", "Database migration failed, you may be downgrading Dockge."); + } else { + log.error("db", "Database migration failed"); + throw e; + } + } + } + + /** + * Special handle, because tarn.js throw a promise reject that cannot be caught + * @returns {Promise} + */ + static async close() { + const listener = () => { + Database.noReject = false; + }; + process.addListener("unhandledRejection", listener); + + log.info("db", "Closing the database"); + + // Flush WAL to main database + if (Database.dbConfig.type === "sqlite") { + await R.exec("PRAGMA wal_checkpoint(TRUNCATE)"); + } + + while (true) { + Database.noReject = true; + await R.close(); + await sleep(2000); + + if (Database.noReject) { + break; + } else { + log.info("db", "Waiting to close the database"); + } + } + log.info("db", "Database closed"); + + process.removeListener("unhandledRejection", listener); + } + + /** + * Get the size of the database (SQLite only) + * @returns {number} Size of database + */ + static getSize() { + if (Database.dbConfig.type === "sqlite") { + log.debug("db", "Database.getSize()"); + const stats = fs.statSync(Database.sqlitePath); + log.debug("db", stats); + return stats.size; + } + return 0; + } + + /** + * Shrink the database + * @returns {Promise} + */ + static async shrink() { + if (Database.dbConfig.type === "sqlite") { + await R.exec("VACUUM"); + } + } + +} diff --git a/backend/docker.ts b/backend/docker.ts new file mode 100644 index 0000000..4083a73 --- /dev/null +++ b/backend/docker.ts @@ -0,0 +1,3 @@ +export class Docker { + +} diff --git a/backend/dockge-server.ts b/backend/dockge-server.ts new file mode 100644 index 0000000..b2b27db --- /dev/null +++ b/backend/dockge-server.ts @@ -0,0 +1,381 @@ +import { MainRouter } from "./routers/main-router"; +import * as fs from "node:fs"; +import { PackageJson } from "type-fest"; +import { Database } from "./database"; +import packageJSON from "../package.json"; +import { log } from "./log"; +import * as socketIO from "socket.io"; +import express, { Express } from "express"; +import { parse } from "ts-command-line-args"; +import https from "https"; +import http from "http"; +import { Router } from "./router"; +import { Socket } from "socket.io"; +import { MainSocketHandler } from "./socket-handlers/main-socket-handler"; +import { SocketHandler } from "./socket-handler"; +import { Settings } from "./settings"; +import checkVersion from "./check-version"; +import dayjs from "dayjs"; +import { R } from "redbean-node"; +import { genSecret, isDev } from "./util-common"; +import { generatePasswordHash } from "./password-hash"; +import { Bean } from "redbean-node/dist/bean"; +import { DockgeSocket } from "./util-server"; +import { DockerSocketHandler } from "./socket-handlers/docker-socket-handler"; +import { Terminal } from "./terminal"; + +export interface Arguments { + sslKey? : string; + sslCert? : string; + sslKeyPassphrase? : string; + port? : number; + hostname? : string; + dataDir? : string; +} + +export class DockgeServer { + app : Express; + httpServer : http.Server; + packageJSON : PackageJson; + io : socketIO.Server; + config : Arguments; + indexHTML : string; + terminal : Terminal; + + /** + * List of express routers + */ + routerList : Router[] = [ + new MainRouter(), + ]; + + /** + * List of socket handlers + */ + socketHandlerList : SocketHandler[] = [ + new MainSocketHandler(), + new DockerSocketHandler(), + ]; + + /** + * Show Setup Page + */ + needSetup = false; + + jwtSecret? : string; + + /** + * + */ + constructor() { + if (!process.env.NODE_ENV) { + process.env.NODE_ENV = "production"; + } + + // Log NODE ENV + log.info("server", "NODE_ENV: " + process.env.NODE_ENV); + + // Load arguments + const args = this.config = parse({ + sslKey: { + type: String, + optional: true, + }, + sslCert: { + type: String, + optional: true, + }, + sslKeyPassphrase: { + type: String, + optional: true, + }, + port: { + type: Number, + optional: true, + }, + hostname: { + type: String, + optional: true, + }, + dataDir: { + type: String, + optional: true, + } + }); + + // Load from environment variables or default values if args are not set + args.sslKey = args.sslKey || process.env.DOCKGE_SSL_KEY || undefined; + args.sslCert = args.sslCert || process.env.DOCKGE_SSL_CERT || undefined; + args.sslKeyPassphrase = args.sslKeyPassphrase || process.env.DOCKGE_SSL_KEY_PASSPHRASE || undefined; + args.port = args.port || parseInt(process.env.DOCKGE_PORT) || 5001; + args.hostname = args.hostname || process.env.DOCKGE_HOSTNAME || undefined; + args.dataDir = args.dataDir || process.env.DOCKGE_DATA_DIR || "./data/"; + + log.debug("server", args); + + this.packageJSON = packageJSON as PackageJson; + + this.initDataDir(); + + this.terminal = new Terminal(this); + } + + /** + * + */ + async serve() { + // Connect to database + try { + await Database.init(this); + } catch (e) { + log.error("server", "Failed to prepare your database: " + e.message); + process.exit(1); + } + + // First time setup if needed + let jwtSecretBean = await R.findOne("setting", " `key` = ? ", [ + "jwtSecret", + ]); + + if (! jwtSecretBean) { + log.info("server", "JWT secret is not found, generate one."); + jwtSecretBean = await this.initJWTSecret(); + log.info("server", "Stored JWT secret into database"); + } else { + log.debug("server", "Load JWT secret from database."); + } + + this.jwtSecret = jwtSecretBean.value; + + const userCount = (await R.knex("user").count("id as count").first()).count; + + log.debug("server", "User count: " + userCount); + + // If there is no record in user table, it is a new Dockge instance, need to setup + if (userCount == 0) { + log.info("server", "No user, need setup"); + this.needSetup = true; + } + + // Create express + this.app = express(); + + if (this.config.sslKey && this.config.sslCert) { + log.info("server", "Server Type: HTTPS"); + this.httpServer = https.createServer({ + key: fs.readFileSync(this.config.sslKey), + cert: fs.readFileSync(this.config.sslCert), + passphrase: this.config.sslKeyPassphrase, + }, this.app); + } else { + log.info("server", "Server Type: HTTP"); + this.httpServer = http.createServer(this.app); + } + + try { + this.indexHTML = fs.readFileSync("./dist/index.html").toString(); + } catch (e) { + // "dist/index.html" is not necessary for development + if (process.env.NODE_ENV !== "development") { + log.error("server", "Error: Cannot find 'dist/index.html', did you install correctly?"); + process.exit(1); + } + } + + for (const router of this.routerList) { + this.app.use(router.create(this.app, this)); + } + + let cors = undefined; + + if (isDev) { + cors = { + origin: "*", + }; + } + + // Create Socket.io + this.io = new socketIO.Server(this.httpServer, { + cors, + }); + + this.io.on("connection", (socket: Socket) => { + log.info("server", "Socket connected!"); + + this.sendInfo(socket, true); + + if (this.needSetup) { + log.info("server", "Redirect to setup page"); + socket.emit("setup"); + } + + // Create socket handlers + for (const socketHandler of this.socketHandlerList) { + socketHandler.create(socket as DockgeSocket, this); + } + }); + + // Listen + this.httpServer.listen(5001, this.config.hostname, () => { + if (this.config.hostname) { + log.info( "server", `Listening on ${this.config.hostname}:${this.config.port}`); + } else { + log.info("server", `Listening on ${this.config.port}`); + } + }); + } + + /** + * Emits the version information to the client. + * @param socket Socket.io socket instance + * @param hideVersion Should we hide the version information in the response? + * @returns + */ + async sendInfo(socket : Socket, hideVersion = false) { + let versionProperty; + let latestVersionProperty; + let isContainer; + + if (!hideVersion) { + versionProperty = packageJSON.version; + latestVersionProperty = checkVersion.latestVersion; + isContainer = (process.env.DOCKGE_IS_CONTAINER === "1"); + } + + socket.emit("info", { + versionProperty, + latestVersionProperty, + isContainer, + primaryBaseURL: await Settings.get("primaryBaseURL"), + serverTimezone: await this.getTimezone(), + serverTimezoneOffset: this.getTimezoneOffset(), + }); + } + + /** + * Get the IP of the client connected to the socket + * @param {Socket} socket Socket to query + * @returns IP of client + */ + async getClientIP(socket : Socket) : Promise { + let clientIP = socket.client.conn.remoteAddress; + + if (clientIP === undefined) { + clientIP = ""; + } + + if (await Settings.get("trustProxy")) { + const forwardedFor = socket.client.conn.request.headers["x-forwarded-for"]; + + if (typeof forwardedFor === "string") { + return forwardedFor.split(",")[0].trim(); + } else if (typeof socket.client.conn.request.headers["x-real-ip"] === "string") { + return socket.client.conn.request.headers["x-real-ip"]; + } + } + return clientIP.replace(/^::ffff:/, ""); + } + + /** + * Attempt to get the current server timezone + * If this fails, fall back to environment variables and then make a + * guess. + * @returns {Promise} Current timezone + */ + async getTimezone() { + // From process.env.TZ + try { + if (process.env.TZ) { + this.checkTimezone(process.env.TZ); + return process.env.TZ; + } + } catch (e) { + log.warn("timezone", e.message + " in process.env.TZ"); + } + + const timezone = await Settings.get("serverTimezone"); + + // From Settings + try { + log.debug("timezone", "Using timezone from settings: " + timezone); + if (timezone) { + this.checkTimezone(timezone); + return timezone; + } + } catch (e) { + log.warn("timezone", e.message + " in settings"); + } + + // Guess + try { + const guess = dayjs.tz.guess(); + log.debug("timezone", "Guessing timezone: " + guess); + if (guess) { + this.checkTimezone(guess); + return guess; + } else { + return "UTC"; + } + } catch (e) { + // Guess failed, fall back to UTC + log.debug("timezone", "Guessed an invalid timezone. Use UTC as fallback"); + return "UTC"; + } + } + + /** + * Get the current offset + * @returns {string} Time offset + */ + getTimezoneOffset() { + return dayjs().format("Z"); + } + + /** + * Throw an error if the timezone is invalid + * @param {string} timezone Timezone to test + * @returns {void} + * @throws The timezone is invalid + */ + checkTimezone(timezone : string) { + try { + dayjs.utc("2013-11-18 11:55").tz(timezone).format(); + } catch (e) { + throw new Error("Invalid timezone:" + timezone); + } + } + + /** + * Initialize the data directory + */ + initDataDir() { + // Check if a directory + if (!fs.lstatSync(this.config.dataDir).isDirectory()) { + throw new Error(`Fatal error: ${this.config.dataDir} is not a directory`); + } + + if (! fs.existsSync(this.config.dataDir)) { + fs.mkdirSync(this.config.dataDir, { recursive: true }); + } + log.info("server", `Data Dir: ${this.config.dataDir}`); + } + + /** + * Init or reset JWT secret + * @returns JWT secret + */ + async initJWTSecret() : Promise { + let jwtSecretBean = await R.findOne("setting", " `key` = ? ", [ + "jwtSecret", + ]); + + if (!jwtSecretBean) { + jwtSecretBean = R.dispense("setting"); + jwtSecretBean.key = "jwtSecret"; + } + + jwtSecretBean.value = generatePasswordHash(genSecret()); + await R.store(jwtSecretBean); + return jwtSecretBean; + } +} diff --git a/backend/index.ts b/backend/index.ts new file mode 100644 index 0000000..d0b53f2 --- /dev/null +++ b/backend/index.ts @@ -0,0 +1,6 @@ +import { DockgeServer } from "./dockge-server"; +import { log } from "./log"; + +log.info("server", "Welcome to dockge!"); +const server = new DockgeServer(); +await server.serve(); diff --git a/backend/log.ts b/backend/log.ts new file mode 100644 index 0000000..37f2d4a --- /dev/null +++ b/backend/log.ts @@ -0,0 +1,208 @@ +// Console colors +// https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color +import { intHash, isDev } from "./util-common"; +import dayjs from "dayjs"; + +export const CONSOLE_STYLE_Reset = "\x1b[0m"; +export const CONSOLE_STYLE_Bright = "\x1b[1m"; +export const CONSOLE_STYLE_Dim = "\x1b[2m"; +export const CONSOLE_STYLE_Underscore = "\x1b[4m"; +export const CONSOLE_STYLE_Blink = "\x1b[5m"; +export const CONSOLE_STYLE_Reverse = "\x1b[7m"; +export const CONSOLE_STYLE_Hidden = "\x1b[8m"; + +export const CONSOLE_STYLE_FgBlack = "\x1b[30m"; +export const CONSOLE_STYLE_FgRed = "\x1b[31m"; +export const CONSOLE_STYLE_FgGreen = "\x1b[32m"; +export const CONSOLE_STYLE_FgYellow = "\x1b[33m"; +export const CONSOLE_STYLE_FgBlue = "\x1b[34m"; +export const CONSOLE_STYLE_FgMagenta = "\x1b[35m"; +export const CONSOLE_STYLE_FgCyan = "\x1b[36m"; +export const CONSOLE_STYLE_FgWhite = "\x1b[37m"; +export const CONSOLE_STYLE_FgGray = "\x1b[90m"; +export const CONSOLE_STYLE_FgOrange = "\x1b[38;5;208m"; +export const CONSOLE_STYLE_FgLightGreen = "\x1b[38;5;119m"; +export const CONSOLE_STYLE_FgLightBlue = "\x1b[38;5;117m"; +export const CONSOLE_STYLE_FgViolet = "\x1b[38;5;141m"; +export const CONSOLE_STYLE_FgBrown = "\x1b[38;5;130m"; +export const CONSOLE_STYLE_FgPink = "\x1b[38;5;219m"; + +export const CONSOLE_STYLE_BgBlack = "\x1b[40m"; +export const CONSOLE_STYLE_BgRed = "\x1b[41m"; +export const CONSOLE_STYLE_BgGreen = "\x1b[42m"; +export const CONSOLE_STYLE_BgYellow = "\x1b[43m"; +export const CONSOLE_STYLE_BgBlue = "\x1b[44m"; +export const CONSOLE_STYLE_BgMagenta = "\x1b[45m"; +export const CONSOLE_STYLE_BgCyan = "\x1b[46m"; +export const CONSOLE_STYLE_BgWhite = "\x1b[47m"; +export const CONSOLE_STYLE_BgGray = "\x1b[100m"; + +const consoleModuleColors = [ + CONSOLE_STYLE_FgCyan, + CONSOLE_STYLE_FgGreen, + CONSOLE_STYLE_FgLightGreen, + CONSOLE_STYLE_FgBlue, + CONSOLE_STYLE_FgLightBlue, + CONSOLE_STYLE_FgMagenta, + CONSOLE_STYLE_FgOrange, + CONSOLE_STYLE_FgViolet, + CONSOLE_STYLE_FgBrown, + CONSOLE_STYLE_FgPink, +]; + +const consoleLevelColors : Record = { + "INFO": CONSOLE_STYLE_FgCyan, + "WARN": CONSOLE_STYLE_FgYellow, + "ERROR": CONSOLE_STYLE_FgRed, + "DEBUG": CONSOLE_STYLE_FgGray, +}; + +class Logger { + + /** + * DOCKGE_HIDE_LOG=debug_monitor,info_monitor + * + * Example: + * [ + * "debug_monitor", // Hide all logs that level is debug and the module is monitor + * "info_monitor", + * ] + */ + hideLog : Record = { + info: [], + warn: [], + error: [], + debug: [], + }; + + /** + * + */ + constructor() { + if (typeof process !== "undefined" && process.env.DOCKGE_HIDE_LOG) { + const list = process.env.DOCKGE_HIDE_LOG.split(",").map(v => v.toLowerCase()); + + for (const pair of list) { + // split first "_" only + const values = pair.split(/_(.*)/s); + + if (values.length >= 2) { + this.hideLog[values[0]].push(values[1]); + } + } + + this.debug("server", "DOCKGE_HIDE_LOG is set"); + this.debug("server", this.hideLog); + } + } + + /** + * Write a message to the log + * @param module The module the log comes from + * @param msg Message to write + * @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized. + */ + log(module: string, msg: unknown, level: string) { + if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) { + return; + } + + module = module.toUpperCase(); + level = level.toUpperCase(); + + let now; + if (dayjs.tz) { + now = dayjs.tz(new Date()).format(); + } else { + now = dayjs().format(); + } + + const levelColor = consoleLevelColors[level]; + const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)]; + + let timePart = CONSOLE_STYLE_FgCyan + now + CONSOLE_STYLE_Reset; + const modulePart = "[" + moduleColor + module + CONSOLE_STYLE_Reset + "]"; + const levelPart = levelColor + `${level}:` + CONSOLE_STYLE_Reset; + + if (level === "INFO") { + console.info(timePart, modulePart, levelPart, msg); + } else if (level === "WARN") { + console.warn(timePart, modulePart, levelPart, msg); + } else if (level === "ERROR") { + let msgPart : unknown; + if (typeof msg === "string") { + msgPart = CONSOLE_STYLE_FgRed + msg + CONSOLE_STYLE_Reset; + } else { + msgPart = msg; + } + console.error(timePart, modulePart, levelPart, msgPart); + } else if (level === "DEBUG") { + if (isDev) { + timePart = CONSOLE_STYLE_FgGray + now + CONSOLE_STYLE_Reset; + let msgPart : unknown; + if (typeof msg === "string") { + msgPart = CONSOLE_STYLE_FgGray + msg + CONSOLE_STYLE_Reset; + } else { + msgPart = msg; + } + console.debug(timePart, modulePart, levelPart, msgPart); + } + } else { + console.log(timePart, modulePart, msg); + } + } + + /** + * Log an INFO message + * @param module Module log comes from + * @param msg Message to write + */ + info(module: string, msg: unknown) { + this.log(module, msg, "info"); + } + + /** + * Log a WARN message + * @param module Module log comes from + * @param msg Message to write + */ + warn(module: string, msg: unknown) { + this.log(module, msg, "warn"); + } + + /** + * Log an ERROR message + * @param module Module log comes from + * @param msg Message to write + */ + error(module: string, msg: unknown) { + this.log(module, msg, "error"); + } + + /** + * Log a DEBUG message + * @param module Module log comes from + * @param msg Message to write + */ + debug(module: string, msg: unknown) { + this.log(module, msg, "debug"); + } + + /** + * Log an exception as an ERROR + * @param module Module log comes from + * @param exception The exception to include + * @param msg The message to write + */ + exception(module: string, exception: unknown, msg: unknown) { + let finalMessage = exception; + + if (msg) { + finalMessage = `${msg}: ${exception}`; + } + + this.log(module, finalMessage, "error"); + } +} + +export const log = new Logger(); diff --git a/backend/migrations/2023-10-20-0829-setting-table.ts b/backend/migrations/2023-10-20-0829-setting-table.ts new file mode 100644 index 0000000..56c5d6a --- /dev/null +++ b/backend/migrations/2023-10-20-0829-setting-table.ts @@ -0,0 +1,14 @@ +import { Knex } from "knex"; + +export async function up(knex: Knex): Promise { + return knex.schema.createTable("setting", (table) => { + table.increments("id"); + table.string("key", 200).notNullable().unique().collate("utf8_general_ci"); + table.text("value"); + table.string("type", 20); + }); +} + +export async function down(knex: Knex): Promise { + return knex.schema.dropTable("setting"); +} diff --git a/backend/migrations/2023-10-20-0829-user-table.ts b/backend/migrations/2023-10-20-0829-user-table.ts new file mode 100644 index 0000000..ca84b00 --- /dev/null +++ b/backend/migrations/2023-10-20-0829-user-table.ts @@ -0,0 +1,19 @@ +import { Knex } from "knex"; + +export async function up(knex: Knex): Promise { + // Create the user table + return knex.schema.createTable("user", (table) => { + table.increments("id"); + table.string("username", 255).notNullable().unique().collate("utf8_general_ci"); + table.string("password", 255); + table.boolean("active").notNullable().defaultTo(true); + table.string("timezone", 150); + table.string("twofa_secret", 64); + table.boolean("twofa_status").notNullable().defaultTo(false); + table.string("twofa_last_token", 6); + }); +} + +export async function down(knex: Knex): Promise { + return knex.schema.dropTable("user"); +} diff --git a/backend/models/user.ts b/backend/models/user.ts new file mode 100644 index 0000000..720cdf7 --- /dev/null +++ b/backend/models/user.ts @@ -0,0 +1,44 @@ +import jwt from "jsonwebtoken"; +import { R } from "redbean-node"; +import { BeanModel } from "redbean-node/dist/bean-model"; +import { generatePasswordHash, shake256, SHAKE256_LENGTH } from "../password-hash"; + +export class User extends BeanModel { + /** + * Reset user password + * Fix #1510, as in the context reset-password.js, there is no auto model mapping. Call this static function instead. + * @param {number} userID ID of user to update + * @param {string} newPassword Users new password + * @returns {Promise} + */ + static async resetPassword(userID : number, newPassword : string) { + await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [ + generatePasswordHash(newPassword), + userID + ]); + } + + /** + * Reset this users password + * @param {string} newPassword Users new password + * @returns {Promise} + */ + async resetPassword(newPassword : string) { + await User.resetPassword(this.id, newPassword); + this.password = newPassword; + } + + /** + * Create a new JWT for a user + * @param {User} user The User to create a JsonWebToken for + * @param {string} jwtSecret The key used to sign the JsonWebToken + * @returns {string} the JsonWebToken as a string + */ + static createJWT(user : User, jwtSecret : string) { + return jwt.sign({ + username: user.username, + h: shake256(user.password, SHAKE256_LENGTH), + }, jwtSecret); + } + +} diff --git a/backend/password-hash.ts b/backend/password-hash.ts new file mode 100644 index 0000000..fb8d42d --- /dev/null +++ b/backend/password-hash.ts @@ -0,0 +1,47 @@ +import bcrypt from "bcryptjs"; +import crypto from "crypto"; +const saltRounds = 10; + +/** + * Hash a password + * @param {string} password Password to hash + * @returns {string} Hash + */ +export function generatePasswordHash(password : string) { + return bcrypt.hashSync(password, saltRounds); +} + +/** + * Verify a password against a hash + * @param {string} password Password to verify + * @param {string} hash Hash to verify against + * @returns {boolean} Does the password match the hash? + */ +export function verifyPassword(password, hash) { + return bcrypt.compareSync(password, hash); +} + +/** + * Does the hash need to be rehashed? + * @param {string} hash Hash to check + * @returns {boolean} Needs to be rehashed? + */ +export function needRehashPassword(hash : string) : boolean { + return false; +} + +export const SHAKE256_LENGTH = 16; + +/** + * @param {string} data The data to be hashed + * @param {number} len Output length of the hash + * @returns {string} The hashed data in hex format + */ +export function shake256(data, len) { + if (!data) { + return ""; + } + return crypto.createHash("shake256", { outputLength: len }) + .update(data) + .digest("hex"); +} diff --git a/backend/rate-limiter.ts b/backend/rate-limiter.ts new file mode 100644 index 0000000..3c43abe --- /dev/null +++ b/backend/rate-limiter.ts @@ -0,0 +1,75 @@ +// "limit" is bugged in Typescript, use "limiter-es6-compat" instead +// See https://github.com/jhurliman/node-rate-limiter/issues/80 +import { RateLimiter } from "limiter-es6-compat"; +import { log } from "./log"; + +class KumaRateLimiter { + + errorMessage : string; + rateLimiter : RateLimiter; + + /** + * @param {object} config Rate limiter configuration object + */ + constructor(config) { + this.errorMessage = config.errorMessage; + this.rateLimiter = new RateLimiter(config); + } + + /** + * Callback for pass + * @callback passCB + * @param {object} err Too many requests + */ + + /** + * Should the request be passed through + * @param {passCB} callback Callback function to call with decision + * @param {number} num Number of tokens to remove + * @returns {Promise} Should the request be allowed? + */ + async pass(callback, num = 1) { + const remainingRequests = await this.removeTokens(num); + log.info("rate-limit", "remaining requests: " + remainingRequests); + if (remainingRequests < 0) { + if (callback) { + callback({ + ok: false, + msg: this.errorMessage, + }); + } + return false; + } + return true; + } + + /** + * Remove a given number of tokens + * @param {number} num Number of tokens to remove + * @returns {Promise} Number of remaining tokens + */ + async removeTokens(num = 1) { + return await this.rateLimiter.removeTokens(num); + } +} + +export const loginRateLimiter = new KumaRateLimiter({ + tokensPerInterval: 20, + interval: "minute", + fireImmediately: true, + errorMessage: "Too frequently, try again later." +}); + +export const apiRateLimiter = new KumaRateLimiter({ + tokensPerInterval: 60, + interval: "minute", + fireImmediately: true, + errorMessage: "Too frequently, try again later." +}); + +export const twoFaRateLimiter = new KumaRateLimiter({ + tokensPerInterval: 30, + interval: "minute", + fireImmediately: true, + errorMessage: "Too frequently, try again later." +}); diff --git a/backend/router.ts b/backend/router.ts new file mode 100644 index 0000000..b004477 --- /dev/null +++ b/backend/router.ts @@ -0,0 +1,6 @@ +import { DockgeServer } from "./dockge-server"; +import { Express, Router as ExpressRouter } from "express"; + +export abstract class Router { + abstract create(app : Express, server : DockgeServer): ExpressRouter; +} diff --git a/backend/routers/main-router.ts b/backend/routers/main-router.ts new file mode 100644 index 0000000..fd36da6 --- /dev/null +++ b/backend/routers/main-router.ts @@ -0,0 +1,16 @@ +import { DockgeServer } from "../dockgeServer"; +import { Router } from "../router"; +import express, { Express, Router as ExpressRouter } from "express"; + +export class MainRouter extends Router { + create(app: Express, server: DockgeServer): ExpressRouter { + const router = express.Router(); + + router.get("/", (req, res) => { + + }); + + return router; + } + +} diff --git a/backend/settings.ts b/backend/settings.ts new file mode 100644 index 0000000..fed94a7 --- /dev/null +++ b/backend/settings.ts @@ -0,0 +1,174 @@ +import { R } from "redbean-node"; +import { log } from "./log"; + +export class Settings { + + /** + * Example: + * { + * key1: { + * value: "value2", + * timestamp: 12345678 + * }, + * key2: { + * value: 2, + * timestamp: 12345678 + * }, + * } + * @type {{}} + */ + static cacheList = { + + }; + + static cacheCleaner = null; + + /** + * Retrieve value of setting based on key + * @param {string} key Key of setting to retrieve + * @returns {Promise} Value + */ + static async get(key) { + + // Start cache clear if not started yet + if (!Settings.cacheCleaner) { + Settings.cacheCleaner = setInterval(() => { + log.debug("settings", "Cache Cleaner is just started."); + for (key in Settings.cacheList) { + if (Date.now() - Settings.cacheList[key].timestamp > 60 * 1000) { + log.debug("settings", "Cache Cleaner deleted: " + key); + delete Settings.cacheList[key]; + } + } + + }, 60 * 1000); + } + + // Query from cache + if (key in Settings.cacheList) { + const v = Settings.cacheList[key].value; + log.debug("settings", `Get Setting (cache): ${key}: ${v}`); + return v; + } + + const value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [ + key, + ]); + + try { + const v = JSON.parse(value); + log.debug("settings", `Get Setting: ${key}: ${v}`); + + Settings.cacheList[key] = { + value: v, + timestamp: Date.now() + }; + + return v; + } catch (e) { + return value; + } + } + + /** + * Sets the specified setting to specified value + * @param {string} key Key of setting to set + * @param {any} value Value to set to + * @param {?string} type Type of setting + * @returns {Promise} + */ + static async set(key, value, type = null) { + + let bean = await R.findOne("setting", " `key` = ? ", [ + key, + ]); + if (!bean) { + bean = R.dispense("setting"); + bean.key = key; + } + bean.type = type; + bean.value = JSON.stringify(value); + await R.store(bean); + + Settings.deleteCache([ key ]); + } + + /** + * Get settings based on type + * @param {string} type The type of setting + * @returns {Promise} Settings + */ + static async getSettings(type) { + const list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [ + type, + ]); + + const result = {}; + + for (const row of list) { + try { + result[row.key] = JSON.parse(row.value); + } catch (e) { + result[row.key] = row.value; + } + } + + return result; + } + + /** + * Set settings based on type + * @param {string} type Type of settings to set + * @param {object} data Values of settings + * @returns {Promise} + */ + static async setSettings(type, data) { + const keyList = Object.keys(data); + + const promiseList = []; + + for (const key of keyList) { + let bean = await R.findOne("setting", " `key` = ? ", [ + key + ]); + + if (bean == null) { + bean = R.dispense("setting"); + bean.type = type; + bean.key = key; + } + + if (bean.type === type) { + bean.value = JSON.stringify(data[key]); + promiseList.push(R.store(bean)); + } + } + + await Promise.all(promiseList); + + Settings.deleteCache(keyList); + } + + /** + * Delete selected keys from settings cache + * @param {string[]} keyList Keys to remove + * @returns {void} + */ + static deleteCache(keyList) { + for (const key of keyList) { + delete Settings.cacheList[key]; + } + } + + /** + * Stop the cache cleaner if running + * @returns {void} + */ + static stopCacheCleaner() { + if (Settings.cacheCleaner) { + clearInterval(Settings.cacheCleaner); + Settings.cacheCleaner = null; + } + } +} + diff --git a/backend/socket-handler.ts b/backend/socket-handler.ts new file mode 100644 index 0000000..aaf6060 --- /dev/null +++ b/backend/socket-handler.ts @@ -0,0 +1,6 @@ +import { DockgeServer } from "./dockge-server"; +import { DockgeSocket } from "./util-server"; + +export abstract class SocketHandler { + abstract create(socket : DockgeSocket, server : DockgeServer): void; +} diff --git a/backend/socket-handlers/docker-socket-handler.ts b/backend/socket-handlers/docker-socket-handler.ts new file mode 100644 index 0000000..55df1a0 --- /dev/null +++ b/backend/socket-handlers/docker-socket-handler.ts @@ -0,0 +1,61 @@ +import { SocketHandler } from "../socket-handler.js"; +import { DockgeServer } from "../dockge-server"; +import { checkLogin, DockgeSocket } from "../util-server"; +import { log } from "../log"; + +const allowedCommandList : string[] = [ + "docker", +]; + +export class DockerSocketHandler extends SocketHandler { + create(socket : DockgeSocket, server : DockgeServer) { + + socket.on("composeUp", async (compose, callback) => { + + }); + + socket.on("terminalInput", async (cmd : unknown, errorCallback) => { + try { + checkLogin(socket); + + if (typeof(cmd) !== "string") { + throw new Error("Command must be a string."); + } + + // Check if the command is allowed + const cmdParts = cmd.split(" "); + const executable = cmdParts[0].trim(); + log.debug("console", "Executable: " + executable); + log.debug("console", "Executable length: " + executable.length); + + if (!allowedCommandList.includes(executable)) { + throw new Error("Command not allowed."); + } + + server.terminal.write(cmd); + } catch (e) { + errorCallback({ + ok: false, + msg: e.message, + }); + } + }); + + // Setup + socket.on("getTerminalBuffer", async (callback) => { + try { + checkLogin(socket); + callback({ + ok: true, + buffer: server.terminal.getBuffer(), + }); + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + + }); + } +} diff --git a/backend/socket-handlers/main-socket-handler.ts b/backend/socket-handlers/main-socket-handler.ts new file mode 100644 index 0000000..60dd58a --- /dev/null +++ b/backend/socket-handlers/main-socket-handler.ts @@ -0,0 +1,220 @@ +import { SocketHandler } from "../socket-handler.js"; +import { Socket } from "socket.io"; +import { DockgeServer } from "../dockge-server"; +import { log } from "../log"; +import { R } from "redbean-node"; +import { loginRateLimiter, twoFaRateLimiter } from "../rate-limiter"; +import { generatePasswordHash, needRehashPassword, shake256, SHAKE256_LENGTH, verifyPassword } from "../password-hash"; +import { User } from "../models/user"; +import { DockgeSocket } from "../util-server"; +import { passwordStrength } from "check-password-strength"; +import jwt from "jsonwebtoken"; + +export class MainSocketHandler extends SocketHandler { + create(socket : DockgeSocket, server : DockgeServer) { + + // *************************** + // Public Socket API + // *************************** + + // Setup + socket.on("setup", async (username, password, callback) => { + try { + if (passwordStrength(password).value === "Too weak") { + throw new Error("Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length."); + } + + if ((await R.knex("user").count("id as count").first()).count !== 0) { + throw new Error("Dockge has been initialized. If you want to run setup again, please delete the database."); + } + + const user = R.dispense("user"); + user.username = username; + user.password = generatePasswordHash(password); + await R.store(user); + + server.needSetup = false; + + callback({ + ok: true, + msg: "successAdded", + msgi18n: true, + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Login by token + socket.on("loginByToken", async (token, callback) => { + const clientIP = await server.getClientIP(socket); + + log.info("auth", `Login by token. IP=${clientIP}`); + + try { + const decoded = jwt.verify(token, server.jwtSecret); + + log.info("auth", "Username from JWT: " + decoded.username); + + const user = await R.findOne("user", " username = ? AND active = 1 ", [ + decoded.username, + ]) as User; + + if (user) { + // Check if the password changed + if (decoded.h !== shake256(user.password, SHAKE256_LENGTH)) { + throw new Error("The token is invalid due to password change or old token"); + } + + log.debug("auth", "afterLogin"); + await this.afterLogin(socket, user); + log.debug("auth", "afterLogin ok"); + + log.info("auth", `Successfully logged in user ${decoded.username}. IP=${clientIP}`); + + callback({ + ok: true, + }); + } else { + + log.info("auth", `Inactive or deleted user ${decoded.username}. IP=${clientIP}`); + + callback({ + ok: false, + msg: "authUserInactiveOrDeleted", + msgi18n: true, + }); + } + } catch (error) { + log.error("auth", `Invalid token. IP=${clientIP}`); + if (error.message) { + log.error("auth", error.message, `IP=${clientIP}`); + } + callback({ + ok: false, + msg: "authInvalidToken", + msgi18n: true, + }); + } + + }); + + // Login + socket.on("login", async (data, callback) => { + const clientIP = await server.getClientIP(socket); + + log.info("auth", `Login by username + password. IP=${clientIP}`); + + // Checking + if (typeof callback !== "function") { + return; + } + + if (!data) { + return; + } + + // Login Rate Limit + if (!await loginRateLimiter.pass(callback)) { + log.info("auth", `Too many failed requests for user ${data.username}. IP=${clientIP}`); + return; + } + + const user = await this.login(data.username, data.password); + + if (user) { + if (user.twofa_status === 0) { + this.afterLogin(socket, user); + + log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`); + + callback({ + ok: true, + token: User.createJWT(user, server.jwtSecret), + }); + } + + if (user.twofa_status === 1 && !data.token) { + + log.info("auth", `2FA token required for user ${data.username}. IP=${clientIP}`); + + callback({ + tokenRequired: true, + }); + } + + if (data.token) { + const verify = notp.totp.verify(data.token, user.twofa_secret, twoFAVerifyOptions); + + if (user.twofa_last_token !== data.token && verify) { + this.afterLogin(socket, user); + + await R.exec("UPDATE `user` SET twofa_last_token = ? WHERE id = ? ", [ + data.token, + socket.userID, + ]); + + log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`); + + callback({ + ok: true, + token: User.createJWT(user, server.jwtSecret), + }); + } else { + + log.warn("auth", `Invalid token provided for user ${data.username}. IP=${clientIP}`); + + callback({ + ok: false, + msg: "authInvalidToken", + msgi18n: true, + }); + } + } + } else { + + log.warn("auth", `Incorrect username or password for user ${data.username}. IP=${clientIP}`); + + callback({ + ok: false, + msg: "authIncorrectCreds", + msgi18n: true, + }); + } + + }); + } + + async afterLogin(socket : DockgeSocket, user : User) { + socket.userID = user.id; + socket.join(user.id + ""); + socket.join("terminal"); + } + + async login(username : string, password : string) { + if (typeof username !== "string" || typeof password !== "string") { + return null; + } + + const user = await R.findOne("user", " username = ? AND active = 1 ", [ + username, + ]); + + if (user && verifyPassword(password, user.password)) { + // Upgrade the hash to bcrypt + if (needRehashPassword(user.password)) { + await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [ + generatePasswordHash(password), + user.id, + ]); + } + return user; + } + + return null; + } +} diff --git a/backend/terminal.ts b/backend/terminal.ts new file mode 100644 index 0000000..9f95b01 --- /dev/null +++ b/backend/terminal.ts @@ -0,0 +1,43 @@ +import { DockgeServer } from "./dockge-server"; +import * as os from "node:os"; +import * as pty from "node-pty"; +import { LimitQueue } from "./utils/limit-queue"; + +const shell = os.platform() === "win32" ? "pwsh.exe" : "bash"; + +export class Terminal { + + ptyProcess; + private server : DockgeServer; + private buffer : LimitQueue = new LimitQueue(100); + + constructor(server : DockgeServer) { + this.server = server; + + this.ptyProcess = pty.spawn(shell, [], { + name: "dockge-terminal", + cwd: "./tmp", + }); + + // this.ptyProcess.write("npm remove lodash\r"); + //this.ptyProcess.write("npm install lodash\r"); + + this.ptyProcess.onData((data) => { + this.buffer.push(data); + this.server.io.to("terminal").emit("commandOutput", data); + }); + + } + + write(input : string) { + this.ptyProcess.write(input); + } + + /** + * Get the terminal output string for re-connecting + */ + getBuffer() : string { + return this.buffer.join(""); + } + +} diff --git a/backend/util-common.ts b/backend/util-common.ts new file mode 100644 index 0000000..3bfbf6c --- /dev/null +++ b/backend/util-common.ts @@ -0,0 +1,118 @@ +import dayjs from "dayjs"; + +// For loading dayjs plugins, don't remove event though it is not used in this file +import timezone from "dayjs/plugin/timezone"; +import utc from "dayjs/plugin/utc"; + +import { randomBytes } from "crypto"; + +export const isDev = process.env.NODE_ENV === "development"; + +/** + * Generate a decimal integer number from a string + * @param str Input + * @param length Default is 10 which means 0 - 9 + */ +export function intHash(str : string, length = 10) : number { + // A simple hashing function (you can use more complex hash functions if needed) + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash += str.charCodeAt(i); + } + // Normalize the hash to the range [0, 10] + return (hash % length + length) % length; // Ensure the result is non-negative +} + +/** + * Delays for specified number of seconds + * @param ms Number of milliseconds to sleep for + */ +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +/** + * Generate a random alphanumeric string of fixed length + * @param length Length of string to generate + * @returns string + */ +export function genSecret(length = 64) { + let secret = ""; + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + const charsLength = chars.length; + for ( let i = 0; i < length; i++ ) { + secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); + } + return secret; +} + +/** + * Get a random integer suitable for use in cryptography between upper + * and lower bounds. + * @param min Minimum value of integer + * @param max Maximum value of integer + * @returns Cryptographically suitable random integer + */ +export function getCryptoRandomInt(min: number, max: number):number { + + // synchronous version of: https://github.com/joepie91/node-random-number-csprng + + const range = max - min; + if (range >= Math.pow(2, 32)) { + console.log("Warning! Range is too large."); + } + + let tmpRange = range; + let bitsNeeded = 0; + let bytesNeeded = 0; + let mask = 1; + + while (tmpRange > 0) { + if (bitsNeeded % 8 === 0) { + bytesNeeded += 1; + } + bitsNeeded += 1; + mask = mask << 1 | 1; + tmpRange = tmpRange >>> 1; + } + + const randomBytes = getRandomBytes(bytesNeeded); + let randomValue = 0; + + for (let i = 0; i < bytesNeeded; i++) { + randomValue |= randomBytes[i] << 8 * i; + } + + randomValue = randomValue & mask; + + if (randomValue <= range) { + return min + randomValue; + } else { + return getCryptoRandomInt(min, max); + } +} + +/** + * Returns either the NodeJS crypto.randomBytes() function or its + * browser equivalent implemented via window.crypto.getRandomValues() + */ +const getRandomBytes = ( + (typeof window !== "undefined" && window.crypto) + + // Browsers + ? function () { + return (numBytes: number) => { + const randomBytes = new Uint8Array(numBytes); + for (let i = 0; i < numBytes; i += 65536) { + window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); + } + return randomBytes; + }; + } + + // Node + : function () { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return randomBytes; + } +)(); diff --git a/backend/util-server.ts b/backend/util-server.ts new file mode 100644 index 0000000..29171a2 --- /dev/null +++ b/backend/util-server.ts @@ -0,0 +1,11 @@ +import { Socket } from "socket.io"; + +export interface DockgeSocket extends Socket { + userID: number; +} + +export function checkLogin(socket : DockgeSocket) { + if (!socket.userID) { + throw new Error("You are not logged in."); + } +} diff --git a/backend/utils/limit-queue.ts b/backend/utils/limit-queue.ts new file mode 100644 index 0000000..8a1a95d --- /dev/null +++ b/backend/utils/limit-queue.ts @@ -0,0 +1,24 @@ +/** + * Limit Queue + * The first element will be removed when the length exceeds the limit + */ +export class LimitQueue extends Array { + __limit; + __onExceed = null; + + constructor(limit: number) { + super(); + this.__limit = limit; + } + + push(value : T) { + super.push(value); + if (this.length > this.__limit) { + const item = this.shift(); + if (this.__onExceed) { + this.__onExceed(item); + } + } + } + +} diff --git a/docker/Base.Dockerfile b/docker/Base.Dockerfile new file mode 100644 index 0000000..6124b56 --- /dev/null +++ b/docker/Base.Dockerfile @@ -0,0 +1,20 @@ +FROM debian:bookworm-slim + +COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/ + +RUN apt update && apt install --yes --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + && rm -rf /var/lib/apt/lists/* +RUN curl https://bun.sh/install | bash -s "bun-v1.0.3" + + +# Full Base Image +# MariaDB, Chromium and fonts +FROM base-slim AS base +ENV DOCKGE_ENABLE_EMBEDDED_MARIADB=1 +RUN apt update && \ + apt --yes --no-install-recommends install mariadb-server && \ + rm -rf /var/lib/apt/lists/* && \ + apt --yes autoremove diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..7d4163e --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,15 @@ +FROM debian:bookworm-slim + +COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/ + +RUN apt update && apt install --yes --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + && rm -rf /var/lib/apt/lists/* +RUN curl https://bun.sh/install | bash -s "bun-v1.0.3" + +WORKDIR /app + +COPY . . +RUN bun install --production --frozen-lockfile diff --git a/frontend/components.d.ts b/frontend/components.d.ts new file mode 100644 index 0000000..d96ecad --- /dev/null +++ b/frontend/components.d.ts @@ -0,0 +1,20 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + BDropdown: typeof import('bootstrap-vue-next')['BDropdown'] + BDropdownItem: typeof import('bootstrap-vue-next')['BDropdownItem'] + Confirm: typeof import('./src/components/Confirm.vue')['default'] + Login: typeof import('./src/components/Login.vue')['default'] + MonitorListItem: typeof import('./src/components/MonitorListItem.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + StackList: typeof import('./src/components/StackList.vue')['default'] + StackListItem: typeof import('./src/components/StackListItem.vue')['default'] + } +} diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..bd46fe2 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + Dockge + + + + +
+ + + diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dedf0cd3ccaf010297785c5b2820df5af6762613 GIT binary patch literal 15086 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 N002ovPDHLkV1j>wKivQT literal 0 HcmV?d00001 diff --git a/frontend/public/icon-512x512.png b/frontend/public/icon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..cd3ab7718da26bf86ef5bc6fe4fb2d0dd62bd527 GIT binary patch literal 9739 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 + + +Created with Fabric.js 5.3.0 + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json new file mode 100644 index 0000000..e62d262 --- /dev/null +++ b/frontend/public/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Dockge", + "short_name": "Dockge", + "start_url": "/", + "background_color": "#fff", + "display": "standalone", + "icons": [ + { + "src": "icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..aef300e --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,9 @@ + + + diff --git a/frontend/src/components/Confirm.vue b/frontend/src/components/Confirm.vue new file mode 100644 index 0000000..e855b67 --- /dev/null +++ b/frontend/src/components/Confirm.vue @@ -0,0 +1,84 @@ + + + diff --git a/frontend/src/components/Login.vue b/frontend/src/components/Login.vue new file mode 100644 index 0000000..b10a072 --- /dev/null +++ b/frontend/src/components/Login.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/frontend/src/components/StackList.vue b/frontend/src/components/StackList.vue new file mode 100644 index 0000000..284af44 --- /dev/null +++ b/frontend/src/components/StackList.vue @@ -0,0 +1,455 @@ + + + + + diff --git a/frontend/src/components/StackListItem.vue b/frontend/src/components/StackListItem.vue new file mode 100644 index 0000000..62e4ead --- /dev/null +++ b/frontend/src/components/StackListItem.vue @@ -0,0 +1,261 @@ + + + + + diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts new file mode 100644 index 0000000..64b575c --- /dev/null +++ b/frontend/src/i18n.ts @@ -0,0 +1,35 @@ +import { createI18n } from "vue-i18n"; +import en from "./lang/en.json"; + +const languageList = { + +}; + +let messages = { + en, +}; + +for (let lang in languageList) { + messages[lang] = { + languageName: languageList[lang] + }; +} + +const rtlLangs = [ "fa", "ar-SY", "ur" ]; + +export const currentLocale = () => localStorage.locale + || languageList[navigator.language] && navigator.language + || languageList[navigator.language.substring(0, 2)] && navigator.language.substring(0, 2) + || "en"; + +export const localeDirection = () => { + return rtlLangs.includes(currentLocale()) ? "rtl" : "ltr"; +}; + +export const i18n = createI18n({ + locale: currentLocale(), + fallbackLocale: "en", + silentFallbackWarn: true, + silentTranslationWarn: true, + messages: messages, +}); diff --git a/frontend/src/icon.ts b/frontend/src/icon.ts new file mode 100644 index 0000000..e1e757c --- /dev/null +++ b/frontend/src/icon.ts @@ -0,0 +1,107 @@ +import { library } from "@fortawesome/fontawesome-svg-core"; +import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; + +// Add Free Font Awesome Icons +// https://fontawesome.com/v6/icons?d=gallery&p=2&s=solid&m=free +// In order to add an icon, you have to: +// 1) add the icon name in the import statement below; +// 2) add the icon name to the library.add() statement below. +import { + faArrowAltCircleUp, + faCog, + faEdit, + faEye, + faEyeSlash, + faList, + faPause, + faPlay, + faPlus, + faSearch, + faTachometerAlt, + faTimes, + faTimesCircle, + faTrash, + faCheckCircle, + faStream, + faSave, + faExclamationCircle, + faBullhorn, + faArrowsAltV, + faUnlink, + faQuestionCircle, + faImages, + faUpload, + faCopy, + faCheck, + faFile, + faAward, + faLink, + faChevronDown, + faSignOutAlt, + faPen, + faExternalLinkSquareAlt, + faSpinner, + faUndo, + faPlusCircle, + faAngleDown, + faWrench, + faHeartbeat, + faFilter, + faInfoCircle, + faClone, + faCertificate, + faTerminal, faWarehouse, faHome, +} from "@fortawesome/free-solid-svg-icons"; + +library.add( + faArrowAltCircleUp, + faCog, + faEdit, + faEye, + faEyeSlash, + faList, + faPause, + faPlay, + faPlus, + faSearch, + faTachometerAlt, + faTimes, + faTimesCircle, + faTrash, + faCheckCircle, + faStream, + faSave, + faExclamationCircle, + faBullhorn, + faArrowsAltV, + faUnlink, + faQuestionCircle, + faImages, + faUpload, + faCopy, + faCheck, + faFile, + faAward, + faLink, + faChevronDown, + faSignOutAlt, + faPen, + faExternalLinkSquareAlt, + faSpinner, + faUndo, + faPlusCircle, + faAngleDown, + faLink, + faWrench, + faHeartbeat, + faFilter, + faInfoCircle, + faClone, + faCertificate, + faTerminal, + faWarehouse, + faHome, +); + +export { FontAwesomeIcon }; + diff --git a/frontend/src/lang/en.json b/frontend/src/lang/en.json new file mode 100644 index 0000000..443db89 --- /dev/null +++ b/frontend/src/lang/en.json @@ -0,0 +1,12 @@ +{ + "languageName": "English", + "authIncorrectCreds": "Incorrect username or password.", + "PasswordsDoNotMatch": "Passwords do not match.", + "signedInDisp": "Signed in as {0}", + "signedInDispDisabled": "Auth Disabled.", + "home": "Home", + "console": "Console", + "registry": "Registry", + "compose": "Compose", + "addFirstStackMsg": "Compose your first stack!" +} diff --git a/frontend/src/layouts/EmptyLayout.vue b/frontend/src/layouts/EmptyLayout.vue new file mode 100644 index 0000000..825ec93 --- /dev/null +++ b/frontend/src/layouts/EmptyLayout.vue @@ -0,0 +1,8 @@ + + + + diff --git a/frontend/src/layouts/Layout.vue b/frontend/src/layouts/Layout.vue new file mode 100644 index 0000000..88d5b9d --- /dev/null +++ b/frontend/src/layouts/Layout.vue @@ -0,0 +1,326 @@ + + + + + diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..6acbef5 --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,118 @@ +import { createApp, defineComponent, h } from "vue"; +import App from "./App.vue"; +import { router } from "./router"; +import { FontAwesomeIcon } from "./icon.js"; +import { i18n } from "./i18n"; + +// Dependencies +import "bootstrap"; +import Toast, { POSITION, useToast } from "vue-toastification"; +import "xterm/lib/xterm.js"; + +// CSS +import "vue-toastification/dist/index.css"; +import "xterm/css/xterm.css"; +import "./styles/main.scss"; + +// Dayjs +import dayjs from "dayjs"; +import timezone from "dayjs/plugin/timezone"; +import utc from "dayjs/plugin/utc"; +import relativeTime from "dayjs/plugin/relativeTime"; + +// Minxins +import socket from "./mixins/socket"; +import lang from "./mixins/lang"; +import theme from "./mixins/theme"; + +dayjs.extend(utc); +dayjs.extend(timezone); +dayjs.extend(relativeTime); + +const app = createApp(rootApp()); + +app.use(Toast, { + position: POSITION.BOTTOM_RIGHT, + containerClassName: "toast-container mb-5", + showCloseButtonOnHover: true, + + filterBeforeCreate: (toast, toasts) => { + if (toast.timeout === 0) { + return false; + } else { + return toast; + } + }, +}); + +app.use(router); +app.use(i18n); +app.component("FontAwesomeIcon", FontAwesomeIcon); +app.mount("#app"); + +/** + * Root Vue component + */ +function rootApp() { + const toast = useToast(); + + return defineComponent({ + mixins: [ + socket, + lang, + theme, + ], + data() { + return { + loggedIn: false, + allowLoginDialog: false, + username: null, + }; + }, + computed: { + + }, + methods: { + + /** + * Show success or error toast dependant on response status code + * @param {object} res Response object + * @returns {void} + */ + toastRes(res) { + let msg = res.msg; + if (res.msgi18n) { + if (msg != null && typeof msg === "object") { + msg = this.$t(msg.key, msg.values); + } else { + msg = this.$t(msg); + } + } + + if (res.ok) { + toast.success(msg); + } else { + toast.error(msg); + } + }, + /** + * Show a success toast + * @param {string} msg Message to show + * @returns {void} + */ + toastSuccess(msg : string) { + toast.success(this.$t(msg)); + }, + + /** + * Show an error toast + * @param {string} msg Message to show + * @returns {void} + */ + toastError(msg : string) { + toast.error(this.$t(msg)); + }, + }, + render: () => h(App), + }); +} diff --git a/frontend/src/mixins/lang.ts b/frontend/src/mixins/lang.ts new file mode 100644 index 0000000..1a9ab93 --- /dev/null +++ b/frontend/src/mixins/lang.ts @@ -0,0 +1,39 @@ +import { currentLocale } from "../i18n"; +import { setPageLocale } from "../util-frontend"; +import { defineComponent } from "vue"; +const langModules = import.meta.glob("../lang/*.json"); + +export default defineComponent({ + data() { + return { + language: currentLocale(), + }; + }, + + watch: { + async language(lang) { + await this.changeLang(lang); + }, + }, + + async created() { + if (this.language !== "en") { + await this.changeLang(this.language); + } + }, + + methods: { + /** + * Change the application language + * @param {string} lang Language code to switch to + * @returns {Promise} + */ + async changeLang(lang : string) { + const message = (await langModules["../lang/" + lang + ".json"]()).default; + this.$i18n.setLocaleMessage(lang, message); + this.$i18n.locale = lang; + localStorage.locale = lang; + setPageLocale(); + } + } +}); diff --git a/frontend/src/mixins/socket.ts b/frontend/src/mixins/socket.ts new file mode 100644 index 0000000..47a467b --- /dev/null +++ b/frontend/src/mixins/socket.ts @@ -0,0 +1,281 @@ +import { io } from "socket.io-client"; +import { Socket } from "socket.io-client"; +import { defineComponent } from "vue"; +import jwtDecode from "jwt-decode"; +import { Terminal } from "xterm"; +import { FitAddon } from "xterm-addon-fit"; +import { WebLinksAddon } from "xterm-addon-web-links"; + +const terminal = new Terminal({ + fontSize: 16, + fontFamily: "monospace", + cursorBlink: true, +}); +terminal.loadAddon(new FitAddon()); +terminal.loadAddon(new WebLinksAddon()); +let terminalInputBuffer = ""; +let cursorPosition = 0; +let socket : Socket; + +function removeInput() { + const backspaceCount = terminalInputBuffer.length; + const backspaces = "\b \b".repeat(backspaceCount); + cursorPosition = 0; + terminal.write(backspaces); + terminalInputBuffer = ""; +} + +export default defineComponent({ + data() { + return { + socketIO: { + token: null, + firstConnect: true, + connected: false, + connectCount: 0, + initedSocketIO: false, + connectionErrorMsg: `${this.$t("Cannot connect to the socket server.")} ${this.$t("Reconnecting...")}`, + showReverseProxyGuide: true, + }, + info: { + + }, + remember: (localStorage.remember !== "0"), + loggedIn: false, + allowLoginDialog: false, + username: null, + + stackList: {}, + }; + }, + computed: { + usernameFirstChar() { + if (typeof this.username == "string" && this.username.length >= 1) { + return this.username.charAt(0).toUpperCase(); + } else { + return "🐻"; + } + }, + }, + watch: { + remember() { + localStorage.remember = (this.remember) ? "1" : "0"; + }, + }, + created() { + this.initSocketIO(); + }, + mounted() { + terminal.onKey(e => { + const code = e.key.charCodeAt(0); + console.debug("Encode: " + JSON.stringify(e.key)); + + if (e.key === "\r") { + // Return if no input + if (terminalInputBuffer.length === 0) { + return; + } + + const buffer = terminalInputBuffer; + + // Remove the input from the terminal + removeInput(); + + socket.emit("terminalInput", buffer + e.key, (err) => { + this.toastError(err.msg); + }); + + } else if (code === 127) { // Backspace + if (cursorPosition > 0) { + terminal.write("\b \b"); + cursorPosition--; + terminalInputBuffer = terminalInputBuffer.slice(0, -1); + } + } else if (e.key === "\u001B\u005B\u0041" || e.key === "\u001B\u005B\u0042") { // UP OR DOWN + // Do nothing + + } else if (e.key === "\u001B\u005B\u0043") { // RIGHT + // TODO + } else if (e.key === "\u001B\u005B\u0044") { // LEFT + // TODO + } else if (e.key === "\u0003") { // Ctrl + C + console.debug("Ctrl + C"); + removeInput(); + } else { + cursorPosition++; + terminalInputBuffer += e.key; + console.log(terminalInputBuffer); + terminal.write(e.key); + } + }); + }, + methods: { + /** + * Initialize connection to socket server + * @param bypass Should the check for if we + * are on a status page be bypassed? + */ + initSocketIO(bypass = false) { + // No need to re-init + if (this.socketIO.initedSocketIO) { + return; + } + + this.socketIO.initedSocketIO = true; + let url : string; + const env = process.env.NODE_ENV || "production"; + if (env === "development" || localStorage.dev === "dev") { + url = location.protocol + "//" + location.hostname + ":5001"; + } else { + url = location.protocol + "//" + location.host; + } + + socket = io(url, { + + }); + + socket.on("connect", () => { + console.log("Connected to the socket server"); + + this.socketIO.connectCount++; + this.socketIO.connected = true; + this.socketIO.showReverseProxyGuide = false; + const token = this.storage().token; + + if (token) { + if (token !== "autoLogin") { + console.log("Logging in by token"); + this.loginByToken(token); + } else { + // Timeout if it is not actually auto login + setTimeout(() => { + if (! this.loggedIn) { + this.allowLoginDialog = true; + this.storage().removeItem("token"); + } + }, 5000); + } + } else { + this.allowLoginDialog = true; + } + + this.socketIO.firstConnect = false; + }); + + socket.on("disconnect", () => { + console.log("disconnect"); + this.socketIO.connectionErrorMsg = "Lost connection to the socket server. Reconnecting..."; + this.socketIO.connected = false; + }); + + socket.on("connect_error", (err) => { + console.error(`Failed to connect to the backend. Socket.io connect_error: ${err.message}`); + this.socketIO.connectionErrorMsg = `${this.$t("Cannot connect to the socket server.")} [${err}] ${this.$t("Reconnecting...")}`; + this.socketIO.showReverseProxyGuide = true; + this.socketIO.connected = false; + this.socketIO.firstConnect = false; + }); + + // Custom Events + + socket.on("info", (info) => { + this.info = info; + }); + + socket.on("autoLogin", () => { + this.loggedIn = true; + this.storage().token = "autoLogin"; + this.socketIO.token = "autoLogin"; + this.allowLoginDialog = false; + this.afterLogin(); + }); + + socket.on("setup", () => { + console.log("setup"); + this.$router.push("/setup"); + }); + + socket.on("commandOutput", (data) => { + terminal.write(data); + }); + }, + + /** + * The storage currently in use + * @returns Current storage + */ + storage() : Storage { + return (this.remember) ? localStorage : sessionStorage; + }, + + getSocket() : Socket { + return socket; + }, + + getTerminal() : Terminal { + return terminal; + }, + + /** + * Get payload of JWT cookie + * @returns {(object | undefined)} JWT payload + */ + getJWTPayload() { + const jwtToken = this.storage().token; + + if (jwtToken && jwtToken !== "autoLogin") { + return jwtDecode(jwtToken); + } + return undefined; + }, + + /** + * Log in using a token + * @param {string} token Token to log in with + * @returns {void} + */ + loginByToken(token : string) { + socket.emit("loginByToken", token, (res) => { + this.allowLoginDialog = true; + + if (! res.ok) { + this.logout(); + } else { + this.loggedIn = true; + this.username = this.getJWTPayload()?.username; + this.afterLogin(); + } + }); + }, + + /** + * Log out of the web application + * @returns {void} + */ + logout() { + socket.emit("logout", () => { }); + this.storage().removeItem("token"); + this.socketIO.token = null; + this.loggedIn = false; + this.username = null; + this.clearData(); + }, + + /** + * @returns {void} + */ + clearData() { + + }, + + afterLogin() { + terminal.clear(); + // Load terminal, get terminal screen + socket.emit("getTerminalBuffer", (res) => { + console.log("getTerminalBuffer"); + terminal.write(res.buffer); + }); + }, + + } +}); diff --git a/frontend/src/mixins/theme.ts b/frontend/src/mixins/theme.ts new file mode 100644 index 0000000..3982d04 --- /dev/null +++ b/frontend/src/mixins/theme.ts @@ -0,0 +1,80 @@ +import { defineComponent } from "vue"; + +export default defineComponent({ + data() { + return { + system: (window.matchMedia("(prefers-color-scheme: dark)").matches) ? "dark" : "light", + userTheme: localStorage.theme, + statusPageTheme: "light", + forceStatusPageTheme: false, + path: "", + }; + }, + + computed: { + theme() { + if (this.userTheme === "auto") { + return this.system; + } + return this.userTheme; + }, + + isDark() { + return this.theme === "dark"; + } + }, + + watch: { + "$route.fullPath"(path) { + this.path = path; + }, + + userTheme(to, from) { + localStorage.theme = to; + }, + + styleElapsedTime(to, from) { + localStorage.styleElapsedTime = to; + }, + + theme(to, from) { + document.body.classList.remove(from); + document.body.classList.add(this.theme); + this.updateThemeColorMeta(); + }, + + userHeartbeatBar(to, from) { + localStorage.heartbeatBarTheme = to; + }, + + heartbeatBarTheme(to, from) { + document.body.classList.remove(from); + document.body.classList.add(this.heartbeatBarTheme); + } + }, + + mounted() { + // Default Dark + if (! this.userTheme) { + this.userTheme = "dark"; + } + + document.body.classList.add(this.theme); + this.updateThemeColorMeta(); + }, + + methods: { + /** + * Update the theme color meta tag + * @returns {void} + */ + updateThemeColorMeta() { + if (this.theme === "dark") { + document.querySelector("#theme-color").setAttribute("content", "#161B22"); + } else { + document.querySelector("#theme-color").setAttribute("content", "#5cdd8b"); + } + } + } +}); + diff --git a/frontend/src/pages/Compose.vue b/frontend/src/pages/Compose.vue new file mode 100644 index 0000000..d190ce1 --- /dev/null +++ b/frontend/src/pages/Compose.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/frontend/src/pages/Console.vue b/frontend/src/pages/Console.vue new file mode 100644 index 0000000..3c66cb5 --- /dev/null +++ b/frontend/src/pages/Console.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/frontend/src/pages/Dashboard.vue b/frontend/src/pages/Dashboard.vue new file mode 100644 index 0000000..1fc2d84 --- /dev/null +++ b/frontend/src/pages/Dashboard.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/frontend/src/pages/DashboardHome.vue b/frontend/src/pages/DashboardHome.vue new file mode 100644 index 0000000..974e09e --- /dev/null +++ b/frontend/src/pages/DashboardHome.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/frontend/src/pages/EditStack.vue b/frontend/src/pages/EditStack.vue new file mode 100644 index 0000000..aadf393 --- /dev/null +++ b/frontend/src/pages/EditStack.vue @@ -0,0 +1,14 @@ + + + + + diff --git a/frontend/src/pages/Setup.vue b/frontend/src/pages/Setup.vue new file mode 100644 index 0000000..d8ec406 --- /dev/null +++ b/frontend/src/pages/Setup.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/frontend/src/router.ts b/frontend/src/router.ts new file mode 100644 index 0000000..9470552 --- /dev/null +++ b/frontend/src/router.ts @@ -0,0 +1,49 @@ +import { createRouter, createWebHistory } from "vue-router"; + +import Layout from "./layouts/Layout.vue"; +import Setup from "./pages/Setup.vue"; +import Dashboard from "./pages/Dashboard.vue"; +import DashboardHome from "./pages/DashboardHome.vue"; +import EditStack from "./pages/EditStack.vue"; +import Console from "./pages/Console.vue"; + +const routes = [ + { + path: "/empty", + component: Layout, + children: [ + { + path: "", + component: Dashboard, + children: [ + { + name: "DashboardHome", + path: "/", + component: DashboardHome, + children: [ + { + path: "/compose", + component: EditStack, + }, + + ] + }, + { + path: "/console", + component: Console, + }, + ] + }, + ] + }, + { + path: "/setup", + component: Setup, + }, +]; + +export const router = createRouter({ + linkActiveClass: "active", + history: createWebHistory(), + routes, +}); diff --git a/frontend/src/styles/localization.scss b/frontend/src/styles/localization.scss new file mode 100644 index 0000000..97be377 --- /dev/null +++ b/frontend/src/styles/localization.scss @@ -0,0 +1,9 @@ +html[lang='fa'] { + #app { + font-family: 'IRANSans', 'Iranian Sans','B Nazanin', 'Tahoma', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; + } +} + +ul.multiselect__content { + padding-left: 0 !important; +} diff --git a/frontend/src/styles/main.scss b/frontend/src/styles/main.scss new file mode 100644 index 0000000..3f64be0 --- /dev/null +++ b/frontend/src/styles/main.scss @@ -0,0 +1,664 @@ +@import "vars.scss"; +@import "bootstrap/scss/bootstrap"; +@import "bootstrap-vue-next/dist/bootstrap-vue-next.css"; + +#app { + font-family: BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; +} + +h1 { + font-size: 32px; +} + +h2 { + font-size: 26px; +} + +textarea.form-control { + border-radius: 19px; +} + +::-webkit-scrollbar { + width: 10px; +} + +.bg-maintenance { + color: white !important; + background-color: $maintenance !important; +} + +.bg-dark { + color: white; +} + +.text-maintenance { + color: $maintenance !important; +} + +.incident a, +.bg-maintenance a { + color: inherit; +} + +.list-group { + border-radius: 0.75rem; + + .dark & { + .list-group-item { + background-color: $dark-bg; + color: $dark-font-color; + border-color: $dark-border-color; + } + } +} + + +// optgroup +optgroup { + color: #b1b1b1; + option { + color: #212529; + } +} + +.dark { + optgroup { + color: #535864; + option { + color: $dark-font-color; + } + } +} + +// Scrollbar +::-webkit-scrollbar-thumb { + background: #ccc; + border-radius: 20px; +} + +.modal { + backdrop-filter: blur(3px); +} + +.modal-content { + border-radius: 1rem; + box-shadow: 0 15px 70px rgba(0, 0, 0, 0.1); + + .dark & { + box-shadow: 0 15px 70px rgb(0 0 0); + background-color: $dark-bg; + } +} + +.VuePagination__count { + font-size: 13px; + text-align: center; +} + +.shadow-box { + box-shadow: 0 15px 70px rgba(0, 0, 0, 0.1); + padding: 10px; + border-radius: 10px; + + &.big-padding { + padding: 20px; + } +} + +.btn { + padding-left: 20px; + padding-right: 20px; +} + +.btn-sm { + border-radius: 25px; +} + +.btn-primary { + color: white; + background: $primary-gradient; + + &:hover, &:active, &:focus, &.active { + color: white; + background: $primary-gradient-active; + border-color: $highlight; + } + + .dark & { + color: $dark-font-color2; + } +} + +.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; + + &:hover, &:active, &:focus, &.active { + color: white; + } +} + +.btn-info { + color: white; + + &:hover, &:active, &:focus, &.active { + color: white; + } +} + +.btn-dark { + background-color: #161B22; +} + +.btn-outline-normal { + padding: 4px 10px; + border: 1px solid #ced4da; + border-radius: 25px; + background-color: transparent; + + .dark & { + color: $dark-font-color; + border: 1px solid $dark-font-color2; + } + + &.active { + background-color: $highlight-white; + + .dark & { + background-color: $dark-font-color2; + } + } +} + +@media (max-width: 550px) { + .table-shadow-box { + padding: 10px !important; + + thead { + display: none; + } + + tbody { + .shadow-box { + background-color: white; + } + } + + tr { + margin-top: 0 !important; + padding: 4px 10px !important; + display: block; + margin-bottom: 6px; + + td:first-child { + font-weight: bold; + } + + td:nth-child(-n+3) { + text-align: center; + } + + td:last-child { + text-align: left; + } + + td { + border-bottom: 1px solid $dark-font-color; + display: block; + padding: 4px; + + .badge { + margin: auto; + display: block; + width: 30%; + } + } + } + } +} + +// Dark Theme override here +.dark { + background-color: #090c10; + color: $dark-font-color; + + mark, .mark { + background-color: #b6ad86; + } + + &::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb { + background: $dark-border-color; + } + + .shadow-box { + &:not(.alert) { + background-color: $dark-bg; + } + } + + .form-check-input { + background-color: $dark-bg2; + border-color: $dark-border-color; + } + + .input-group-text { + background-color: #282f39; + border-color: $dark-border-color; + color: $dark-font-color; + } + + .form-check-input:checked { + border-color: $primary; // Re-apply bootstrap border + } + + .form-switch .form-check-input { + background-color: #232f3b; + } + + a:not(.btn), + .table, + .nav-link { + color: $dark-font-color; + + &.btn-info { + color: white; + } + } + + .incident a, + .bg-maintenance a { + color: inherit; + } + + .form-control, + .form-control:focus, + .form-select, + .form-select:focus { + color: $dark-font-color; + background-color: $dark-bg2; + } + + .form-select:disabled { + color: rgba($dark-font-color, 0.7); + background-color: $dark-bg; + } + + .form-control, .form-select { + border-color: $dark-border-color; + } + + .form-control:disabled, .form-control[readonly] { + background-color: #232f3b; + opacity: 1; + } + + .table-hover > tbody > tr:hover > * { + --bs-table-accent-bg: #070a10; + color: $dark-font-color; + } + + .nav-pills .nav-link.active, .nav-pills .show > .nav-link { + color: $dark-font-color2; + background: $primary-gradient; + + &:hover { + background: $primary-gradient-active; + } + } + + .bg-primary { + color: $dark-font-color2; + } + + .btn-secondary { + 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; + + &:hover, &:active, &:focus, &.active { + color: $dark-font-color2; + } + } + + .btn-close { + box-shadow: none; + filter: invert(1); + + &:hover { + opacity: 0.6; + } + } + + .modal-header { + border-color: $dark-bg; + } + + .modal-footer { + border-color: $dark-bg; + } + + // Pagination + .page-item.disabled .page-link { + background-color: $dark-bg; + border-color: $dark-border-color; + } + + .page-link { + background-color: $dark-bg; + border-color: $dark-border-color; + color: $dark-font-color; + } + + .monitor-list { + .item { + &:hover { + background-color: $dark-bg2; + } + + &.active { + background-color: $dark-bg2; + } + } + } + + @media (max-width: 550px) { + .table-shadow-box { + tbody { + .shadow-box { + background-color: $dark-bg2; + + td { + border-bottom: 1px solid $dark-border-color; + } + } + } + } + } + + .alert { + &.bg-info, + &.bg-warning, + &.bg-danger, + &.bg-maintenance, + &.bg-light { + color: $dark-font-color2; + } + } +} + +// Floating Label +.form-floating > .form-control:focus ~ label::after, .form-floating > .form-control:not(:placeholder-shown) ~ label::after, .form-floating > .form-control-plaintext ~ label::after, .form-floating > .form-select ~ label::after { + background-color: transparent; + + +} +.form-floating > label { + .dark & { + color: $dark-font-color3 !important; + } +} + + +/* + * Transitions + */ + +// page-change +.slide-fade-enter-active { + transition: all 0.2s $easing-in; +} + +.slide-fade-leave-active { + transition: all 0.2s $easing-in; +} + +.slide-fade-enter-from, +.slide-fade-leave-to { + transform: translateY(50px); + opacity: 0; +} + +.slide-fade-right-enter-active { + transition: all 0.2s $easing-in; +} + +.slide-fade-right-leave-active { + transition: all 0.2s $easing-in; +} + +.slide-fade-right-enter-from, +.slide-fade-right-leave-to { + transform: translateX(50px); + opacity: 0; +} + +.slide-fade-up-enter-active { + transition: all 0.2s $easing-in; +} + +.slide-fade-up-leave-active { + transition: all 0.2s $easing-in; +} + +.slide-fade-up-enter-from, +.slide-fade-up-leave-to { + transform: translateY(-50px); + opacity: 0; +} + +.monitor-list { + &.scrollbar { + overflow-y: auto; + } + + @media (max-width: 770px) { + &.scrollbar { + height: calc(100% - 97px); + } + } + + .item { + display: block; + text-decoration: none; + padding: 13px 15px 10px 15px; + border-radius: 10px; + transition: all ease-in-out 0.15s; + + &.disabled { + opacity: 0.3; + } + + .info { + white-space: nowrap; + overflow: hidden; + } + + &:hover { + background-color: $highlight-white; + } + + &.active { + background-color: #cdf8f4; + } + .tags { + // Removes margin to line up tags list with uptime percentage + margin-left: -0.25rem; + } + } +} + +.alert-success { + color: #122f21; + background-color: $primary; + border-color: $primary; +} + +.alert-info { + color: #055160; + background-color: #cff4fc; + border-color: #cff4fc; +} + +.alert-danger { + color: #842029; + background-color: #f8d7da; + border-color: #f8d7da; +} + +.btn-success { + color: #fff; + background-color: #4caf50; + border-color: #4caf50; +} + + +[contenteditable=true] { + transition: all $easing-in 0.2s; + background-color: rgba(239, 239, 239, 0.7); + border-radius: 8px; + + &.no-bg { + background-color: transparent !important; + } + + &:focus { + outline: 0 solid #eee; + background-color: rgba(245, 245, 245, 0.9); + } + + &:hover { + background-color: rgba(239, 239, 239, 0.8); + } + + .dark & { + background-color: rgba(239, 239, 239, 0.2); + } + + /* + &::after { + margin-left: 5px; + content: "🖊️"; + font-size: 13px; + color: #eee; + } + */ + +} + +.action { + transition: all $easing-in 0.2s; + + &:hover { + cursor: pointer; + transform: scale(1.2); + } +} + +.vue-image-crop-upload .vicp-wrap { + border-radius: 10px !important; +} + +.spinner { + color: $primary; +} + +.prism-editor__textarea { + outline: none !important; +} + +h5.settings-subheading::after { + content: ""; + display: block; + width: 50%; + padding-top: 8px; + border-bottom: 1px solid $dark-border-color; +} + +/* required class */ +.code-editor, .css-editor { + /* we dont use `language-` classes anymore so thats why we need to add background and text color manually */ + + border-radius: 1rem; + padding: 10px 5px; + border: 1px solid #ced4da; + + .dark & { + background: $dark-bg2; + border: 1px solid $dark-border-color; + } +} + + +$shadow-box-padding: 20px; + +.shadow-box-with-fixed-bottom-bar { + padding-top: $shadow-box-padding; + padding-bottom: 0; + padding-right: $shadow-box-padding; + padding-left: $shadow-box-padding; +} + +.fixed-bottom-bar { + position: sticky; + bottom: 0; + margin-left: -$shadow-box-padding; + margin-right: -$shadow-box-padding; + z-index: 100; + background-color: rgba(white, 0.2); + backdrop-filter: blur(2px); + border-radius: 0 0 10px 10px; + + .dark & { + background-color: rgba($dark-header-bg, 0.9); + } +} + +@media (max-width: 770px) { + .toast-container { + margin-bottom: 100px !important; + } +} + +@media (max-width: 550px) { + .toast-container { + margin-bottom: 126px !important; + } +} + +#terminal { + .xterm-viewport { + border-radius: 10px; + background-color: $dark-bg !important; + } +} + +// Localization +@import "localization.scss"; diff --git a/frontend/src/styles/vars.scss b/frontend/src/styles/vars.scss new file mode 100644 index 0000000..5595da2 --- /dev/null +++ b/frontend/src/styles/vars.scss @@ -0,0 +1,26 @@ +$primary: #74c2ff; +$danger: #dc3545; +$warning: #f8a306; +$maintenance: #1747f5; +$link-color: #111; +$border-radius: 50rem; + +$highlight: #9dd1ff; +$highlight-white: #e7faec; + +$dark-font-color: #b1b8c0; +$dark-font-color2: #020b05; +$dark-font-color3: #575c62; +$dark-bg: #0d1117; +$dark-bg2: #070a10; +$dark-border-color: #1d2634; +$dark-header-bg: #161b22; + +$easing-in: cubic-bezier(0.54, 0.78, 0.55, 0.97); +$easing-out: cubic-bezier(0.25, 0.46, 0.45, 0.94); +$easing-in-out: cubic-bezier(0.79, 0.14, 0.15, 0.86); + +$dropdown-border-radius: 0.5rem; + +$primary-gradient: linear-gradient(135deg, #74c2ff 0%, #74c2ff 75%, #86e6a9); +$primary-gradient-active: linear-gradient(135deg, #74c2ff 0%, #74c2ff 50%, #86e6a9); diff --git a/frontend/src/util-frontend.ts b/frontend/src/util-frontend.ts new file mode 100644 index 0000000..1e30160 --- /dev/null +++ b/frontend/src/util-frontend.ts @@ -0,0 +1,214 @@ +import dayjs from "dayjs"; +import timezones from "timezones-list"; +import { localeDirection, currentLocale } from "./i18n"; +import { POSITION } from "vue-toastification"; + +/** + * Returns the offset from UTC in hours for the current locale. + * @param {string} timeZone Timezone to get offset for + * @returns {number} The offset from UTC in hours. + * + * Generated by Trelent + */ +function getTimezoneOffset(timeZone) { + const now = new Date(); + const tzString = now.toLocaleString("en-US", { + timeZone, + }); + const localString = now.toLocaleString("en-US"); + const diff = (Date.parse(localString) - Date.parse(tzString)) / 3600000; + const offset = diff + now.getTimezoneOffset() / 60; + return -offset; +} + +/** + * Returns a list of timezones sorted by their offset from UTC. + * @returns {object[]} A list of the given timezones sorted by their offset from UTC. + * + * Generated by Trelent + */ +export function timezoneList() { + let result = []; + + for (let timezone of timezones) { + try { + let display = dayjs().tz(timezone.tzCode).format("Z"); + + result.push({ + name: `(UTC${display}) ${timezone.tzCode}`, + value: timezone.tzCode, + time: getTimezoneOffset(timezone.tzCode), + }); + } catch (e) { + // Skipping not supported timezone.tzCode by dayjs + } + } + + result.sort((a, b) => { + if (a.time > b.time) { + return 1; + } + + if (b.time > a.time) { + return -1; + } + + return 0; + }); + + return result; +} + +/** + * Set the locale of the HTML page + * @returns {void} + */ +export function setPageLocale() { + const html = document.documentElement; + html.setAttribute("lang", currentLocale() ); + html.setAttribute("dir", localeDirection() ); +} + +/** + * Get the base URL + * Mainly used for dev, because the backend and the frontend are in different ports. + * @returns {string} Base URL + */ +export function getResBaseURL() { + const env = process.env.NODE_ENV; + if (env === "development" && isDevContainer()) { + return location.protocol + "//" + getDevContainerServerHostname(); + } else if (env === "development" || localStorage.dev === "dev") { + return location.protocol + "//" + location.hostname + ":3001"; + } else { + return ""; + } +} + +/** + * Are we currently running in a dev container? + * @returns {boolean} Running in dev container? + */ +export function isDevContainer() { + // eslint-disable-next-line no-undef + return (typeof DEVCONTAINER === "string" && DEVCONTAINER === "1"); +} + +/** + * Supports GitHub Codespaces only currently + * @returns {string} Dev container server hostname + */ +export function getDevContainerServerHostname() { + if (!isDevContainer()) { + return ""; + } + + // eslint-disable-next-line no-undef + return CODESPACE_NAME + "-3001." + GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN; +} + +/** + * Regex pattern fr identifying hostnames and IP addresses + * @param {boolean} mqtt whether or not the regex should take into + * account the fact that it is an mqtt uri + * @returns {RegExp} The requested regex + */ +export function hostNameRegexPattern(mqtt = false) { + // mqtt, mqtts, ws and wss schemes accepted by mqtt.js (https://github.com/mqttjs/MQTT.js/#connect) + const mqttSchemeRegexPattern = "((mqtt|ws)s?:\\/\\/)?"; + // Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/ + const ipRegexPattern = `((^${mqtt ? mqttSchemeRegexPattern : ""}((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))$)|(^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$))`; + // Source: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address + const hostNameRegexPattern = `^${mqtt ? mqttSchemeRegexPattern : ""}([a-zA-Z0-9])?(([a-zA-Z0-9_]|[a-zA-Z0-9_][a-zA-Z0-9\\-_]*[a-zA-Z0-9_])\\.)*([A-Za-z0-9_]|[A-Za-z0-9_][A-Za-z0-9\\-_]*[A-Za-z0-9_])(\\.)?$`; + + return `${ipRegexPattern}|${hostNameRegexPattern}`; +} + +/** + * Get the tag color options + * Shared between components + * @param {any} self Component + * @returns {object[]} Colour options + */ +export function colorOptions(self) { + return [ + { name: self.$t("Gray"), + color: "#4B5563" }, + { name: self.$t("Red"), + color: "#DC2626" }, + { name: self.$t("Orange"), + color: "#D97706" }, + { name: self.$t("Green"), + color: "#059669" }, + { name: self.$t("Blue"), + color: "#2563EB" }, + { name: self.$t("Indigo"), + color: "#4F46E5" }, + { name: self.$t("Purple"), + color: "#7C3AED" }, + { name: self.$t("Pink"), + color: "#DB2777" }, + ]; +} + +/** + * Loads the toast timeout settings from storage. + * @returns {object} The toast plugin options object. + */ +export function loadToastSettings() { + return { + position: POSITION.BOTTOM_RIGHT, + containerClassName: "toast-container mb-5", + showCloseButtonOnHover: true, + + filterBeforeCreate: (toast, toasts) => { + if (toast.timeout === 0) { + return false; + } else { + return toast; + } + }, + }; +} + +/** + * Get timeout for success toasts + * @returns {(number|boolean)} Timeout in ms. If false timeout disabled. + */ +export function getToastSuccessTimeout() { + let successTimeout = 20000; + + if (localStorage.toastSuccessTimeout !== undefined) { + const parsedTimeout = parseInt(localStorage.toastSuccessTimeout); + if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) { + successTimeout = parsedTimeout; + } + } + + if (successTimeout === -1) { + successTimeout = false; + } + + return successTimeout; +} + +/** + * Get timeout for error toasts + * @returns {(number|boolean)} Timeout in ms. If false timeout disabled. + */ +export function getToastErrorTimeout() { + let errorTimeout = -1; + + if (localStorage.toastErrorTimeout !== undefined) { + const parsedTimeout = parseInt(localStorage.toastErrorTimeout); + if (parsedTimeout != null && !Number.isNaN(parsedTimeout)) { + errorTimeout = parsedTimeout; + } + } + + if (errorTimeout === -1) { + errorTimeout = false; + } + + return errorTimeout; +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..899b0bc --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..da84018 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import Components from "unplugin-vue-components/vite"; +import { BootstrapVueNextResolver } from "unplugin-vue-components/resolvers"; +import viteCompression from "vite-plugin-compression"; +import "vue"; + +const viteCompressionFilter = /\.(js|mjs|json|css|html|svg)$/i; + +// https://vitejs.dev/config/ +export default defineConfig({ + server: { + port: 5000, + }, + root: "./frontend", + build: { + outDir: "../dist", + }, + plugins: [ + vue(), + Components({ + resolvers: [ BootstrapVueNextResolver() ], + }), + viteCompression({ + algorithm: "gzip", + filter: viteCompressionFilter, + }), + viteCompression({ + algorithm: "brotliCompress", + filter: viteCompressionFilter, + }), + ], +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..c5dc78c --- /dev/null +++ b/package.json @@ -0,0 +1,66 @@ +{ + "name": "dockge", + "version": "0.0.1", + "type": "module", + "scripts": { + "fmt": "eslint \"**/*.{ts,vue}\" --fix", + "lint": "eslint \"**/*.{ts,vue}\"", + "dev:backend": "cross-env NODE_ENV=development tsx watch ./backend/index.ts", + "dev:frontend": "cross-env NODE_ENV=development vite --host --config ./frontend/vite.config.ts", + "build:frontend": "vite build --config ./frontend/vite.config.ts" + }, + "dependencies": { + "@louislam/sqlite3": "~15.1.6", + "bcryptjs": "^2.4.3", + "check-password-strength": "^2.0.7", + "compare-versions": "~6.1.0", + "dayjs": "^1.11.10", + "express": "~4.18.2", + "jsonwebtoken": "^9.0.2", + "jwt-decode": "^3.1.2", + "knex": "~2.5.1", + "limiter-es6-compat": "~2.1.2", + "mysql2": "^3.6.2", + "node-pty": "^1.0.0", + "redbean-node": "0.3.1", + "socket.io": "~4.7.2", + "socket.io-client": "~4.7.2", + "timezones-list": "^3.0.2", + "ts-command-line-args": "~2.5.1", + "tsx": "~3.14.0", + "type-fest": "~4.3.3", + "yaml": "~2.3.3" + }, + "optionalDependencies": { + "pm2": "~5.3.0" + }, + "devDependencies": { + "@fortawesome/fontawesome-svg-core": "6.4.2", + "@fortawesome/free-regular-svg-icons": "6.4.2", + "@fortawesome/free-solid-svg-icons": "6.4.2", + "@fortawesome/vue-fontawesome": "3.0.3", + "@types/express": "~4.17.20", + "@typescript-eslint/eslint-plugin": "~6.8.0", + "@typescript-eslint/parser": "~6.8.0", + "@vitejs/plugin-vue": "~4.3.4", + "bootstrap": "5.3.2", + "bootstrap-vue-next": "~0.14.10", + "cross-env": "~7.0.3", + "eslint": "~8.50.0", + "eslint-plugin-jsdoc": "~46.8.2", + "eslint-plugin-vue": "~9.17.0", + "sass": "~1.68.0", + "typescript": "~5.2.2", + "unplugin-vue-components": "^0.25.2", + "vite": "~4.5.0", + "vite-plugin-compression": "^0.5.1", + "vue": "~3.3.6", + "vue-eslint-parser": "^9.3.2", + "vue-i18n": "~9.5.0", + "vue-router": "~4.2.5", + "vue-toastification": "~2.0.0-rc.5", + "xterm": "^5.3.0", + "xterm-addon-fit": "^0.8.0", + "xterm-addon-web-links": "^0.9.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..1e360fa --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4928 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@louislam/sqlite3': + specifier: ~15.1.6 + version: 15.1.6 + bcryptjs: + specifier: ^2.4.3 + version: 2.4.3 + check-password-strength: + specifier: ^2.0.7 + version: 2.0.7 + compare-versions: + specifier: ~6.1.0 + version: 6.1.0 + dayjs: + specifier: ^1.11.10 + version: 1.11.10 + express: + specifier: ~4.18.2 + version: 4.18.2 + jsonwebtoken: + specifier: ^9.0.2 + version: 9.0.2 + jwt-decode: + specifier: ^3.1.2 + version: 3.1.2 + knex: + specifier: ~2.5.1 + version: 2.5.1(mysql2@3.6.2) + limiter-es6-compat: + specifier: ~2.1.2 + version: 2.1.2 + mysql2: + specifier: ^3.6.2 + version: 3.6.2 + node-pty: + specifier: ^1.0.0 + version: 1.0.0 + redbean-node: + specifier: 0.3.1 + version: 0.3.1(mysql2@3.6.2) + socket.io: + specifier: ~4.7.2 + version: 4.7.2 + socket.io-client: + specifier: ~4.7.2 + version: 4.7.2 + timezones-list: + specifier: ^3.0.2 + version: 3.0.2 + ts-command-line-args: + specifier: ~2.5.1 + version: 2.5.1 + tsx: + specifier: ~3.14.0 + version: 3.14.0 + type-fest: + specifier: ~4.3.3 + version: 4.3.3 + yaml: + specifier: ~2.3.3 + version: 2.3.3 + +optionalDependencies: + pm2: + specifier: ~5.3.0 + version: 5.3.0 + +devDependencies: + '@fortawesome/fontawesome-svg-core': + specifier: 6.4.2 + version: 6.4.2 + '@fortawesome/free-regular-svg-icons': + specifier: 6.4.2 + version: 6.4.2 + '@fortawesome/free-solid-svg-icons': + specifier: 6.4.2 + version: 6.4.2 + '@fortawesome/vue-fontawesome': + specifier: 3.0.3 + version: 3.0.3(@fortawesome/fontawesome-svg-core@6.4.2)(vue@3.3.6) + '@types/express': + specifier: ~4.17.20 + version: 4.17.20 + '@typescript-eslint/eslint-plugin': + specifier: ~6.8.0 + version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/parser': + specifier: ~6.8.0 + version: 6.8.0(eslint@8.50.0)(typescript@5.2.2) + '@vitejs/plugin-vue': + specifier: ~4.3.4 + version: 4.3.4(vite@4.5.0)(vue@3.3.6) + bootstrap: + specifier: 5.3.2 + version: 5.3.2(@popperjs/core@2.11.8) + bootstrap-vue-next: + specifier: ~0.14.10 + version: 0.14.10(vue@3.3.6) + cross-env: + specifier: ~7.0.3 + version: 7.0.3 + eslint: + specifier: ~8.50.0 + version: 8.50.0 + eslint-plugin-jsdoc: + specifier: ~46.8.2 + version: 46.8.2(eslint@8.50.0) + eslint-plugin-vue: + specifier: ~9.17.0 + version: 9.17.0(eslint@8.50.0) + sass: + specifier: ~1.68.0 + version: 1.68.0 + typescript: + specifier: ~5.2.2 + version: 5.2.2 + unplugin-vue-components: + specifier: ^0.25.2 + version: 0.25.2(vue@3.3.6) + vite: + specifier: ~4.5.0 + version: 4.5.0(sass@1.68.0) + vite-plugin-compression: + specifier: ^0.5.1 + version: 0.5.1(vite@4.5.0) + vue: + specifier: ~3.3.6 + version: 3.3.6(typescript@5.2.2) + vue-eslint-parser: + specifier: ^9.3.2 + version: 9.3.2(eslint@8.50.0) + vue-i18n: + specifier: ~9.5.0 + version: 9.5.0(vue@3.3.6) + vue-router: + specifier: ~4.2.5 + version: 4.2.5(vue@3.3.6) + vue-toastification: + specifier: ~2.0.0-rc.5 + version: 2.0.0-rc.5(vue@3.3.6) + xterm: + specifier: ^5.3.0 + version: 5.3.0 + xterm-addon-fit: + specifier: ^0.8.0 + version: 0.8.0(xterm@5.3.0) + xterm-addon-web-links: + specifier: ^0.9.0 + version: 0.9.0(xterm@5.3.0) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@antfu/utils@0.7.6: + resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==} + dev: true + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/parser@7.23.0: + resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.0 + dev: true + + /@babel/types@7.23.0: + resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@es-joy/jsdoccomment@0.40.1: + resolution: {integrity: sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg==} + engines: {node: '>=16'} + dependencies: + comment-parser: 1.4.0 + esquery: 1.5.0 + jsdoc-type-pratt-parser: 4.0.0 + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.50.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.50.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.9.1: + resolution: {integrity: sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.23.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.50.0: + resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@floating-ui/core@1.5.0: + resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} + dependencies: + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/dom@1.5.3: + resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} + dependencies: + '@floating-ui/core': 1.5.0 + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/utils@0.1.6: + resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + dev: true + + /@floating-ui/vue@1.0.2(vue@3.3.6): + resolution: {integrity: sha512-sImlAl9mAoCKZLNlwWz2P2ZMJIDlOEDXrRD6aD2sIHAka1LPC+nWtB+D3lPe7IE7FGWSbwBPTnlSdlABa3Fr0A==} + dependencies: + '@floating-ui/dom': 1.5.3 + vue-demi: 0.14.6(vue@3.3.6) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /@fortawesome/fontawesome-common-types@6.4.2: + resolution: {integrity: sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==} + engines: {node: '>=6'} + requiresBuild: true + dev: true + + /@fortawesome/fontawesome-svg-core@6.4.2: + resolution: {integrity: sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + '@fortawesome/fontawesome-common-types': 6.4.2 + dev: true + + /@fortawesome/free-regular-svg-icons@6.4.2: + resolution: {integrity: sha512-0+sIUWnkgTVVXVAPQmW4vxb9ZTHv0WstOa3rBx9iPxrrrDH6bNLsDYuwXF9b6fGm+iR7DKQvQshUH/FJm3ed9Q==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + '@fortawesome/fontawesome-common-types': 6.4.2 + dev: true + + /@fortawesome/free-solid-svg-icons@6.4.2: + resolution: {integrity: sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + '@fortawesome/fontawesome-common-types': 6.4.2 + dev: true + + /@fortawesome/vue-fontawesome@3.0.3(@fortawesome/fontawesome-svg-core@6.4.2)(vue@3.3.6): + resolution: {integrity: sha512-KCPHi9QemVXGMrfuwf3nNnNo129resAIQWut9QTAMXmXqL2ErABC6ohd2yY5Ipq0CLWNbKHk8TMdTXL/Zf3ZhA==} + peerDependencies: + '@fortawesome/fontawesome-svg-core': ~1 || ~6 + vue: '>= 3.0.0 < 4' + dependencies: + '@fortawesome/fontawesome-svg-core': 6.4.2 + vue: 3.3.6(typescript@5.2.2) + dev: true + + /@gar/promisify@1.1.3: + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + requiresBuild: true + dev: false + optional: true + + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + dev: true + + /@intlify/core-base@9.5.0: + resolution: {integrity: sha512-y3ufM1RJbI/DSmJf3lYs9ACq3S/iRvaSsE3rPIk0MGH7fp+JxU6rdryv/EYcwfcr3Y1aHFlCBir6S391hRZ57w==} + engines: {node: '>= 16'} + dependencies: + '@intlify/message-compiler': 9.5.0 + '@intlify/shared': 9.5.0 + dev: true + + /@intlify/message-compiler@9.5.0: + resolution: {integrity: sha512-CAhVNfEZcOVFg0/5MNyt+OFjvs4J/ARjCj2b+54/FvFP0EDJI5lIqMTSDBE7k0atMROSP0SvWCkwu/AZ5xkK1g==} + engines: {node: '>= 16'} + dependencies: + '@intlify/shared': 9.5.0 + source-map-js: 1.0.2 + dev: true + + /@intlify/shared@9.5.0: + resolution: {integrity: sha512-tAxV14LMXZDZbu32XzLMTsowNlgJNmLwWHYzvMUl6L8gvQeoYiZONjY7AUsqZW8TOZDX9lfvF6adPkk9FSRdDA==} + engines: {node: '>= 16'} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: false + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@louislam/sqlite3@15.1.6: + resolution: {integrity: sha512-cVf7hcMrfywYnycatLvorngTFpL3BSWvEy7/NrEfcTyQX8xxj9fdeD553oCTv5fIAk85fluo6mzPq89V3YzrVA==} + requiresBuild: true + peerDependenciesMeta: + node-gyp: + optional: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.11 + node-addon-api: 4.3.0 + tar: 6.2.0 + optionalDependencies: + node-gyp: 8.4.1 + transitivePeerDependencies: + - bluebird + - encoding + - supports-color + dev: false + + /@mapbox/node-pre-gyp@1.0.11: + resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} + hasBin: true + dependencies: + detect-libc: 2.0.2 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.7.0 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.5.4 + tar: 6.2.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@npmcli/fs@1.1.1: + resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + requiresBuild: true + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.5.4 + dev: false + optional: true + + /@npmcli/move-file@1.1.2: + resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} + engines: {node: '>=10'} + deprecated: This functionality has been moved to @npmcli/fs + requiresBuild: true + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + dev: false + optional: true + + /@opencensus/core@0.0.8: + resolution: {integrity: sha512-yUFT59SFhGMYQgX0PhoTR0LBff2BEhPrD9io1jWfF/VDbakRfs6Pq60rjv0Z7iaTav5gQlttJCX2+VPxFWCuoQ==} + engines: {node: '>=6.0'} + requiresBuild: true + dependencies: + continuation-local-storage: 3.2.1 + log-driver: 1.2.7 + semver: 5.7.2 + shimmer: 1.2.1 + uuid: 3.4.0 + dev: false + optional: true + + /@opencensus/core@0.0.9: + resolution: {integrity: sha512-31Q4VWtbzXpVUd2m9JS6HEaPjlKvNMOiF7lWKNmXF84yUcgfAFL5re7/hjDmdyQbOp32oGc+RFV78jXIldVz6Q==} + engines: {node: '>=6.0'} + requiresBuild: true + dependencies: + continuation-local-storage: 3.2.1 + log-driver: 1.2.7 + semver: 5.7.2 + shimmer: 1.2.1 + uuid: 3.4.0 + dev: false + optional: true + + /@opencensus/propagation-b3@0.0.8: + resolution: {integrity: sha512-PffXX2AL8Sh0VHQ52jJC4u3T0H6wDK6N/4bg7xh4ngMYOIi13aR1kzVvX1sVDBgfGwDOkMbl4c54Xm3tlPx/+A==} + engines: {node: '>=6.0'} + requiresBuild: true + dependencies: + '@opencensus/core': 0.0.8 + uuid: 3.4.0 + dev: false + optional: true + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: false + optional: true + + /@pm2/agent@2.0.3: + resolution: {integrity: sha512-xkqqCoTf5VsciMqN0vb9jthW7olVAi4KRFNddCc7ZkeJZ3i8QwZANr4NSH2H5DvseRFHq7MiPspRY/EWAFWWTg==} + requiresBuild: true + dependencies: + async: 3.2.4 + chalk: 3.0.0 + dayjs: 1.8.36 + debug: 4.3.4 + eventemitter2: 5.0.1 + fast-json-patch: 3.1.1 + fclone: 1.0.11 + nssocket: 0.6.0 + pm2-axon: 4.0.1 + pm2-axon-rpc: 0.7.1 + proxy-agent: 6.3.1 + semver: 7.5.4 + ws: 7.4.6 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + optional: true + + /@pm2/io@5.0.2: + resolution: {integrity: sha512-XAvrNoQPKOyO/jJyCu8jPhLzlyp35MEf7w/carHXmWKddPzeNOFSEpSEqMzPDawsvpxbE+i918cNN+MwgVsStA==} + engines: {node: '>=6.0'} + requiresBuild: true + dependencies: + '@opencensus/core': 0.0.9 + '@opencensus/propagation-b3': 0.0.8 + async: 2.6.4 + debug: 4.3.4 + eventemitter2: 6.4.9 + require-in-the-middle: 5.2.0 + semver: 7.5.4 + shimmer: 1.2.1 + signal-exit: 3.0.7 + tslib: 1.9.3 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /@pm2/js-api@0.6.7: + resolution: {integrity: sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw==} + engines: {node: '>=4.0'} + requiresBuild: true + dependencies: + async: 2.6.4 + axios: 0.21.4(debug@4.3.4) + debug: 4.3.4 + eventemitter2: 6.4.9 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + optional: true + + /@pm2/pm2-version-check@1.0.4: + resolution: {integrity: sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==} + requiresBuild: true + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + dev: true + + /@rollup/pluginutils@5.0.5: + resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.3 + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: true + + /@socket.io/component-emitter@3.1.0: + resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + dev: false + + /@tootallnate/once@1.1.2: + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + requiresBuild: true + dev: false + optional: true + + /@tootallnate/quickjs-emscripten@0.23.0: + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + requiresBuild: true + dev: false + optional: true + + /@types/body-parser@1.19.4: + resolution: {integrity: sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==} + dependencies: + '@types/connect': 3.4.37 + '@types/node': 20.8.7 + dev: true + + /@types/connect@3.4.37: + resolution: {integrity: sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==} + dependencies: + '@types/node': 20.8.7 + dev: true + + /@types/cookie@0.4.1: + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + dev: false + + /@types/cors@2.8.15: + resolution: {integrity: sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==} + dependencies: + '@types/node': 20.8.7 + dev: false + + /@types/estree@1.0.3: + resolution: {integrity: sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==} + dev: true + + /@types/express-serve-static-core@4.17.39: + resolution: {integrity: sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ==} + dependencies: + '@types/node': 20.8.7 + '@types/qs': 6.9.9 + '@types/range-parser': 1.2.6 + '@types/send': 0.17.3 + dev: true + + /@types/express@4.17.20: + resolution: {integrity: sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==} + dependencies: + '@types/body-parser': 1.19.4 + '@types/express-serve-static-core': 4.17.39 + '@types/qs': 6.9.9 + '@types/serve-static': 1.15.4 + dev: true + + /@types/http-errors@2.0.3: + resolution: {integrity: sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==} + dev: true + + /@types/json-schema@7.0.14: + resolution: {integrity: sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==} + dev: true + + /@types/mime@1.3.4: + resolution: {integrity: sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==} + dev: true + + /@types/mime@3.0.3: + resolution: {integrity: sha512-i8MBln35l856k5iOhKk2XJ4SeAWg75mLIpZB4v6imOagKL6twsukBZGDMNhdOVk7yRFTMPpfILocMos59Q1otQ==} + dev: true + + /@types/node@20.3.3: + resolution: {integrity: sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==} + dev: false + + /@types/node@20.8.7: + resolution: {integrity: sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==} + dependencies: + undici-types: 5.25.3 + + /@types/qs@6.9.9: + resolution: {integrity: sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==} + dev: true + + /@types/range-parser@1.2.6: + resolution: {integrity: sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==} + dev: true + + /@types/semver@7.5.4: + resolution: {integrity: sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==} + dev: true + + /@types/send@0.17.3: + resolution: {integrity: sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==} + dependencies: + '@types/mime': 1.3.4 + '@types/node': 20.8.7 + dev: true + + /@types/serve-static@1.15.4: + resolution: {integrity: sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==} + dependencies: + '@types/http-errors': 2.0.3 + '@types/mime': 3.0.3 + '@types/node': 20.8.7 + dev: true + + /@types/web-bluetooth@0.0.18: + resolution: {integrity: sha512-v/ZHEj9xh82usl8LMR3GarzFY1IrbXJw5L4QfQhokjRV91q+SelFqxQWSep1ucXEZ22+dSTwLFkXeur25sPIbw==} + dev: true + + /@typescript-eslint/eslint-plugin@6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.9.1 + '@typescript-eslint/parser': 6.8.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/type-utils': 6.8.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.8.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.8.0 + debug: 4.3.4 + eslint: 8.50.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.8.0(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.8.0 + debug: 4.3.4 + eslint: 8.50.0 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@6.8.0: + resolution: {integrity: sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/visitor-keys': 6.8.0 + dev: true + + /@typescript-eslint/type-utils@6.8.0(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.8.0(eslint@8.50.0)(typescript@5.2.2) + debug: 4.3.4 + eslint: 8.50.0 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@6.8.0: + resolution: {integrity: sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@6.8.0(typescript@5.2.2): + resolution: {integrity: sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/visitor-keys': 6.8.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@6.8.0(eslint@8.50.0)(typescript@5.2.2): + resolution: {integrity: sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@types/json-schema': 7.0.14 + '@types/semver': 7.5.4 + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + eslint: 8.50.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@6.8.0: + resolution: {integrity: sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.8.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@vitejs/plugin-vue@4.3.4(vite@4.5.0)(vue@3.3.6): + resolution: {integrity: sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.5.0(sass@1.68.0) + vue: 3.3.6(typescript@5.2.2) + dev: true + + /@vue/compiler-core@3.3.6: + resolution: {integrity: sha512-2JNjemwaNwf+MkkatATVZi7oAH1Hx0B04DdPH3ZoZ8vKC1xZVP7nl4HIsk8XYd3r+/52sqqoz9TWzYc3yE9dqA==} + dependencies: + '@babel/parser': 7.23.0 + '@vue/shared': 3.3.6 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + dev: true + + /@vue/compiler-dom@3.3.6: + resolution: {integrity: sha512-1MxXcJYMHiTPexjLAJUkNs/Tw2eDf2tY3a0rL+LfuWyiKN2s6jvSwywH3PWD8bKICjfebX3GWx2Os8jkRDq3Ng==} + dependencies: + '@vue/compiler-core': 3.3.6 + '@vue/shared': 3.3.6 + dev: true + + /@vue/compiler-sfc@3.3.6: + resolution: {integrity: sha512-/Kms6du2h1VrXFreuZmlvQej8B1zenBqIohP0690IUBkJjsFvJxY0crcvVRJ0UhMgSR9dewB+khdR1DfbpArJA==} + dependencies: + '@babel/parser': 7.23.0 + '@vue/compiler-core': 3.3.6 + '@vue/compiler-dom': 3.3.6 + '@vue/compiler-ssr': 3.3.6 + '@vue/reactivity-transform': 3.3.6 + '@vue/shared': 3.3.6 + estree-walker: 2.0.2 + magic-string: 0.30.5 + postcss: 8.4.31 + source-map-js: 1.0.2 + dev: true + + /@vue/compiler-ssr@3.3.6: + resolution: {integrity: sha512-QTIHAfDCHhjXlYGkUg5KH7YwYtdUM1vcFl/FxFDlD6d0nXAmnjizka3HITp8DGudzHndv2PjKVS44vqqy0vP4w==} + dependencies: + '@vue/compiler-dom': 3.3.6 + '@vue/shared': 3.3.6 + dev: true + + /@vue/devtools-api@6.5.1: + resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} + dev: true + + /@vue/reactivity-transform@3.3.6: + resolution: {integrity: sha512-RlJl4dHfeO7EuzU1iJOsrlqWyJfHTkJbvYz/IOJWqu8dlCNWtxWX377WI0VsbAgBizjwD+3ZjdnvSyyFW1YVng==} + dependencies: + '@babel/parser': 7.23.0 + '@vue/compiler-core': 3.3.6 + '@vue/shared': 3.3.6 + estree-walker: 2.0.2 + magic-string: 0.30.5 + dev: true + + /@vue/reactivity@3.3.6: + resolution: {integrity: sha512-gtChAumfQz5lSy5jZXfyXbKrIYPf9XEOrIr6rxwVyeWVjFhJwmwPLtV6Yis+M9onzX++I5AVE9j+iPH60U+B8Q==} + dependencies: + '@vue/shared': 3.3.6 + dev: true + + /@vue/runtime-core@3.3.6: + resolution: {integrity: sha512-qp7HTP1iw1UW2ZGJ8L3zpqlngrBKvLsDAcq5lA6JvEXHmpoEmjKju7ahM9W2p/h51h0OT5F2fGlP/gMhHOmbUA==} + dependencies: + '@vue/reactivity': 3.3.6 + '@vue/shared': 3.3.6 + dev: true + + /@vue/runtime-dom@3.3.6: + resolution: {integrity: sha512-AoX3Cp8NqMXjLbIG9YR6n/pPLWE9TiDdk6wTJHFnl2GpHzDFH1HLBC9wlqqQ7RlnvN3bVLpzPGAAH00SAtOxHg==} + dependencies: + '@vue/runtime-core': 3.3.6 + '@vue/shared': 3.3.6 + csstype: 3.1.2 + dev: true + + /@vue/server-renderer@3.3.6(vue@3.3.6): + resolution: {integrity: sha512-kgLoN43W4ERdZ6dpyy+gnk2ZHtcOaIr5Uc/WUP5DRwutgvluzu2pudsZGoD2b7AEJHByUVMa9k6Sho5lLRCykw==} + peerDependencies: + vue: 3.3.6 + dependencies: + '@vue/compiler-ssr': 3.3.6 + '@vue/shared': 3.3.6 + vue: 3.3.6(typescript@5.2.2) + dev: true + + /@vue/shared@3.3.6: + resolution: {integrity: sha512-Xno5pEqg8SVhomD0kTSmfh30ZEmV/+jZtyh39q6QflrjdJCXah5lrnOLi9KB6a5k5aAHXMXjoMnxlzUkCNfWLQ==} + dev: true + + /@vueuse/core@10.5.0(vue@3.3.6): + resolution: {integrity: sha512-z/tI2eSvxwLRjOhDm0h/SXAjNm8N5ld6/SC/JQs6o6kpJ6Ya50LnEL8g5hoYu005i28L0zqB5L5yAl8Jl26K3A==} + dependencies: + '@types/web-bluetooth': 0.0.18 + '@vueuse/metadata': 10.5.0 + '@vueuse/shared': 10.5.0(vue@3.3.6) + vue-demi: 0.14.6(vue@3.3.6) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /@vueuse/metadata@10.5.0: + resolution: {integrity: sha512-fEbElR+MaIYyCkeM0SzWkdoMtOpIwO72x8WsZHRE7IggiOlILttqttM69AS13nrDxosnDBYdyy3C5mR1LCxHsw==} + dev: true + + /@vueuse/shared@10.5.0(vue@3.3.6): + resolution: {integrity: sha512-18iyxbbHYLst9MqU1X1QNdMHIjks6wC7XTVf0KNOv5es/Ms6gjVFCAAWTVP2JStuGqydg3DT+ExpFORUEi9yhg==} + dependencies: + vue-demi: 0.14.6(vue@3.3.6) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + requiresBuild: true + dev: false + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: false + + /acorn-jsx@5.3.2(acorn@8.10.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.10.0 + dev: true + + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /agent-base@7.1.0: + resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + requiresBuild: true + dependencies: + humanize-ms: 1.2.1 + dev: false + optional: true + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: false + optional: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /amp-message@0.1.2: + resolution: {integrity: sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==} + requiresBuild: true + dependencies: + amp: 0.3.1 + dev: false + optional: true + + /amp@0.3.1: + resolution: {integrity: sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==} + requiresBuild: true + dev: false + optional: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + requiresBuild: true + dev: false + optional: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: false + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: false + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + /aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: false + + /are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + dev: true + + /are-we-there-yet@2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: false + + /are-we-there-yet@3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: false + optional: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + requiresBuild: true + dependencies: + sprintf-js: 1.0.3 + dev: false + optional: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-back@3.1.0: + resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} + engines: {node: '>=6'} + dev: false + + /array-back@4.0.2: + resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} + engines: {node: '>=8'} + dev: false + + /array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + dev: false + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + requiresBuild: true + dependencies: + tslib: 2.6.2 + dev: false + optional: true + + /async-listener@0.6.10: + resolution: {integrity: sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==} + engines: {node: <=0.11.8 || >0.11.10} + requiresBuild: true + dependencies: + semver: 5.7.2 + shimmer: 1.2.1 + dev: false + optional: true + + /async@2.6.4: + resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} + requiresBuild: true + dependencies: + lodash: 4.17.21 + dev: false + optional: true + + /async@3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + requiresBuild: true + dev: false + optional: true + + /await-lock@2.2.2: + resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} + dev: false + + /axios@0.21.4(debug@4.3.4): + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + requiresBuild: true + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + optional: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + dev: false + + /basic-ftp@5.0.3: + resolution: {integrity: sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dev: false + optional: true + + /bcryptjs@2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + dev: false + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + /blessed@0.1.81: + resolution: {integrity: sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==} + engines: {node: '>= 0.8.0'} + hasBin: true + requiresBuild: true + dev: false + optional: true + + /bodec@0.1.0: + resolution: {integrity: sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==} + requiresBuild: true + dev: false + optional: true + + /body-parser@1.20.1: + resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /bootstrap-vue-next@0.14.10(vue@3.3.6): + resolution: {integrity: sha512-0czOUVVi8nSA3M9dm48jJnMUB6vP7sYrMxfbFjINE/MEwVbsi4b1Gq41k6gFJcwE54fj7pYQW9q8LP5fqcq0Lw==} + peerDependencies: + vue: ^3.3.4 + dependencies: + '@floating-ui/vue': 1.0.2(vue@3.3.6) + '@vueuse/core': 10.5.0(vue@3.3.6) + vue: 3.3.6(typescript@5.2.2) + transitivePeerDependencies: + - '@vue/composition-api' + dev: true + + /bootstrap@5.3.2(@popperjs/core@2.11.8): + resolution: {integrity: sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==} + peerDependencies: + '@popperjs/core': ^2.11.8 + dependencies: + '@popperjs/core': 2.11.8 + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + + /buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + dev: false + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: false + + /builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + dev: false + + /cacache@15.3.0: + resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} + engines: {node: '>= 10'} + requiresBuild: true + dependencies: + '@npmcli/fs': 1.1.1 + '@npmcli/move-file': 1.1.2 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 7.2.3 + infer-owner: 1.0.4 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 8.0.1 + tar: 6.2.0 + unique-filename: 1.1.1 + transitivePeerDependencies: + - bluebird + dev: false + optional: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: false + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + + /chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: false + optional: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + /charm@0.1.2: + resolution: {integrity: sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==} + requiresBuild: true + dev: false + optional: true + + /check-password-strength@2.0.7: + resolution: {integrity: sha512-VyklBkB6dOKnCIh63zdVr7QKVMN9/npwUqNAXxWrz8HabVZH/n/d+lyNm1O/vbXFJlT/Hytb5ouYKYGkoeZirQ==} + dev: false + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + /chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: false + + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + requiresBuild: true + dev: false + optional: true + + /cli-tableau@2.0.1: + resolution: {integrity: sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==} + engines: {node: '>=8.10.0'} + requiresBuild: true + dependencies: + chalk: 3.0.0 + dev: false + optional: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: false + + /colorette@2.0.19: + resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} + dev: false + + /command-line-args@5.2.1: + resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + find-replace: 3.0.0 + lodash.camelcase: 4.3.0 + typical: 4.0.0 + dev: false + + /command-line-usage@6.1.3: + resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} + engines: {node: '>=8.0.0'} + dependencies: + array-back: 4.0.2 + chalk: 2.4.2 + table-layout: 1.0.2 + typical: 5.2.0 + dev: false + + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + dev: false + + /commander@2.15.1: + resolution: {integrity: sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==} + requiresBuild: true + dev: false + optional: true + + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: false + + /comment-parser@1.4.0: + resolution: {integrity: sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==} + engines: {node: '>= 12.0.0'} + dev: true + + /compare-versions@6.1.0: + resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: false + + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + dev: false + + /continuation-local-storage@3.2.1: + resolution: {integrity: sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==} + requiresBuild: true + dependencies: + async-listener: 0.6.10 + emitter-listener: 1.1.2 + dev: false + optional: true + + /cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + dev: false + + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: false + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: false + + /cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: false + + /croner@4.1.97: + resolution: {integrity: sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==} + requiresBuild: true + dev: false + optional: true + + /cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + dependencies: + cross-spawn: 7.0.3 + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true + + /culvert@0.1.2: + resolution: {integrity: sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==} + requiresBuild: true + dev: false + optional: true + + /data-uri-to-buffer@6.0.1: + resolution: {integrity: sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==} + engines: {node: '>= 14'} + requiresBuild: true + dev: false + optional: true + + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: false + + /dayjs@1.8.36: + resolution: {integrity: sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==} + requiresBuild: true + dev: false + optional: true + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: false + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + requiresBuild: true + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + optional: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: false + + /degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + dev: false + optional: true + + /delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: false + + /denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + dev: false + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + dev: false + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: false + + /ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: false + + /emitter-listener@1.1.2: + resolution: {integrity: sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==} + requiresBuild: true + dependencies: + shimmer: 1.2.1 + dev: false + optional: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + requiresBuild: true + dev: false + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: false + + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: false + + /encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + requiresBuild: true + dependencies: + iconv-lite: 0.6.3 + dev: false + optional: true + + /engine.io-client@6.5.2: + resolution: {integrity: sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + engine.io-parser: 5.2.1 + ws: 8.11.0 + xmlhttprequest-ssl: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /engine.io-parser@5.2.1: + resolution: {integrity: sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==} + engines: {node: '>=10.0.0'} + dev: false + + /engine.io@6.5.3: + resolution: {integrity: sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==} + engines: {node: '>=10.2.0'} + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.15 + '@types/node': 20.8.7 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.2 + cors: 2.8.5 + debug: 4.3.4 + engine.io-parser: 5.2.1 + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /enquirer@2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} + requiresBuild: true + dependencies: + ansi-colors: 4.1.3 + dev: false + optional: true + + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + requiresBuild: true + dev: false + optional: true + + /err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + requiresBuild: true + dev: false + optional: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: false + + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + /escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + requiresBuild: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: false + optional: true + + /eslint-plugin-jsdoc@46.8.2(eslint@8.50.0): + resolution: {integrity: sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ==} + engines: {node: '>=16'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@es-joy/jsdoccomment': 0.40.1 + are-docs-informative: 0.0.2 + comment-parser: 1.4.0 + debug: 4.3.4 + escape-string-regexp: 4.0.0 + eslint: 8.50.0 + esquery: 1.5.0 + is-builtin-module: 3.2.1 + semver: 7.5.4 + spdx-expression-parse: 3.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-vue@9.17.0(eslint@8.50.0): + resolution: {integrity: sha512-r7Bp79pxQk9I5XDP0k2dpUC7Ots3OSWgvGZNu3BxmKK6Zg7NgVtcOB6OCna5Kb9oQwJPl5hq183WD0SY5tZtIQ==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + eslint: 8.50.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.0.13 + semver: 7.5.4 + vue-eslint-parser: 9.3.2(eslint@8.50.0) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.50.0: + resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) + '@eslint-community/regexpp': 4.9.1 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.50.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.23.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /esm@3.2.25: + resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} + engines: {node: '>=6'} + dev: false + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + requiresBuild: true + dev: false + optional: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: false + + /eventemitter2@0.4.14: + resolution: {integrity: sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==} + requiresBuild: true + dev: false + optional: true + + /eventemitter2@5.0.1: + resolution: {integrity: sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==} + requiresBuild: true + dev: false + optional: true + + /eventemitter2@6.4.9: + resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} + requiresBuild: true + dev: false + optional: true + + /express@4.18.2: + resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-patch@3.1.1: + resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} + requiresBuild: true + dev: false + optional: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fclone@1.0.11: + resolution: {integrity: sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==} + requiresBuild: true + dev: false + optional: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.1.1 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /find-replace@3.0.0: + resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + dev: false + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.1.1: + resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==} + engines: {node: '>=12.0.0'} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + dev: true + + /follow-redirects@1.15.3(debug@4.3.4): + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + engines: {node: '>=4.0'} + requiresBuild: true + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 + dev: false + optional: true + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: false + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: false + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: false + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + + /fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + requiresBuild: true + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + optional: true + + /fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + requiresBuild: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /gauge@3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + + /gauge@4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + optional: true + + /generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + dependencies: + is-property: 1.0.2 + dev: false + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: false + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: false + + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: false + + /get-uri@6.0.2: + resolution: {integrity: sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + basic-ftp: 5.0.3 + data-uri-to-buffer: 6.0.1 + debug: 4.3.4 + fs-extra: 8.1.0 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /getopts@2.3.0: + resolution: {integrity: sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==} + dev: false + + /git-node-fs@1.0.0(js-git@0.7.8): + resolution: {integrity: sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ==} + requiresBuild: true + peerDependencies: + js-git: ^0.7.8 + peerDependenciesMeta: + js-git: + optional: true + dependencies: + js-git: 0.7.8 + dev: false + optional: true + + /git-sha1@0.1.2: + resolution: {integrity: sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==} + requiresBuild: true + dev: false + optional: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 + dev: false + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + requiresBuild: true + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.1 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: false + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: false + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: false + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false + + /has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: false + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + requiresBuild: true + dev: false + optional: true + + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: false + + /http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + requiresBuild: true + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /http-proxy-agent@7.0.0: + resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /https-proxy-agent@7.0.2: + resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + requiresBuild: true + dependencies: + ms: 2.1.3 + dev: false + optional: true + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + requiresBuild: true + dependencies: + safer-buffer: 2.1.2 + dev: false + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /immutable@4.3.4: + resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + requiresBuild: true + dev: false + optional: true + + /infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + requiresBuild: true + dev: false + optional: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + requiresBuild: true + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + requiresBuild: true + dev: false + optional: true + + /interpret@2.2.0: + resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} + engines: {node: '>= 0.10'} + dev: false + + /ip@1.1.8: + resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} + requiresBuild: true + dev: false + optional: true + + /ip@2.0.0: + resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + requiresBuild: true + dev: false + optional: true + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: false + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + + /is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + requiresBuild: true + dev: false + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + requiresBuild: true + dev: false + optional: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + dev: false + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + requiresBuild: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: false + + /js-git@0.7.8: + resolution: {integrity: sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==} + requiresBuild: true + dependencies: + bodec: 0.1.0 + culvert: 0.1.2 + git-sha1: 0.1.2 + pako: 0.2.9 + dev: false + optional: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsdoc-type-pratt-parser@4.0.0: + resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} + engines: {node: '>=12.0.0'} + dev: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + requiresBuild: true + dev: false + optional: true + + /jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + requiresBuild: true + optionalDependencies: + graceful-fs: 4.2.11 + dev: false + optional: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + + /jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.5.4 + dev: false + + /just-performance-es6-compat@4.3.2: + resolution: {integrity: sha512-bNPuqRaV8PrqYVivdN8FsKi0rmXaQ0Y63oasFUQFJooJPH0r26LdfBAfoodhUQI6I6cek9yNo+tnGiF0R3pIHw==} + dev: false + + /jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + dev: false + + /jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + dev: false + + /jwt-decode@3.1.2: + resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} + dev: false + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /knex@2.4.2(mysql2@3.6.2): + resolution: {integrity: sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + better-sqlite3: '*' + mysql: '*' + mysql2: '*' + pg: '*' + pg-native: '*' + sqlite3: '*' + tedious: '*' + peerDependenciesMeta: + better-sqlite3: + optional: true + mysql: + optional: true + mysql2: + optional: true + pg: + optional: true + pg-native: + optional: true + sqlite3: + optional: true + tedious: + optional: true + dependencies: + colorette: 2.0.19 + commander: 9.5.0 + debug: 4.3.4 + escalade: 3.1.1 + esm: 3.2.25 + get-package-type: 0.1.0 + getopts: 2.3.0 + interpret: 2.2.0 + lodash: 4.17.21 + mysql2: 3.6.2 + pg-connection-string: 2.5.0 + rechoir: 0.8.0 + resolve-from: 5.0.0 + tarn: 3.0.2 + tildify: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /knex@2.5.1(mysql2@3.6.2): + resolution: {integrity: sha512-z78DgGKUr4SE/6cm7ku+jHvFT0X97aERh/f0MUKAKgFnwCYBEW4TFBqtHWFYiJFid7fMrtpZ/gxJthvz5mEByA==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + better-sqlite3: '*' + mysql: '*' + mysql2: '*' + pg: '*' + pg-native: '*' + sqlite3: '*' + tedious: '*' + peerDependenciesMeta: + better-sqlite3: + optional: true + mysql: + optional: true + mysql2: + optional: true + pg: + optional: true + pg-native: + optional: true + sqlite3: + optional: true + tedious: + optional: true + dependencies: + colorette: 2.0.19 + commander: 10.0.1 + debug: 4.3.4 + escalade: 3.1.1 + esm: 3.2.25 + get-package-type: 0.1.0 + getopts: 2.3.0 + interpret: 2.2.0 + lodash: 4.17.21 + mysql2: 3.6.2 + pg-connection-string: 2.6.1 + rechoir: 0.8.0 + resolve-from: 5.0.0 + tarn: 3.0.2 + tildify: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /lazy@1.0.11: + resolution: {integrity: sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==} + engines: {node: '>=0.2.0'} + requiresBuild: true + dev: false + optional: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /limiter-es6-compat@2.1.2: + resolution: {integrity: sha512-rAi6LCOubXfnojSePboCylTSJWi9m0hlnZJ6AYsBv0clRFr4PJAZd8DtDVhXSN5Ed5nXa6pULHu9sJxoxpWWww==} + dependencies: + just-performance-es6-compat: 4.3.2 + dev: false + + /local-pkg@0.4.3: + resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} + engines: {node: '>=14'} + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + dev: false + + /lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + dev: false + + /lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + dev: false + + /lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + dev: false + + /lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + dev: false + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: false + + /lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + dev: false + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + /log-driver@1.2.7: + resolution: {integrity: sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==} + engines: {node: '>=0.8.6'} + requiresBuild: true + dev: false + optional: true + + /long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + dev: false + + /lru-cache@10.0.1: + resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} + engines: {node: 14 || >=16.14} + dev: false + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + dev: false + + /lru-cache@8.0.5: + resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==} + engines: {node: '>=16.14'} + dev: false + + /magic-string@0.30.5: + resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + dev: false + + /make-fetch-happen@9.1.0: + resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} + engines: {node: '>= 10'} + requiresBuild: true + dependencies: + agentkeepalive: 4.5.0 + cacache: 15.3.0 + http-cache-semantics: 4.1.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 1.4.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.3 + promise-retry: 2.0.1 + socks-proxy-agent: 6.2.1 + ssri: 8.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + optional: true + + /media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + dev: false + + /merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + dev: false + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: false + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + + /minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass-fetch@1.4.1: + resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + dev: false + optional: true + + /minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: false + + /minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + dev: false + + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: false + + /minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: false + + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: false + + /module-details-from-path@1.0.3: + resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==} + requiresBuild: true + dev: false + optional: true + + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false + + /mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + requiresBuild: true + dev: false + optional: true + + /mysql2@3.6.2: + resolution: {integrity: sha512-m5erE6bMoWfPXW1D5UrVwlT8PowAoSX69KcZzPuARQ3wY1RJ52NW9PdvdPo076XiSIkQ5IBTis7hxdlrQTlyug==} + engines: {node: '>= 8.0'} + dependencies: + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru-cache: 8.0.5 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + dev: false + + /named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + dependencies: + lru-cache: 7.18.3 + dev: false + + /nan@2.18.0: + resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} + dev: false + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /needle@2.4.0: + resolution: {integrity: sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==} + engines: {node: '>= 4.4.x'} + hasBin: true + requiresBuild: true + dependencies: + debug: 3.2.7 + iconv-lite: 0.4.24 + sax: 1.3.0 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + requiresBuild: true + dev: false + + /netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + requiresBuild: true + dev: false + optional: true + + /node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + dev: false + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + + /node-gyp@8.4.1: + resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==} + engines: {node: '>= 10.12.0'} + hasBin: true + requiresBuild: true + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + make-fetch-happen: 9.1.0 + nopt: 5.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.5.4 + tar: 6.2.0 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + optional: true + + /node-pty@1.0.0: + resolution: {integrity: sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==} + requiresBuild: true + dependencies: + nan: 2.18.0 + dev: false + + /nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: false + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /npmlog@5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: false + + /npmlog@6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + dev: false + optional: true + + /nssocket@0.6.0: + resolution: {integrity: sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==} + engines: {node: '>= 0.10.x'} + requiresBuild: true + dependencies: + eventemitter2: 0.4.14 + lazy: 1.0.11 + dev: false + optional: true + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: false + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: false + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + requiresBuild: true + dependencies: + wrappy: 1.0.2 + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + requiresBuild: true + dependencies: + aggregate-error: 3.1.0 + dev: false + optional: true + + /pac-proxy-agent@7.0.1: + resolution: {integrity: sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.0 + debug: 4.3.4 + get-uri: 6.0.2 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + pac-resolver: 7.0.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /pac-resolver@7.0.0: + resolution: {integrity: sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + degenerator: 5.0.1 + ip: 1.1.8 + netmask: 2.0.2 + dev: false + optional: true + + /pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + requiresBuild: true + dev: false + optional: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + requiresBuild: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.0.1 + minipass: 7.0.4 + dev: false + + /path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + dev: false + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pg-connection-string@2.5.0: + resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} + dev: false + + /pg-connection-string@2.6.1: + resolution: {integrity: sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==} + dev: false + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /pidusage@2.0.21: + resolution: {integrity: sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + safe-buffer: 5.2.1 + dev: false + optional: true + + /pidusage@3.0.2: + resolution: {integrity: sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==} + engines: {node: '>=10'} + requiresBuild: true + dependencies: + safe-buffer: 5.2.1 + dev: false + optional: true + + /pm2-axon-rpc@0.7.1: + resolution: {integrity: sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==} + engines: {node: '>=5'} + requiresBuild: true + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /pm2-axon@4.0.1: + resolution: {integrity: sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==} + engines: {node: '>=5'} + requiresBuild: true + dependencies: + amp: 0.3.1 + amp-message: 0.1.2 + debug: 4.3.4 + escape-string-regexp: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /pm2-deploy@1.0.2: + resolution: {integrity: sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==} + engines: {node: '>=4.0.0'} + requiresBuild: true + dependencies: + run-series: 1.1.9 + tv4: 1.3.0 + dev: false + optional: true + + /pm2-multimeter@0.1.2: + resolution: {integrity: sha512-S+wT6XfyKfd7SJIBqRgOctGxaBzUOmVQzTAS+cg04TsEUObJVreha7lvCfX8zzGVr871XwCSnHUU7DQQ5xEsfA==} + requiresBuild: true + dependencies: + charm: 0.1.2 + dev: false + optional: true + + /pm2-sysmonit@1.2.8: + resolution: {integrity: sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==} + requiresBuild: true + dependencies: + async: 3.2.4 + debug: 4.3.4 + pidusage: 2.0.21 + systeminformation: 5.21.13 + tx2: 1.0.5 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /pm2@5.3.0: + resolution: {integrity: sha512-xscmQiAAf6ArVmKhjKTeeN8+Td7ZKnuZFFPw1DGkdFPR/0Iyx+m+1+OpCdf9+HQopX3VPc9/wqPQHqVOfHum9w==} + engines: {node: '>=10.0.0'} + hasBin: true + requiresBuild: true + dependencies: + '@pm2/agent': 2.0.3 + '@pm2/io': 5.0.2 + '@pm2/js-api': 0.6.7 + '@pm2/pm2-version-check': 1.0.4 + async: 3.2.4 + blessed: 0.1.81 + chalk: 3.0.0 + chokidar: 3.5.3 + cli-tableau: 2.0.1 + commander: 2.15.1 + croner: 4.1.97 + dayjs: 1.11.10 + debug: 4.3.4 + enquirer: 2.3.6 + eventemitter2: 5.0.1 + fclone: 1.0.11 + mkdirp: 1.0.4 + needle: 2.4.0 + pidusage: 3.0.2 + pm2-axon: 4.0.1 + pm2-axon-rpc: 0.7.1 + pm2-deploy: 1.0.2 + pm2-multimeter: 0.1.2 + promptly: 2.2.0 + semver: 7.5.4 + source-map-support: 0.5.21 + sprintf-js: 1.1.2 + vizion: 2.2.1 + yamljs: 0.3.0 + optionalDependencies: + pm2-sysmonit: 1.2.8 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + optional: true + + /postcss-selector-parser@6.0.13: + resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + requiresBuild: true + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + dev: false + optional: true + + /promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + requiresBuild: true + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + dev: false + optional: true + + /promptly@2.2.0: + resolution: {integrity: sha512-aC9j+BZsRSSzEsXBNBwDnAxujdx19HycZoKgRgzWnS8eOHg1asuf9heuLprfbe739zY3IdUQx+Egv6Jn135WHA==} + requiresBuild: true + dependencies: + read: 1.0.7 + dev: false + optional: true + + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: false + + /proxy-agent@6.3.1: + resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.1 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + requiresBuild: true + dev: false + optional: true + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: false + + /raw-body@2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: false + + /read@1.0.7: + resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} + engines: {node: '>=0.8'} + requiresBuild: true + dependencies: + mute-stream: 0.0.8 + dev: false + optional: true + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /rechoir@0.8.0: + resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} + engines: {node: '>= 10.13.0'} + dependencies: + resolve: 1.22.8 + dev: false + + /redbean-node@0.3.1(mysql2@3.6.2): + resolution: {integrity: sha512-rz71vF7UtJQ14ttZ9I0QuaJ9TOwBCnZb+qHUBiU05f2fLaiQC79liisL3xgkHI8uE9et6HAkG8Z8VPkZbhgxKw==} + dependencies: + '@types/node': 20.3.3 + await-lock: 2.2.2 + dayjs: 1.11.10 + glob: 10.3.10 + knex: 2.4.2(mysql2@3.6.2) + lodash: 4.17.21 + transitivePeerDependencies: + - better-sqlite3 + - mysql + - mysql2 + - pg + - pg-native + - sqlite3 + - supports-color + - tedious + dev: false + + /reduce-flatten@2.0.0: + resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} + engines: {node: '>=6'} + dev: false + + /require-in-the-middle@5.2.0: + resolution: {integrity: sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + debug: 4.3.4 + module-details-from-path: 1.0.3 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: false + + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: false + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + requiresBuild: true + dev: false + optional: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /run-series@1.1.9: + resolution: {integrity: sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==} + requiresBuild: true + dev: false + optional: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + + /sass@1.68.0: + resolution: {integrity: sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.3.4 + source-map-js: 1.0.2 + dev: true + + /sax@1.3.0: + resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + requiresBuild: true + dev: false + optional: true + + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + requiresBuild: true + dev: false + optional: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: false + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + dev: false + + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + dev: false + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: false + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /shimmer@1.2.1: + resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} + requiresBuild: true + dev: false + optional: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: false + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: false + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + requiresBuild: true + dev: false + optional: true + + /socket.io-adapter@2.5.2: + resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} + dependencies: + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /socket.io-client@4.7.2: + resolution: {integrity: sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + engine.io-client: 6.5.2 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /socket.io@4.7.2: + resolution: {integrity: sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==} + engines: {node: '>=10.2.0'} + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.4 + engine.io: 6.5.3 + socket.io-adapter: 2.5.2 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /socks-proxy-agent@6.2.1: + resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} + engines: {node: '>= 10'} + requiresBuild: true + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /socks-proxy-agent@8.0.2: + resolution: {integrity: sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==} + engines: {node: '>= 14'} + requiresBuild: true + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + + /socks@2.7.1: + resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} + engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + requiresBuild: true + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: false + optional: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: false + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: false + + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.16 + dev: true + + /spdx-license-ids@3.0.16: + resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + requiresBuild: true + dev: false + optional: true + + /sprintf-js@1.1.2: + resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} + requiresBuild: true + dev: false + optional: true + + /sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + dev: false + + /ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: false + + /string-format@2.0.0: + resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + requiresBuild: true + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: false + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /systeminformation@5.21.13: + resolution: {integrity: sha512-sGgMhQxxjKHSIJtv7g5s19IRpfCgLG3tZqGbFcfGFyMm1hJ3BmzTfaq0yyOO2oLHlbkM49mgMjnPPB8g573LMA==} + engines: {node: '>=8.0.0'} + os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] + hasBin: true + requiresBuild: true + dev: false + optional: true + + /table-layout@1.0.2: + resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} + engines: {node: '>=8.0.0'} + dependencies: + array-back: 4.0.2 + deep-extend: 0.6.0 + typical: 5.2.0 + wordwrapjs: 4.0.1 + dev: false + + /tar@6.2.0: + resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: false + + /tarn@3.0.2: + resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==} + engines: {node: '>=8.0.0'} + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /tildify@2.0.0: + resolution: {integrity: sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==} + engines: {node: '>=8'} + dev: false + + /timezones-list@3.0.2: + resolution: {integrity: sha512-I698hm6Jp/xxkwyTSOr39pZkYKETL8LDJeSIhjxXBfPUAHM5oZNuQ4o9UK3PSkDBOkjATecSOBb3pR1IkIBUsg==} + dev: false + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /ts-api-utils@1.0.3(typescript@5.2.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.2.2 + dev: true + + /ts-command-line-args@2.5.1: + resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} + hasBin: true + dependencies: + chalk: 4.1.2 + command-line-args: 5.2.1 + command-line-usage: 6.1.3 + string-format: 2.0.0 + dev: false + + /tslib@1.9.3: + resolution: {integrity: sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==} + requiresBuild: true + dev: false + optional: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + requiresBuild: true + dev: false + optional: true + + /tsx@3.14.0: + resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} + hasBin: true + dependencies: + esbuild: 0.18.20 + get-tsconfig: 4.7.2 + source-map-support: 0.5.21 + optionalDependencies: + fsevents: 2.3.3 + dev: false + + /tv4@1.3.0: + resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==} + engines: {node: '>= 0.8.0'} + requiresBuild: true + dev: false + optional: true + + /tx2@1.0.5: + resolution: {integrity: sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==} + requiresBuild: true + dependencies: + json-stringify-safe: 5.0.1 + dev: false + optional: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@4.3.3: + resolution: {integrity: sha512-bxhiFii6BBv6UiSDq7uKTMyADT9unXEl3ydGefndVLxFeB44LRbT4K7OJGDYSyDrKnklCC1Pre68qT2wbUl2Aw==} + engines: {node: '>=16'} + dev: false + + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: false + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /typical@4.0.0: + resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} + engines: {node: '>=8'} + dev: false + + /typical@5.2.0: + resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} + engines: {node: '>=8'} + dev: false + + /undici-types@5.25.3: + resolution: {integrity: sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==} + + /unique-filename@1.1.1: + resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + requiresBuild: true + dependencies: + unique-slug: 2.0.2 + dev: false + optional: true + + /unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + requiresBuild: true + dependencies: + imurmurhash: 0.1.4 + dev: false + optional: true + + /universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + requiresBuild: true + dev: false + optional: true + + /universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: true + + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: false + + /unplugin-vue-components@0.25.2(vue@3.3.6): + resolution: {integrity: sha512-OVmLFqILH6w+eM8fyt/d/eoJT9A6WO51NZLf1vC5c1FZ4rmq2bbGxTy8WP2Jm7xwFdukaIdv819+UI7RClPyCA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/parser': ^7.15.8 + '@nuxt/kit': ^3.2.2 + vue: 2 || 3 + peerDependenciesMeta: + '@babel/parser': + optional: true + '@nuxt/kit': + optional: true + dependencies: + '@antfu/utils': 0.7.6 + '@rollup/pluginutils': 5.0.5 + chokidar: 3.5.3 + debug: 4.3.4 + fast-glob: 3.3.1 + local-pkg: 0.4.3 + magic-string: 0.30.5 + minimatch: 9.0.3 + resolve: 1.22.8 + unplugin: 1.5.0 + vue: 3.3.6(typescript@5.2.2) + transitivePeerDependencies: + - rollup + - supports-color + dev: true + + /unplugin@1.5.0: + resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==} + dependencies: + acorn: 8.10.0 + chokidar: 3.5.3 + webpack-sources: 3.2.3 + webpack-virtual-modules: 0.5.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + dev: false + + /uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + requiresBuild: true + dev: false + optional: true + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: false + + /vite-plugin-compression@0.5.1(vite@4.5.0): + resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} + peerDependencies: + vite: '>=2.0.0' + dependencies: + chalk: 4.1.2 + debug: 4.3.4 + fs-extra: 10.1.0 + vite: 4.5.0(sass@1.68.0) + transitivePeerDependencies: + - supports-color + dev: true + + /vite@4.5.0(sass@1.68.0): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + sass: 1.68.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vizion@2.2.1: + resolution: {integrity: sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==} + engines: {node: '>=4.0'} + requiresBuild: true + dependencies: + async: 2.6.4 + git-node-fs: 1.0.0(js-git@0.7.8) + ini: 1.3.8 + js-git: 0.7.8 + dev: false + optional: true + + /vue-demi@0.14.6(vue@3.3.6): + resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.3.6(typescript@5.2.2) + dev: true + + /vue-eslint-parser@9.3.2(eslint@8.50.0): + resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.50.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /vue-i18n@9.5.0(vue@3.3.6): + resolution: {integrity: sha512-NiI3Ph1qMstNf7uhYh8trQBOBFLxeJgcOxBq51pCcZ28Vs18Y7BDS58r8HGDKCYgXdLUYqPDXdKatIF4bvBVZg==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@intlify/core-base': 9.5.0 + '@intlify/shared': 9.5.0 + '@vue/devtools-api': 6.5.1 + vue: 3.3.6(typescript@5.2.2) + dev: true + + /vue-router@4.2.5(vue@3.3.6): + resolution: {integrity: sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.5.1 + vue: 3.3.6(typescript@5.2.2) + dev: true + + /vue-toastification@2.0.0-rc.5(vue@3.3.6): + resolution: {integrity: sha512-q73e5jy6gucEO/U+P48hqX+/qyXDozAGmaGgLFm5tXX4wJBcVsnGp4e/iJqlm9xzHETYOilUuwOUje2Qg1JdwA==} + peerDependencies: + vue: ^3.0.2 + dependencies: + vue: 3.3.6(typescript@5.2.2) + dev: true + + /vue@3.3.6(typescript@5.2.2): + resolution: {integrity: sha512-jJIDETeWJnoY+gfn4ZtMPMS5KtbP4ax+CT4dcQFhTnWEk8xMupFyQ0JxL28nvT/M4+p4a0ptxaV2WY0LiIxvRg==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.3.6 + '@vue/compiler-sfc': 3.3.6 + '@vue/runtime-dom': 3.3.6 + '@vue/server-renderer': 3.3.6(vue@3.3.6) + '@vue/shared': 3.3.6 + typescript: 5.2.2 + dev: true + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + + /webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + dev: true + + /webpack-virtual-modules@0.5.0: + resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} + dev: true + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + + /wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 + dev: false + + /wordwrapjs@4.0.1: + resolution: {integrity: sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==} + engines: {node: '>=8.0.0'} + dependencies: + reduce-flatten: 2.0.0 + typical: 5.2.0 + dev: false + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + requiresBuild: true + + /ws@7.4.6: + resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + engines: {node: '>=8.3.0'} + requiresBuild: true + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + optional: true + + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + requiresBuild: true + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + optional: true + + /ws@8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + 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 + dev: false + + /xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: true + + /xmlhttprequest-ssl@2.0.0: + resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} + engines: {node: '>=0.4.0'} + dev: false + + /xterm-addon-fit@0.8.0(xterm@5.3.0): + resolution: {integrity: sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==} + peerDependencies: + xterm: ^5.0.0 + dependencies: + xterm: 5.3.0 + dev: true + + /xterm-addon-web-links@0.9.0(xterm@5.3.0): + resolution: {integrity: sha512-LIzi4jBbPlrKMZF3ihoyqayWyTXAwGfu4yprz1aK2p71e9UKXN6RRzVONR0L+Zd+Ik5tPVI9bwp9e8fDTQh49Q==} + peerDependencies: + xterm: ^5.0.0 + dependencies: + xterm: 5.3.0 + dev: true + + /xterm@5.3.0: + resolution: {integrity: sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + /yaml@2.3.3: + resolution: {integrity: sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==} + engines: {node: '>= 14'} + dev: false + + /yamljs@0.3.0: + resolution: {integrity: sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==} + hasBin: true + requiresBuild: true + dependencies: + argparse: 1.0.10 + glob: 7.2.3 + dev: false + optional: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..6eff920 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "strict": true, + "moduleResolution": "bundler" + } +}