From 929193d27218e6581a572a6ca5dcf99a468cba2f Mon Sep 17 00:00:00 2001 From: Elijah Dunemask Date: Wed, 15 Mar 2023 15:20:08 +0000 Subject: [PATCH] (feature) Update UI & Resource Availability --- Dockerfile | 15 + dist/app.js | 17 + lib/Minecluster.js | 48 + lib/index.js | 0 lib/k8s.js | 8 + lib/k8s/configs/rcon-secret.yml | 10 + lib/k8s/configs/rcon-svc.yml | 22 + lib/k8s/configs/server-deployment.yml | 215 ++ lib/k8s/configs/server-pvc.yml | 13 + lib/k8s/configs/server-svc.yml | 24 + lib/k8s/live-logging.js | 30 + lib/k8s/server-control.js | 95 + lib/k8s/server-create.js | 171 ++ lib/k8s/server-delete.js | 55 + lib/routes/server-route.js | 19 + lib/routes/system-route.js | 27 + lib/routes/vitals-route.js | 6 + lib/server/rcon.js | 31 + lib/server/router.js | 23 + lib/server/sockets.js | 46 + lib/util/logging.js | 28 + package-lock.json | 2952 ++++++++++++++++++++++++- package.json | 21 +- public/asset-attributions.txt | 1 + public/css/overview.css | 20 + public/css/rcon.css | 9 + public/css/server-card.css | 82 + public/images/server-backdrop.png | Bin 0 -> 29015 bytes src/MCL.jsx | 12 +- src/ctx/SettingsContext.jsx | 62 + src/nav/MCLMenu.jsx | 85 + src/nav/MCLPages.jsx | 20 + src/nav/MCLPortal.jsx | 18 + src/nav/Viewport.jsx | 16 + src/overview/Overview.jsx | 23 + src/overview/OverviewVisual.jsx | 44 + src/pages/Create.jsx | 152 ++ src/pages/Home.jsx | 51 + src/servers/RconDialog.jsx | 45 + src/servers/RconSocket.js | 27 + src/servers/RconView.jsx | 53 + src/servers/ServerCard.jsx | 112 + src/util/queries.js | 60 + vite.config.js | 6 +- 44 files changed, 4747 insertions(+), 27 deletions(-) create mode 100644 Dockerfile create mode 100644 dist/app.js create mode 100644 lib/Minecluster.js create mode 100644 lib/index.js create mode 100644 lib/k8s.js create mode 100644 lib/k8s/configs/rcon-secret.yml create mode 100644 lib/k8s/configs/rcon-svc.yml create mode 100644 lib/k8s/configs/server-deployment.yml create mode 100644 lib/k8s/configs/server-pvc.yml create mode 100644 lib/k8s/configs/server-svc.yml create mode 100644 lib/k8s/live-logging.js create mode 100644 lib/k8s/server-control.js create mode 100644 lib/k8s/server-create.js create mode 100644 lib/k8s/server-delete.js create mode 100644 lib/routes/server-route.js create mode 100644 lib/routes/system-route.js create mode 100644 lib/routes/vitals-route.js create mode 100644 lib/server/rcon.js create mode 100644 lib/server/router.js create mode 100644 lib/server/sockets.js create mode 100644 lib/util/logging.js create mode 100644 public/asset-attributions.txt create mode 100644 public/css/overview.css create mode 100644 public/css/rcon.css create mode 100644 public/css/server-card.css create mode 100644 public/images/server-backdrop.png create mode 100644 src/ctx/SettingsContext.jsx create mode 100644 src/nav/MCLMenu.jsx create mode 100644 src/nav/MCLPages.jsx create mode 100644 src/nav/MCLPortal.jsx create mode 100644 src/nav/Viewport.jsx create mode 100644 src/overview/Overview.jsx create mode 100644 src/overview/OverviewVisual.jsx create mode 100644 src/pages/Create.jsx create mode 100644 src/pages/Home.jsx create mode 100644 src/servers/RconDialog.jsx create mode 100644 src/servers/RconSocket.js create mode 100644 src/servers/RconView.jsx create mode 100644 src/servers/ServerCard.jsx create mode 100644 src/util/queries.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c80bac8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:18 +WORKDIR /dunemask/net/minecluster +# Copy dependencies +COPY package.json . +COPY package-lock.json . +RUN npm i +# Copy react build resources over +COPY public public +COPY dist dist +COPY src src +COPY lib lib +COPY index.html . +COPY vite.config.js . +RUN npm run build:react +CMD ["npm","start"] diff --git a/dist/app.js b/dist/app.js new file mode 100644 index 0000000..bce3fc0 --- /dev/null +++ b/dist/app.js @@ -0,0 +1,17 @@ +import stream from "stream"; +import k8s from "@kubernetes/client-node"; +import Minecluster from "../lib/Minecluster.js"; +const mcl = new Minecluster(); +mcl.start(); + +async function main(){ +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); + +const k8sApi = kc.makeApiClient(k8s.CoreV1Api); +const res = await k8sApi.listNamespacedPod('mc-garden-default'); +const pods = res.body.items.map((vp1) => vp1.metadata.name); +console.log(pods); + +} +main().catch((e)=>{console.log(e)}); \ No newline at end of file diff --git a/lib/Minecluster.js b/lib/Minecluster.js new file mode 100644 index 0000000..0fa918b --- /dev/null +++ b/lib/Minecluster.js @@ -0,0 +1,48 @@ +// Imports +import fig from "figlet"; +import http from "http"; +import express from "express"; +import { INFO, OK, logInfo } from "./util/logging.js"; + +// Import Core Modules +import buildRoutes from "./server/router.js"; +import injectSockets from "./server/sockets.js"; + +// Constants +const title = "MCL"; +const port = process.env.MCL_DEV_PORT ?? 52000; + +// Class +export default class Minecluster { + constructor(options = {}) { + for (var k in options) this[k] = options[k]; + this.port = options.port ?? port; + } + + async _preinitialize() { + logInfo(fig.textSync(title, "Larry 3D")); + INFO("INIT", "Initializing..."); + this.app = express(); + this.server = http.createServer(this.app); + this.sockets = injectSockets(this.server, this.jobs); + this.routes = buildRoutes(this.sockets); + this.app.use(this.routes); + OK("INIT", "Initialized!"); + } + + async _connect() { + // await this.pg.connect(); + } + + start() { + const mcl = this; + return new Promise(async function init(res) { + mcl._preinitialize(); + await mcl._connect(); + mcl.server.listen(mcl.port, function onStart() { + OK("SERVER", `Running on ${mcl.port}`); + res(); + }); + }); + } +} diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/k8s.js b/lib/k8s.js new file mode 100644 index 0000000..b842159 --- /dev/null +++ b/lib/k8s.js @@ -0,0 +1,8 @@ +import k8s from "@kubernetes/client-node"; +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); + +const k8sApi = kc.makeApiClient(k8s.CoreV1Api); +k8sApi.listNamespacedPod("mc-garden-default").then((res) => { + console.log(res.body); +}); diff --git a/lib/k8s/configs/rcon-secret.yml b/lib/k8s/configs/rcon-secret.yml new file mode 100644 index 0000000..6b7bd80 --- /dev/null +++ b/lib/k8s/configs/rcon-secret.yml @@ -0,0 +1,10 @@ +apiVersion: v1 +data: + rcon-password: UEphT3V2aGJlQjNvc3M0dElwQU5YTUZrSkltR1RsRVl0ZGx3elFqZjJLdVZrZXNtV0hja1VhUUd3bmZDcElpbA== +kind: Secret +metadata: + labels: + app: changeme-app-label + name: changeme-rcon-secret + namespace: changeme-namespace +type: Opaque diff --git a/lib/k8s/configs/rcon-svc.yml b/lib/k8s/configs/rcon-svc.yml new file mode 100644 index 0000000..bcb34a7 --- /dev/null +++ b/lib/k8s/configs/rcon-svc.yml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + labels: + app: changeme-app + name: changeme-rcon + namespace: changeme-namespace +spec: + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: rcon + port: 25575 + protocol: TCP + targetPort: rcon + selector: + app: changeme-app + sessionAffinity: None + type: ClusterIP diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml new file mode 100644 index 0000000..bb6611a --- /dev/null +++ b/lib/k8s/configs/server-deployment.yml @@ -0,0 +1,215 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: changeme-name + namespace: changeme-namespace +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: changeme-app + strategy: + type: Recreate + template: + metadata: + labels: + app: changeme-app + spec: + containers: + - env: + - name: SRC_DIR + value: /data + - name: BACKUP_NAME + value: world + - name: INITIAL_DELAY + value: 2m + - name: BACKUP_INTERVAL + value: 24h + - name: PRUNE_BACKUPS_DAYS + value: "2" + - name: PAUSE_IF_NO_PLAYERS + value: "true" + - name: SERVER_PORT + value: "25565" + - name: RCON_HOST + value: localhost + - name: RCON_PORT + value: "25575" + - name: RCON_PASSWORD + valueFrom: + secretKeyRef: + key: rcon-password + name: changeme-rcon-secret + - name: RCON_RETRIES + value: "5" + - name: RCON_RETRY_INTERVAL + value: 10s + - name: EXCLUDES + value: "*.jar,cache,logs" + - name: BACKUP_METHOD + value: rclone + - name: DEST_DIR + value: /backups + - name: LINK_LATEST + value: "false" + - name: TAR_COMPRESS_METHOD + value: gzip + - name: ZSTD_PARAMETERS + value: -3 --long=25 --single-thread + - name: RCLONE_REMOTE + value: mc-dunemask-net + - name: RCLONE_DEST_DIR + value: /minecraft-backups/deltasmp-backups + - name: RCLONE_COMPRESS_METHOD + value: gzip + image: itzg/mc-backup:latest + imagePullPolicy: IfNotPresent + name: mcs-deltasmp-minecraft-mc-backup + resources: + requests: + cpu: 500m + memory: 512Mi + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /data + name: datadir + readOnly: true + - mountPath: /backups + name: backupdir + - mountPath: /config/rclone + name: rclone-config + - env: + - name: EULA + value: "TRUE" + - name: TYPE + value: VANILLA + - name: VERSION + value: "latest" + - name: DIFFICULTY + value: easy + - name: WHITELIST + - name: OPS + - name: ICON + - name: MAX_PLAYERS + value: "20" + - name: MAX_WORLD_SIZE + value: "10000" + - name: ALLOW_NETHER + value: "true" + - name: ANNOUNCE_PLAYER_ACHIEVEMENTS + value: "true" + - name: ENABLE_COMMAND_BLOCK + value: "true" + - name: FORCE_GAMEMODE + value: "false" + - name: GENERATE_STRUCTURES + value: "true" + - name: HARDCORE + value: "false" + - name: MAX_BUILD_HEIGHT + value: "256" + - name: MAX_TICK_TIME + value: "60000" + - name: SPAWN_ANIMALS + value: "true" + - name: SPAWN_MONSTERS + value: "true" + - name: SPAWN_NPCS + value: "true" + - name: SPAWN_PROTECTION + value: "16" + - name: VIEW_DISTANCE + value: "10" + - name: SEED + - name: MODE + value: survival + - name: MOTD + value: ยง6Minecluster Hosting + - name: PVP + value: "true" + - name: LEVEL_TYPE + value: DEFAULT + - name: GENERATOR_SETTINGS + - name: LEVEL + value: world + - name: MODPACK + - name: ONLINE_MODE + value: "true" + - name: MEMORY + value: 1024M + - name: JVM_OPTS + - name: JVM_XX_OPTS + - name: OVERRIDE_SERVER_PROPERTIES + value: "true" + - name: ENABLE_RCON + value: "true" + - name: RCON_PASSWORD + valueFrom: + secretKeyRef: + key: rcon-password + name: changeme-rcon-secret + image: itzg/minecraft-server:latest + imagePullPolicy: IfNotPresent + livenessProbe: + exec: + command: + - mc-health + failureThreshold: 20 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 1 + name: changeme-name + ports: + - containerPort: 25565 + name: minecraft + protocol: TCP + - containerPort: 25575 + name: rcon + protocol: TCP + readinessProbe: + exec: + command: + - mc-health + failureThreshold: 20 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 1 + resources: + requests: + cpu: 500m + memory: 512Mi + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + volumeMounts: + - mountPath: /data + name: datadir + - mountPath: /backups + name: backupdir + readOnly: true + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + fsGroup: 2000 + runAsUser: 1000 + terminationGracePeriodSeconds: 30 + volumes: + - name: datadir + persistentVolumeClaim: + claimName: changeme-pvc-name + - emptyDir: {} + name: backupdir + - name: rclone-config + secret: + defaultMode: 420 + items: + - key: rclone.conf + path: rclone.conf + secretName: rclone-config diff --git a/lib/k8s/configs/server-pvc.yml b/lib/k8s/configs/server-pvc.yml new file mode 100644 index 0000000..caeaa2b --- /dev/null +++ b/lib/k8s/configs/server-pvc.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + service: changeme-service-name + name: changeme-pvc-name + namespace: changeme-namespace +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 20Gi diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml new file mode 100644 index 0000000..c6678e6 --- /dev/null +++ b/lib/k8s/configs/server-svc.yml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + ingress.qumine.io/hostname: changeme-url + ingress.qumine.io/portname: minecraft + labels: + app: changeme-app + name: changeme-name + namespace: changeme-namespace +spec: + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: minecraft + port: 25565 + protocol: TCP + targetPort: minecraft + selector: + app: changeme-app + sessionAffinity: None + type: ClusterIP diff --git a/lib/k8s/live-logging.js b/lib/k8s/live-logging.js new file mode 100644 index 0000000..c65b34b --- /dev/null +++ b/lib/k8s/live-logging.js @@ -0,0 +1,30 @@ +import stream from "stream"; +import k8s from "@kubernetes/client-node"; +import { ERR } from "../util/logging.js"; + +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sApi = kc.makeApiClient(k8s.CoreV1Api); +export default async function liveLogging(socket, serverNamespace) { + const containerName = `mcl-${socket.mcs.serverName}`; + const podResponse = await k8sApi.listNamespacedPod(serverNamespace); + const pods = podResponse.body.items.map((vp1) => vp1.metadata.name); + const mcsPods = pods.filter((p) => p.startsWith(containerName)); + if (mcsPods.length === 0) + throw Error(`Could not find a pod that starts with ${containerName}`); + if (mcsPods.length > 1) + throw Error(`Multiple pods match the name ${containerName}`); + + const log = new k8s.Log(kc); + const logStream = new stream.PassThrough(); + logStream.on("data", (chunk) => + socket.emit("push", Buffer.from(chunk).toString()) + ); + log + .log(serverNamespace, mcsPods[0], containerName, logStream, { + follow: true, + pretty: false, + timestamps: false, + }) + .catch((e) => ERR("K8S", e)); +} diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js new file mode 100644 index 0000000..4bda593 --- /dev/null +++ b/lib/k8s/server-control.js @@ -0,0 +1,95 @@ +import k8s from "@kubernetes/client-node"; +import { ERR } from "../util/logging.js"; +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); + +const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const k8sMetrics = new k8s.Metrics(kc); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +export async function startServer(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + const { name } = serverSpec; + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const dep = deploymentRes.body.items.find( + (i) => i.metadata.name === `mcl-${name}` + ); + if (!dep) return res.status(409).send("Server does not exist!"); + if (dep.spec.replicas === 1) + return res.status(409).send("Server already started!"); + dep.spec.replicas = 1; + k8sDeps.replaceNamespacedDeployment(`mcl-${name}`, namespace, dep); + res.sendStatus(200); +} + +export async function stopServer(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + const { name } = serverSpec; + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const dep = deploymentRes.body.items.find( + (i) => i.metadata.name === `mcl-${name}` + ); + if (!dep) return res.status(409).send("Server does not exist!"); + if (dep.spec.replicas === 0) + return res.status(409).send("Server already stopped!"); + dep.spec.replicas = 0; + k8sDeps.replaceNamespacedDeployment(`mcl-${name}`, namespace, dep); + res.sendStatus(200); +} + +export async function serverList(req, res) { + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const deployments = deploymentRes.body.items.map((i) => i.metadata.name); + // TODO Add an annotation and manage using that + const serverDeployments = deployments.filter((d) => d.startsWith("mcl-")); + res.json(serverDeployments.map((sd) => sd.substring(4))); +} + +export async function getServers(req, res) { + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const deployments = deploymentRes.body.items; + const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace); + // TODO Add an annotation and manage using that + const serverDeployments = deployments.filter((d) => + d.metadata.name.startsWith("mcl-") + ); + var name, metrics, started; + const servers = serverDeployments.map((s) => { + name = s.metadata.name.substring(4); + metrics = null; + started = !!s.spec.replicas; + const pod = podMetricsResponse.items.find(({ metadata: md }) => { + return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`; + }); + if (pod) { + const podCpus = pod.containers.map( + ({ usage }) => parseInt(usage.cpu) / 1_000_000 + ); + const podMems = pod.containers.map( + ({ usage }) => parseInt(usage.memory) / 1024 + ); + metrics = { + cpu: Math.ceil(podCpus.reduce((a, b) => a + b)), + memory: Math.ceil(podMems.reduce((a, b) => a + b)), + }; + } + + return { name, metrics, started }; + }); + var clusterMetrics = { cpu: 0, memory: 0 }; + if (servers.length > 1) { + const clusterCpu = servers + .map(({ metrics }) => (metrics ? metrics.cpu : 0)) + .reduce((a, b) => a + b); + const clusterMem = servers + .map(({ metrics }) => (metrics ? metrics.memory : 0)) + .reduce((a, b) => a + b); + clusterMetrics = { cpu: clusterCpu, memory: clusterMem }; + } + res.json({ servers, clusterMetrics }); +} diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js new file mode 100644 index 0000000..0cf0e2e --- /dev/null +++ b/lib/k8s/server-create.js @@ -0,0 +1,171 @@ +import { v4 as uuidv4 } from "uuid"; +import bcrypt from "bcrypt"; +import k8s from "@kubernetes/client-node"; +import yaml from "js-yaml"; +import fs from "node:fs"; +import path from "node:path"; +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +function payloadFilter(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + const { name, url, version, serverType, difficulty, gamemode, memory } = + serverSpec; + if (!name) return res.status(400).send("Server name is required!"); + if (!url) return res.status(400).send("Server url is required!"); + if (!version) return res.status(400).send("Server version is required!"); + if (!difficulty) + return res.status(400).send("Server difficulty is required!"); + if (!serverType) return res.status(400).send("Server type is required!"); + if (!gamemode) return res.status(400).send("Server Gamemode is required!"); + if (!memory) return res.status(400).send("Memory is required!"); + req.body.name = req.body.name.toLowerCase(); + return "filtered"; +} + +function createRconSecret(serverSpec) { + const { name } = serverSpec; + const rconYaml = yaml.load( + fs.readFileSync(path.resolve("lib/k8s/configs/rcon-secret.yml"), "utf8") + ); + + // TODO: Dyamic rconPassword + const rconPassword = bcrypt.hashSync(uuidv4(), 10); + rconYaml.data["rcon-password"] = Buffer.from(rconPassword).toString("base64"); + rconYaml.metadata.labels.app = `mcl-${name}-app`; + rconYaml.metadata.name = `mcl-${name}-rcon-secret`; + rconYaml.metadata.namespace = namespace; + return rconYaml; +} + +function createServerVolume(serverSpec) { + const { name } = serverSpec; + const volumeYaml = yaml.load( + fs.readFileSync(path.resolve("lib/k8s/configs/server-pvc.yml"), "utf8") + ); + volumeYaml.metadata.labels.service = `mcl-${name}-server`; + volumeYaml.metadata.name = `mcl-${name}-volume`; + volumeYaml.metadata.namespace = namespace; + volumeYaml.spec.resources.requests.storage = "1Gi"; // TODO: Changeme + return volumeYaml; +} + +function createServerDeploy(serverSpec) { + const { + name, + version, + serverType, + difficulty, + gamemode, + memory, + motd, + maxPlayers, + seed, + modpack, + ops, + whitelist, + } = serverSpec; + const deployYaml = yaml.load( + fs.readFileSync( + path.resolve("lib/k8s/configs/server-deployment.yml"), + "utf8" + ) + ); + deployYaml.metadata.name = `mcl-${name}`; + deployYaml.metadata.namespace = namespace; + deployYaml.spec.replicas = 0; // TODO: User control for autostart + deployYaml.spec.selector.matchLabels.app = `mcl-${name}-app`; + deployYaml.spec.template.metadata.labels.app = `mcl-${name}-app`; + deployYaml.spec.template.spec.containers.splice(0, 1); //TODO: Currently removing backup container + const serverContainer = deployYaml.spec.template.spec.containers[0]; + + // Enviornment variables + serverContainer.env.find(({ name: n }) => n === "TYPE").value = serverType; + serverContainer.env.find(({ name: n }) => n === "VERSION").value = version; + serverContainer.env.find(({ name: n }) => n === "DIFFICULTY").value = + difficulty; + serverContainer.env.find(({ name: n }) => n === "MODE").value = gamemode; + serverContainer.env.find(({ name: n }) => n === "MOTD").value = motd; + serverContainer.env.find(({ name: n }) => n === "MAX_PLAYERS").value = + maxPlayers; + serverContainer.env.find(({ name: n }) => n === "SEED").value = seed; + serverContainer.env.find(({ name: n }) => n === "OPS").value = ops; + serverContainer.env.find(({ name: n }) => n === "WHITELIST").value = + whitelist; + serverContainer.env.find( + ({ name: n }) => n === "MEMORY" + ).value = `${memory}M`; + if (version !== "VANILLA") + delete serverContainer.env.find(({ name: n }) => n === "MODPACK").value; + else + serverContainer.env.find(({ name: n }) => n === "MODPACK").value = modpack; + + serverContainer.env.find( + ({ name }) => name === "RCON_PASSWORD" + ).valueFrom.secretKeyRef.name = `mcl-${name}-rcon-secret`; + // Server Container Name + serverContainer.name = `mcl-${name}`; + // Resources + serverContainer.resources.requests.memory = `${memory}Mi`; + // serverContainer.resources.limits.memory = `${memory}Mi`; // TODO Allow for limits beyond initial startup + // Volumes + deployYaml.spec.template.spec.volumes.find( + ({ name }) => name === "datadir" + ).persistentVolumeClaim.claimName = `mcl-${name}-volume`; + deployYaml.spec.template.spec.containers[0] = serverContainer; + return deployYaml; +} + +function createServerService(serverSpec) { + const { name, url } = serverSpec; + const serviceYaml = yaml.load( + fs.readFileSync(path.resolve("lib/k8s/configs/server-svc.yml"), "utf8") + ); + serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = url; + serviceYaml.metadata.labels.app = `mcl-${name}-app`; + serviceYaml.metadata.name = `mcl-${name}-server`; + serviceYaml.metadata.namespace = namespace; + serviceYaml.spec.selector.app = `mcl-${name}-app`; + return serviceYaml; +} + +function createRconService(serverSpec) { + const { name, url } = serverSpec; + const rconSvcYaml = yaml.load( + fs.readFileSync(path.resolve("lib/k8s/configs/rcon-svc.yml"), "utf8") + ); + rconSvcYaml.metadata.labels.app = `mcl-${name}-app`; + rconSvcYaml.metadata.name = `mcl-${name}-rcon`; + rconSvcYaml.metadata.namespace = namespace; + rconSvcYaml.spec.selector.app = `mcl-${name}-app`; + return rconSvcYaml; +} + +export default async function createServer(req, res) { + if (payloadFilter(req, res) !== "filtered") return; + const serverSpec = req.body; + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const deployments = deploymentRes.body.items.map((i) => i.metadata.name); + if (deployments.includes(`mcl-${serverSpec.name}`)) + return res.status(409).send("Server already exists!"); + const pvcRes = await k8sCore.listNamespacedPersistentVolumeClaim(namespace); + const pvcs = pvcRes.body.items.map((i) => i.metadata.name); + if (pvcs.includes(`mcl-${serverSpec.name}-volume`)) + return res.status(409).send("Server PVC already exists!"); + const rconSecret = createRconSecret(serverSpec); + const serverVolume = createServerVolume(serverSpec); + const serverDeploy = createServerDeploy(serverSpec); + const serverService = createServerService(serverSpec); + const rconService = createRconService(serverSpec); + k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume); + k8sCore.createNamespacedSecret(namespace, rconSecret); + k8sCore.createNamespacedService(namespace, serverService); + k8sCore.createNamespacedService(namespace, rconService); + k8sDeps.createNamespacedDeployment(namespace, serverDeploy); + + res.sendStatus(200); +} diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js new file mode 100644 index 0000000..76b540c --- /dev/null +++ b/lib/k8s/server-delete.js @@ -0,0 +1,55 @@ +import k8s from "@kubernetes/client-node"; +import { ERR } from "../util/logging.js"; +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); + +const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +const deleteError = (res) => (err) => { + res.status(500).send("Error deleting a resource!"); + ERR("K8S", "An error occurred while deleting a resource", err); +}; + +export default async function deleteServer(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + const { name } = serverSpec; + // Ensure deployment exists + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const deployments = deploymentRes.body.items.map((i) => i.metadata.name); + if (!deployments.includes(`mcl-${serverSpec.name}`)) + return res.status(409).send("Server does not exist!"); + // Delete in reverse order + const deleteDeploy = k8sDeps.deleteNamespacedDeployment( + `mcl-${serverSpec.name}`, + namespace + ); + const deleteService = k8sCore.deleteNamespacedService( + `mcl-${name}-server`, + namespace + ); + const deleteRconService = k8sCore.deleteNamespacedService( + `mcl-${name}-rcon`, + namespace + ); + await deleteDeploy.catch(deleteError(res)); + const deleteRconSecret = k8sCore.deleteNamespacedSecret( + `mcl-${name}-rcon-secret`, + namespace + ); + const deleteVolume = k8sCore.deleteNamespacedPersistentVolumeClaim( + `mcl-${name}-volume`, + namespace + ); + Promise.all([ + deleteService, + deleteRconService, + deleteRconSecret, + deleteVolume, + ]) + .then(() => res.sendStatus(200)) + .catch(deleteError(res)); +} diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js new file mode 100644 index 0000000..4c7eb35 --- /dev/null +++ b/lib/routes/server-route.js @@ -0,0 +1,19 @@ +import { Router, json as jsonMiddleware } from "express"; +import { + startServer, + stopServer, + serverList, + getServers, +} from "../k8s/server-control.js"; +import createServer from "../k8s/server-create.js"; +import deleteServer from "../k8s/server-delete.js"; +const router = Router(); +router.use(jsonMiddleware()); +// Routes +router.post("/create", createServer); +router.delete("/delete", deleteServer); +router.post("/start", startServer); +router.post("/stop", stopServer); +router.get("/list", serverList); +router.get("/instances", getServers); +export default router; diff --git a/lib/routes/system-route.js b/lib/routes/system-route.js new file mode 100644 index 0000000..ddc5638 --- /dev/null +++ b/lib/routes/system-route.js @@ -0,0 +1,27 @@ +import { Router } from "express"; +import k8s from "@kubernetes/client-node"; +import { WARN } from "../util/logging.js"; +const router = Router(); +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sApi = kc.makeApiClient(k8s.CoreV1Api); +// Get Routes +router.get("/available", (req, res) => { + k8sApi.listNode().then((nodeRes) => { + const nodeAllocatable = nodeRes.body.items.map((i) => i.status.allocatable); + const nodeResources = nodeAllocatable.map(({ cpu, memory }) => ({ + cpu, + memory, + })); + const { cpu: clusterCpu, memory: clusterMemory } = nodeResources[0]; + const isIdentical = ({ cpu, memory }) => + clusterMemory === memory && clusterCpu === cpu; + if (!nodeResources.every(isIdentical)) + WARN("ROUTES", "Warning, node resources were non-consistent"); + const availableCpu = parseInt(clusterCpu) * 1000; + const availableMemory = parseInt(clusterMemory) / 1024; + res.json({ cpu: availableCpu, memory: availableMemory }); + }); +}); + +export default router; diff --git a/lib/routes/vitals-route.js b/lib/routes/vitals-route.js new file mode 100644 index 0000000..cfedce3 --- /dev/null +++ b/lib/routes/vitals-route.js @@ -0,0 +1,6 @@ +import { Router } from "express"; +const router = Router(); +// Get Routes +router.get("/healthz", (req, res) => res.sendStatus(200)); + +export default router; diff --git a/lib/server/rcon.js b/lib/server/rcon.js new file mode 100644 index 0000000..d2535b1 --- /dev/null +++ b/lib/server/rcon.js @@ -0,0 +1,31 @@ +import k8s from "@kubernetes/client-node"; +import { Rcon as RconClient } from "rcon-client"; +import { ERR } from "../util/logging.js"; +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +export default async function rconInterface(socket) { + if (socket.rconClient) + return VERB("RCON", "Socket already connected to RCON"); + const rconSecret = `mcl-${socket.mcs.serverName}-rcon-secret`; + const rconRes = await k8sCore.readNamespacedSecret(rconSecret, namespace); + const rconPassword = Buffer.from( + rconRes.body.data["rcon-password"], + "base64" + ).toString("utf8"); + const rconHost = `mcl-${socket.mcs.serverName}-rcon`; + const rcon = new RconClient({ + host: rconHost, + port: 25575, + password: rconPassword, + }); + rcon.on("error", (error) => socket.emit("push", error)); + try { + await rcon.connect(); + } catch (error) { + ERR("RCON", `Could not connect to 'mcl-${socket.mcs.serverName}-rcon'`); + } + socket.rconClient = rcon; +} diff --git a/lib/server/router.js b/lib/server/router.js new file mode 100644 index 0000000..4bc466b --- /dev/null +++ b/lib/server/router.js @@ -0,0 +1,23 @@ +// Imports +import express from "express"; + +// Routes +import vitals from "../routes/vitals-route.js"; +import systemRoute from "../routes/system-route.js"; +import serverRoute from "../routes/server-route.js"; + +export default function buildRoutes(pg, skio) { + const router = express.Router(); + // Special Routes + router.use(vitals); + router.all("/", (req, res) => res.redirect("/mcl")); + + // Middlewares + + // Routes + router.use("/api/system", systemRoute); + router.use("/api/server", serverRoute); + // router.use("/mcl", react); // Static Build Route + + return router; +} diff --git a/lib/server/sockets.js b/lib/server/sockets.js new file mode 100644 index 0000000..2b63ede --- /dev/null +++ b/lib/server/sockets.js @@ -0,0 +1,46 @@ +import { Server as Skio } from "socket.io"; +import { VERB, WARN, ERR } from "../util/logging.js"; +import liveLogging from "../k8s/live-logging.js"; +import rconInterface from "./rcon.js"; + +const namespace = process.env.MCL_SERVER_NAMESPACE; + +async function rconSend(socket, m) { + if (!socket.rconClient) + return WARN("RCON", "Message sent before RCON connected!"); + try { + const r = await socket.rconClient.send(m); + socket.emit("push", `[RCON]: ${r}`); + } catch (error) { + WARN("RCON", error); + } +} + +const socketConnect = async (io, socket) => { + VERB("WS", "Websocket connecting"); + socket.mcs = { serverName: socket.handshake.query.serverName }; + try { + await liveLogging(socket, namespace); + await rconInterface(socket); + socket.on("msg", (m) => rconSend(socket, m)); + } catch (err) { + ERR("SOCKETS", err); + socket.send("push", err); + socket.disconnect(); + } +}; + +const socketAuth = (socket, next) => { + const { token } = socket.handshake.auth; + // next(new Error("Bad Token")); + next(); +}; + +const applySockets = (server) => { + const io = new Skio(server); + io.on("connection", (socket) => socketConnect(io, socket)); + VERB("WS", "Configured Websockets"); + return io; +}; + +export default applySockets; diff --git a/lib/util/logging.js b/lib/util/logging.js new file mode 100644 index 0000000..2c62b3e --- /dev/null +++ b/lib/util/logging.js @@ -0,0 +1,28 @@ +// Imports +import { Chalk } from "chalk"; +const { redBright, greenBright, yellowBright, cyanBright, magentaBright } = + new Chalk({ level: 2 }); + +// Logging +const logColor = (color, header, ...args) => + console.log(color(header), ...args); + +export const logError = (...args) => logColor(redBright, ...args); + +export const logConfirm = (...args) => logColor(greenBright, ...args); + +export const logWarn = (...args) => logColor(yellowBright, ...args); + +export const logInfo = (...args) => logColor(cyanBright, ...args); + +export const logVerbose = (...args) => logColor(magentaBright, ...args); + +export const ERR = (header, ...args) => logError(`[${header}]`, ...args); + +export const OK = (header, ...args) => logConfirm(`[${header}]`, ...args); + +export const WARN = (header, ...args) => logWarn(`[${header}]`, ...args); + +export const INFO = (header, ...args) => logInfo(`[${header}]`, ...args); + +export const VERB = (header, ...args) => logVerbose(`[${header}]`, ...args); diff --git a/package-lock.json b/package-lock.json index 3490666..0fc9ca3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,31 @@ "name": "minecluster", "version": "0.0.1-alpha.0", "license": "LGPL-2.1", + "dependencies": { + "@kubernetes/client-node": "^0.18.1", + "bcrypt": "^5.1.0", + "chalk": "^5.2.0", + "express": "^4.18.2", + "figlet": "^1.5.2", + "js-yaml": "^4.1.0", + "rcon-client": "^4.2.3", + "socket.io": "^4.6.1", + "uuid": "^9.0.0" + }, "devDependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@mui/icons-material": "^5.11.11", + "@mui/material": "^5.11.11", "@tanstack/react-query": "^4.26.0", "@vitejs/plugin-react": "^3.1.0", "concurrently": "^7.6.0", + "nodemon": "^2.0.21", "prettier": "^2.8.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.8.2", + "socket.io-client": "^4.6.1", "vite": "^4.1.4" } }, @@ -284,6 +301,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/parser": { "version": "7.21.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", @@ -326,6 +357,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", @@ -375,6 +418,164 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", + "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.1.3" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/cache": { + "version": "11.10.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", + "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "dev": true, + "dependencies": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.1.3" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==", + "dev": true + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "dev": true, + "dependencies": { + "@emotion/memoize": "^0.8.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==", + "dev": true + }, + "node_modules/@emotion/react": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", + "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "dev": true, + "dependencies": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", + "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==", + "dev": true + }, + "node_modules/@emotion/styled": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", + "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==", + "dev": true + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "dev": true, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==", + "dev": true + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==", + "dev": true + }, "node_modules/@esbuild/android-arm": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", @@ -774,6 +975,355 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@kubernetes/client-node": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.18.1.tgz", + "integrity": "sha512-F3JiK9iZnbh81O/da1tD0h8fQMi/MDttWc/JydyUVnjPEom55wVfnpl4zQ/sWD4uKB8FlxYRPiLwV2ZXB+xPKw==", + "dependencies": { + "@types/js-yaml": "^4.0.1", + "@types/node": "^18.11.17", + "@types/request": "^2.47.1", + "@types/ws": "^8.5.3", + "byline": "^5.0.0", + "isomorphic-ws": "^5.0.0", + "js-yaml": "^4.1.0", + "jsonpath-plus": "^7.2.0", + "request": "^2.88.0", + "rfc4648": "^1.3.0", + "stream-buffers": "^3.0.2", + "tar": "^6.1.11", + "tmp-promise": "^3.0.2", + "tslib": "^2.4.1", + "underscore": "^1.13.6", + "ws": "^8.11.0" + }, + "optionalDependencies": { + "openid-client": "^5.3.0" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@mui/base": { + "version": "5.0.0-alpha.119", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.119.tgz", + "integrity": "sha512-XA5zhlYfXi67u613eIF0xRmktkatx6ERy3h+PwrMN5IcWFbgiL1guz8VpdXON+GWb8+G7B8t5oqTFIaCqaSAeA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.11.tgz", + "integrity": "sha512-0YK0K9GfW1ysw9z4ztWAjLW+bktf+nExMyn2+EQe1Ijb0kF2kz1kIOmb4+di0/PsXG70uCuw4DhEIdNd+JQkRA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.11.tgz", + "integrity": "sha512-Eell3ADmQVE8HOpt/LZ3zIma8JSvPh3XgnhwZLT0k5HRqZcd6F/QDHc7xsWtgz09t+UEFvOYJXjtrwKmLdwwpw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.11.tgz", + "integrity": "sha512-sSe0dmKjB1IGOYt32Pcha+cXV3IIrX5L5mFAF9LDRssp/x53bluhgLLbkc8eTiJvueVvo6HAyze6EkFEYLQRXQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/base": "5.0.0-alpha.119", + "@mui/core-downloads-tracker": "^5.11.11", + "@mui/system": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.11.tgz", + "integrity": "sha512-yLgTkjNC1mpye2SOUkc+zQQczUpg8NvQAETvxwXTMzNgJK1pv4htL7IvBM5vmCKG7IHAB3hX26W2u6i7bxwF3A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.11.11", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz", + "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.11.tgz", + "integrity": "sha512-a9gaOAJBjpzypDfhbGZQ8HzdcxdxsKkFvbp1aAWZhFHBPdehEkARNh7mj851VfEhD/GdffYt85PFKFKdUta5Eg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/private-theming": "^5.11.11", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", + "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", + "dev": true, + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.11.tgz", + "integrity": "sha512-neMM5rrEXYQrOrlxUfns/TGgX4viS8K2zb9pbQh11/oUUYFlGI32Tn+PHePQx7n6Fy/0zq6WxdBFC9VpnJ5JrQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@remix-run/router": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", @@ -783,6 +1333,11 @@ "node": ">=14" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@tanstack/query-core": { "version": "4.26.0", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.26.0.tgz", @@ -820,6 +1375,105 @@ } } }, + "node_modules/@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==" + }, + "node_modules/@types/node": { + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.0.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", + "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/request": { + "version": "2.48.8", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz", + "integrity": "sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==", + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", + "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==" + }, + "node_modules/@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@vitejs/plugin-react": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz", @@ -839,11 +1493,53 @@ "vite": "^4.1.0-beta.0" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -860,6 +1556,195 @@ "node": ">=4" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "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" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", @@ -888,6 +1773,43 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001460", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz", @@ -904,18 +1826,55 @@ } ] }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=4" + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" } }, "node_modules/cliui": { @@ -932,6 +1891,15 @@ "node": ">=12" } }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -947,6 +1915,30 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/concurrently": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz", @@ -1059,12 +2051,99 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/date-fns": { "version": "2.29.3", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", @@ -1082,7 +2161,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1095,6 +2173,68 @@ } } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, "node_modules/electron-to-chromium": { "version": "1.4.320", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.320.tgz", @@ -1104,8 +2244,73 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz", + "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz", + "integrity": "sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", + "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } }, "node_modules/esbuild": { "version": "0.16.17", @@ -1153,6 +2358,11 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1162,6 +2372,216 @@ "node": ">=0.8.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "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" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/figlet": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", + "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -1179,8 +2599,26 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -1200,6 +2638,58 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -1209,11 +2699,31 @@ "node": ">=4" } }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -1230,6 +2740,151 @@ "node": ">=4" } }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-core-module": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", @@ -1242,21 +2897,93 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/jose": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", + "integrity": "sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -1269,6 +2996,27 @@ "node": ">=4" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1281,6 +3029,34 @@ "node": ">=6" } }, + "node_modules/jsonpath-plus": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.2.0.tgz", + "integrity": "sha512-zBfiUPM5nD0YZSBT/o/fbCUlCcepMIdP0CJZxM1+KgA4f2T206f6VAg9e7mX35+KlMaIc5qXW34f3BnwJ3w+RA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1320,11 +3096,133 @@ "node": ">=12" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", + "integrity": "sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { "version": "3.3.4", @@ -1338,24 +3236,308 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, + "node_modules/nodemon": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.21.tgz", + "integrity": "sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oidc-token-hash": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", + "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==", + "optional": true, + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openid-client": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.4.0.tgz", + "integrity": "sha512-hgJa2aQKcM2hn3eyVtN12tEA45ECjTJPXCgUh5YzTzy9qwapCvmDTVPWOcWVL0d34zeQoQ/hbG9lJhl3AYxJlQ==", + "optional": true, + "dependencies": { + "jose": "^4.10.0", + "lru-cache": "^6.0.0", + "object-hash": "^2.0.1", + "oidc-token-hash": "^5.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/openid-client/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/openid-client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.4.21", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", @@ -1395,6 +3577,98 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rcon-client": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/rcon-client/-/rcon-client-4.2.3.tgz", + "integrity": "sha512-g+DEzI3O0Nl4Y3mPp6DHhSpYeiv+wTq8iKxCumFGO0/SMCsdNfx9bpT5RyHa7phR5dvspKfQK0ZYJp1YCtXNng==", + "dependencies": { + "typed-emitter": "^0.1.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -1420,6 +3694,12 @@ "react": "^18.2.0" } }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/react-refresh": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", @@ -1461,6 +3741,114 @@ "react-dom": ">=16.8" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1487,6 +3875,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rfc4648": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.2.tgz", + "integrity": "sha512-tLOizhR6YGovrEBLatX1sdcuhoSCXddw3mqNVAcKxGJ+J0hFeJ+SjeWCv5UPA/WU3YzWPPuCVYgXBKZUPGpKtg==" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.18.0.tgz", @@ -1512,6 +3928,30 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -1525,11 +3965,75 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "node_modules/shell-quote": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", @@ -1539,6 +4043,105 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/socket.io": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz", + "integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.4.1", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.1.tgz", + "integrity": "sha512-5UswCV6hpaRsNg5kkEHVcbBIXEYoVbMQaHJBXJCyEQ+CiFPV1NIOY0XOFWG4XR4GZcB8Kn6AsRs/9cy9TbqVMQ==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.4.0", + "socket.io-parser": "~4.2.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", + "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -1554,11 +4157,58 @@ "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", "dev": true }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1572,7 +4222,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1580,6 +4229,12 @@ "node": ">=8" } }, + "node_modules/stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==", + "dev": true + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1604,6 +4259,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dependencies": { + "tmp": "^0.2.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -1613,6 +4308,55 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -1625,9 +4369,60 @@ "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-emitter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-0.1.0.tgz", + "integrity": "sha512-Tfay0l6gJMP5rkil8CzGbLthukn+9BN/VXWcABVFPjOoelJ+koW8BuPZYk+h/L+lEeIp1fSzVRiWRPIjKVjPdg==" + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", @@ -1654,6 +4449,14 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -1663,6 +4466,48 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "node_modules/vite": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.4.tgz", @@ -1712,6 +4557,28 @@ } } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1762,6 +4629,40 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "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 + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -1777,6 +4678,15 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/yargs": { "version": "17.7.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", diff --git a/package.json b/package.json index 65c0080..d3680c9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "build:react": "vite build", "start": "node dist/app.js", "dev:server": "nodemon dist/app.js", - "dev:react": "vite" + "dev:react": "vite", + "kub": "nodemon lib/k8s.js", + "start:dev": "concurrently -k \"MCL_DEV_PORT=52025 npm run dev:server\" \" MCL_VITE_DEV_PORT=52000 MCL_VITE_BACKEND_URL=http://localhost:52025 npm run dev:react\" -n s,v -p -c green,yellow" }, "keywords": [ "Minecraft", @@ -19,13 +21,30 @@ "author": "Dunemask", "license": "LGPL-2.1", "devDependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@mui/icons-material": "^5.11.11", + "@mui/material": "^5.11.11", "@tanstack/react-query": "^4.26.0", "@vitejs/plugin-react": "^3.1.0", "concurrently": "^7.6.0", + "nodemon": "^2.0.21", "prettier": "^2.8.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.8.2", + "socket.io-client": "^4.6.1", "vite": "^4.1.4" + }, + "dependencies": { + "@kubernetes/client-node": "^0.18.1", + "bcrypt": "^5.1.0", + "chalk": "^5.2.0", + "express": "^4.18.2", + "figlet": "^1.5.2", + "js-yaml": "^4.1.0", + "rcon-client": "^4.2.3", + "socket.io": "^4.6.1", + "uuid": "^9.0.0" } } diff --git a/public/asset-attributions.txt b/public/asset-attributions.txt new file mode 100644 index 0000000..3b3b3a8 --- /dev/null +++ b/public/asset-attributions.txt @@ -0,0 +1 @@ +/images/server-backdrop.png -> https://pixabay.com/illustrations/minecraft-forest-spruce-oak-azalea-7202839/ \ No newline at end of file diff --git a/public/css/overview.css b/public/css/overview.css new file mode 100644 index 0000000..7c95705 --- /dev/null +++ b/public/css/overview.css @@ -0,0 +1,20 @@ +.overview-toolbar { + background-color: rgba(255, 255, 255, 0.5); + height: 230px; + display: flex; + justify-content: center; +} + +.overview-visual-display { + display: flex; + background-color: rgba(223, 223, 223, 0.5); + border-radius: 50%; +} + +.overview-visual-label { + text-align: center; +} + +.overview-visual-wrapper { + margin: 1rem; +} diff --git a/public/css/rcon.css b/public/css/rcon.css new file mode 100644 index 0000000..a6093ad --- /dev/null +++ b/public/css/rcon.css @@ -0,0 +1,9 @@ +.rconLogsWrapper { + overflow-y: scroll; + max-height: 20rem; + word-wrap: break-word; + margin-bottom: 10px; +} +.rconActions { + display: inline-flex; +} diff --git a/public/css/server-card.css b/public/css/server-card.css new file mode 100644 index 0000000..dc8075f --- /dev/null +++ b/public/css/server-card.css @@ -0,0 +1,82 @@ +.servers { + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +.server-card { + width: 400px; + min-height: 228px; + min-width: 250px; + max-width: 400px; + margin: 15px; + background-image: url("/images/server-backdrop.png"); + background-size: cover; + display: flex; + flex-wrap: wrap; +} + +.server-card-header { + padding: 0px; + display: inline-flex; + max-height: 32px; + height: 100%; + font-weight: bold; + text-transform: capitalize; + background-image: linear-gradient( + to right, + rgba(255, 255, 255, 1), + rgba(255, 255, 255, 0.1) + ); + width: 100%; +} + +.server-card-title { + width: 100%; + height: 100%; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.server-card-status-indicator { + margin-left: auto; + margin-right: auto; +} + +.server-card-actions-wrapper { + margin-top: auto; + justify-content: end; + width: 100%; + background-color: rgba(255, 255, 255, 0.9); +} + +.server-card-actions { + display: flex; + justify-content: center; + flex-wrap: wrap; + padding: 0px; +} + +.server-card-action { + position: relative; + height: 20%; +} + +.server-card-element { + background-color: rgba(255, 255, 255, 0.5); +} + +.server-card-metrics { + display: flex; + flex-wrap: wrap; + width: 100%; +} + +.server-card-metrics-info { + display: inline-flex; + width: 100%; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/public/images/server-backdrop.png b/public/images/server-backdrop.png new file mode 100644 index 0000000000000000000000000000000000000000..a61b6f375ba56aa934b975186f81dc7ba36ca9b8 GIT binary patch literal 29015 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 O0000 +

- -

Welcome to Minecluster!

-
+ + + + +
); diff --git a/src/ctx/SettingsContext.jsx b/src/ctx/SettingsContext.jsx new file mode 100644 index 0000000..e323177 --- /dev/null +++ b/src/ctx/SettingsContext.jsx @@ -0,0 +1,62 @@ +import React, { useReducer, createContext, useMemo } from "react"; +const SettingsContext = createContext(); + +const ACTIONS = { + UPDATE: "u", +}; + +const localSettings = localStorage.getItem("settings"); +const defaultSettings = { + simplifiedControls: false, + logAppDetails: true, + defaultPage: "home", +}; + +const settings = localSettings ? JSON.parse(localSettings) : defaultSettings; +const settingsKeys = Object.keys(defaultSettings); + +const initialState = { + pages: ["home"], + ...settings, +}; + +const settingsUpdater = (oldState, settingsUpdate) => { + const settingsToUpdate = {}; + for (var k of settingsKeys) { + settingsToUpdate[k] = oldState[k]; + if (settingsUpdate[k] === undefined) continue; + settingsToUpdate[k] = settingsUpdate[k]; + } + localStorage.setItem("settings", JSON.stringify(settingsToUpdate)); +}; + +const reducer = (state, action) => { + const { settings } = action; + // Actions + switch (action.type) { + case ACTIONS.UPDATE: + settingsUpdater(state, settings); + return { ...state, ...settings }; + default: + return state; + } +}; + +export const SettingsProvider = ({ children }) => { + const [state, dispatch] = useReducer(reducer, initialState); + + const context = { + state, + dispatch, + updateSettings: (settings) => dispatch({ type: ACTIONS.UPDATE, settings }), + }; + const contextValue = useMemo(() => context, [state, dispatch]); + + return ( + + {children} + + ); +}; + +export default SettingsContext; diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx new file mode 100644 index 0000000..aa688b3 --- /dev/null +++ b/src/nav/MCLMenu.jsx @@ -0,0 +1,85 @@ +// React imports +import { useState } from "react"; +import { Link, useLocation } from "react-router-dom"; + +// Internal Imports +import pages from "./MCLPages.jsx"; + +// Materialui +import AppBar from "@mui/material/AppBar"; +import Box from "@mui/material/Box"; +import Toolbar from "@mui/material/Toolbar"; +import IconButton from "@mui/material/IconButton"; +import Typography from "@mui/material/Typography"; +import MenuIcon from "@mui/icons-material/Menu"; +import Drawer from "@mui/material/Drawer"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; +import List from "@mui/material/List"; +import ListItemButton from "@mui/material/ListItemButton"; + +const drawerWidth = 250; +export default function MCLMenu() { + const location = useLocation(); + const [drawerOpen, setDrawer] = useState(false); + + const toggleDrawer = () => setDrawer(!drawerOpen); + const closeDrawer = () => setDrawer(false); + + const navHeader = () => { + const name = location.pathname.split("/").pop(); + const pathStr = name.charAt(0).toUpperCase() + name.slice(1); + return pathStr; + }; + + const drawerIndex = (isDrawer) => (theme) => + theme.zIndex.modal + 2 - (isDrawer ? 1 : 0); + + return ( + + + + + + + + + + + {pages.map((page, index) => ( + + {page.icon} + + + ))} + + + + + {navHeader()} + + + + + ); +} diff --git a/src/nav/MCLPages.jsx b/src/nav/MCLPages.jsx new file mode 100644 index 0000000..cf7b86c --- /dev/null +++ b/src/nav/MCLPages.jsx @@ -0,0 +1,20 @@ +import Home from "@mcl/pages/Home.jsx"; +import Create from "@mcl/pages/Create.jsx"; +// Go To https://mui.com/material-ui/material-icons/ for more! +import HomeIcon from "@mui/icons-material/Home"; +import AddIcon from "@mui/icons-material/Add"; + +export default [ + { + name: "Home", + path: "/mcl/home", + icon: , + component: , + }, + { + name: "Create", + path: "/mcl/create", + icon: , + component: , + }, +]; diff --git a/src/nav/MCLPortal.jsx b/src/nav/MCLPortal.jsx new file mode 100644 index 0000000..0ae7913 --- /dev/null +++ b/src/nav/MCLPortal.jsx @@ -0,0 +1,18 @@ +// Import React +import { Routes, Route, Navigate } from "react-router-dom"; +import pages from "./MCLPages.jsx"; + +const defaultPage = pages[0].path; + +export default function MCLPortal() { + return ( + + } /> + } /> + {pages.map((p, i) => ( + + ))} + } /> + + ); +} diff --git a/src/nav/Viewport.jsx b/src/nav/Viewport.jsx new file mode 100644 index 0000000..af78dff --- /dev/null +++ b/src/nav/Viewport.jsx @@ -0,0 +1,16 @@ +import Box from "@mui/material/Box"; +import Toolbar from "@mui/material/Toolbar"; +import MCLPortal from "./MCLPortal.jsx"; +// Import Navbar +/*import Navbar from "./Navbar.jsx";*/ +import MCLMenu from "./MCLMenu.jsx"; + +export default function Views() { + return ( +
+ + + +
+ ); +} diff --git a/src/overview/Overview.jsx b/src/overview/Overview.jsx new file mode 100644 index 0000000..a8fd33e --- /dev/null +++ b/src/overview/Overview.jsx @@ -0,0 +1,23 @@ +import { useState, useEffect } from "react"; +import { useSystemAvailable } from "@mcl/queries"; +import Box from "@mui/material/Box"; +import OverviewVisual from "./OverviewVisual.jsx"; +export default function Overview(props) { + const [memory, setMemory] = useState(100); + const [cpu, setCpu] = useState(100); + const { isLoading: systemLoading, data: systemAvailable } = + useSystemAvailable(); + + useEffect(() => { + if (systemLoading || !props.clusterMetrics) return; + setCpu((props.clusterMetrics.cpu / systemAvailable.cpu) * 100); + setMemory((props.clusterMetrics.memory / systemAvailable.memory) * 100); + }, [systemAvailable, props.clusterMetrics]); + + return ( + + + + + ); +} diff --git a/src/overview/OverviewVisual.jsx b/src/overview/OverviewVisual.jsx new file mode 100644 index 0000000..ef0d9b1 --- /dev/null +++ b/src/overview/OverviewVisual.jsx @@ -0,0 +1,44 @@ +import * as React from "react"; +import CircularProgress from "@mui/material/CircularProgress"; +import Typography from "@mui/material/Typography"; +import Box from "@mui/material/Box"; + +export default function OverviewVisual(props) { + const { value, color, label } = props; + return ( + + + + + + {`${Math.round(value)}%`} + + + + + {label} + + + ); +} diff --git a/src/pages/Create.jsx b/src/pages/Create.jsx new file mode 100644 index 0000000..7507514 --- /dev/null +++ b/src/pages/Create.jsx @@ -0,0 +1,152 @@ +import { useState, useEffect } from "react"; +import TextField from "@mui/material/TextField"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Select from "@mui/material/Select"; +import MenuItem from "@mui/material/MenuItem"; +import InputLabel from "@mui/material/InputLabel"; +import FormControl from "@mui/material/FormControl"; +import { useCreateServer, useVersionList } from "@mcl/queries"; + +const defaultServer = { + version: "latest", + name: "example", + serverType: "VANILLA", + difficulty: "easy", + maxPlayers: "20", + gamemode: "survival", + memory: "1024", + motd: "Minecluster Server Hosting", +}; + +export default function Create() { + const [spec, setSpec] = useState(defaultServer); + const versionList = useVersionList(); + const [versions, setVersions] = useState(["latest"]); + const createServer = useCreateServer(spec); + const updateSpec = (attr, val) => { + const s = { ...spec }; + s[attr] = val; + setSpec(s); + }; + + useEffect(() => { + if (!versionList.data) return; + setVersions([ + "latest", + ...versionList.data.versions + .filter(({ type: releaseType }) => releaseType === "release") + .map(({ id }) => id), + ]); + }, [versionList.data]); + + const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); + + function upsertSpec() { + if (validateSpec() !== "validated") return; + createServer(spec); + } + + function validateSpec() { + console.log("TODO CREATE VALIDATION"); + if (!spec.name) return alertValidationError("Name not included"); + if (!spec.version) return alertValidationError("Version cannot be blank"); + if (!spec.url) return alertValidationError("Url cannot be blank"); + return "validated"; + } + + function alertValidationError(reason) { + alert(`Could not validate spec because: ${reason}`); + } + + return ( + + + + + + {versions.map((v, k) => ( + + {v} + + ))} + + + Vanilla + Fabric + Paper + Spigot + + + Peaceful + Easy + Medium + Hard + + + + + + + + Survival + Creative + Adventure + Spectator + + + + + + + + + ); +} diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx new file mode 100644 index 0000000..7a9dd5e --- /dev/null +++ b/src/pages/Home.jsx @@ -0,0 +1,51 @@ +import { useState, useEffect } from "react"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import ServerCard from "../servers/ServerCard.jsx"; +import RconDialog, { useRconDialog } from "../servers/RconDialog.jsx"; +import Overview from "../overview/Overview.jsx"; +import "@mcl/css/server-card.css"; +import "@mcl/css/overview.css"; +import { useServerInstances } from "@mcl/queries"; + +export default function Home() { + const [server, setServer] = useState(); + const [servers, setServers] = useState([]); + const [rdOpen, rconToggle] = useRconDialog(); + const { isLoading, data: serversData } = useServerInstances(); + const { servers: serverInstances, clusterMetrics } = serversData ?? {}; + useEffect(() => { + if (!serverInstances) return; + serverInstances.sort((a, b) => a.name.localeCompare(b.name)); + setServers(serverInstances); + }, [serverInstances]); + + const openRcon = (s) => () => { + setServer(s); + rconToggle(); + }; + return ( + + + {!isLoading && servers.length === 0 && ( + + + No servers found! + + + )} + + {!isLoading && + servers.map((s, k) => ( + + ))} + + + + ); +} diff --git a/src/servers/RconDialog.jsx b/src/servers/RconDialog.jsx new file mode 100644 index 0000000..5183d1a --- /dev/null +++ b/src/servers/RconDialog.jsx @@ -0,0 +1,45 @@ +import { useState } from "react"; +import useMediaQuery from "@mui/material/useMediaQuery"; +import { useTheme } from "@mui/material/styles"; +import Button from "@mui/material/Button"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import DialogActions from "@mui/material/DialogActions"; +import Dialog from "@mui/material/Dialog"; +import Toolbar from "@mui/material/Toolbar"; +import RconView from "./RconView.jsx"; + +export function useRconDialog(isOpen = false) { + const [open, setOpen] = useState(isOpen); + const dialogToggle = () => setOpen(!open); + return [open, dialogToggle]; +} + +export default function RconDialog(props) { + const { serverName, open, dialogToggle } = props; + const theme = useTheme(); + const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); + return ( + + + RCON - {serverName} + + + + + + + + ); +} diff --git a/src/servers/RconSocket.js b/src/servers/RconSocket.js new file mode 100644 index 0000000..4ce94f3 --- /dev/null +++ b/src/servers/RconSocket.js @@ -0,0 +1,27 @@ +import { io } from "socket.io-client"; +export default class RconSocket { + constructor(logUpdate, serverName) { + (this.sk = io("/", { query: { serverName } })), (this.logs = []); + this.logUpdate = logUpdate; + this.sk.on("push", this.onPush.bind(this)); + this.sk.on("connect", this.onConnect.bind(this)); + } + + onPush(p) { + this.logs = [...this.logs, p]; + this.logUpdate(this.logs); + } + + send(m) { + this.sk.emit("msg", m); + } + + onConnect() { + this.logs = []; + } + + disconnect() { + if (!this.sk) return; + this.sk.disconnect(); + } +} diff --git a/src/servers/RconView.jsx b/src/servers/RconView.jsx new file mode 100644 index 0000000..e6823b3 --- /dev/null +++ b/src/servers/RconView.jsx @@ -0,0 +1,53 @@ +import { useState, useEffect, useRef } from "react"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import TextField from "@mui/material/TextField"; +import RconSocket from "./RconSocket.js"; +import "@mcl/css/rcon.css"; + +export default function RconView(props) { + const { serverName } = props; + const logsRef = useRef(0); + const [cmd, setCmd] = useState(""); + const [logs, setLogs] = useState([]); + const [rcon, setRcon] = useState({}); + const updateCmd = (e) => setCmd(e.target.value); + useEffect(function () { + setRcon(new RconSocket(setLogs, serverName)); + return () => { + if (rcon && typeof rcon.disconnect === "function") rcon.disconnect(); + }; + }, []); + + useEffect(() => { + logsRef.current.scrollTo(0, logsRef.current.scrollHeight); + }, [rcon.logs]); + + function sendCommand() { + rcon.send(cmd); + setCmd(""); + } + + return ( + +
+ {logs.map((v, k) => ( + + {v} +
+
+ ))} +
+ + + + +
+ ); +} diff --git a/src/servers/ServerCard.jsx b/src/servers/ServerCard.jsx new file mode 100644 index 0000000..ac61a5c --- /dev/null +++ b/src/servers/ServerCard.jsx @@ -0,0 +1,112 @@ +import React from "react"; +import { useStartServer, useStopServer, useDeleteServer } from "@mcl/queries"; +import Box from "@mui/material/Box"; +import Card from "@mui/material/Card"; +import CardActions from "@mui/material/CardActions"; +import CardContent from "@mui/material/CardContent"; +import Chip from "@mui/material/Chip"; +import IconButton from "@mui/material/IconButton"; +import Typography from "@mui/material/Typography"; + +import StopIcon from "@mui/icons-material/Stop"; +import TerminalIcon from "@mui/icons-material/Terminal"; +import PlayArrowIcon from "@mui/icons-material/PlayArrow"; +import PendingIcon from "@mui/icons-material/Pending"; +import DeleteForeverIcon from "@mui/icons-material/DeleteForever"; +import EditIcon from "@mui/icons-material/Edit"; + +export default function ServerCard(props) { + const { server, openRcon } = props; + const { name, metrics, started } = server; + const startServer = useStartServer(name); + const stopServer = useStopServer(name); + const deleteServer = useDeleteServer(name); + function toggleRcon() { + if (!started) return; + openRcon(); + } + + return ( + + + + {name} + + {metrics && ( + + + CPU: {metrics.cpu} + + + MEM: {metrics.memory}MB + + + )} + + +
+ + {started && ( + + + + )} + {!started && ( + + + + )} + + + + + + + + + + +
+
+ ); +} diff --git a/src/util/queries.js b/src/util/queries.js new file mode 100644 index 0000000..9636fe4 --- /dev/null +++ b/src/util/queries.js @@ -0,0 +1,60 @@ +import { useQuery, useQueryClient } from "@tanstack/react-query"; +const fetchApi = (subPath) => async () => + fetch(`/api${subPath}`).then((res) => res.json()); + +const fetchApiPost = (subPath, json) => async () => + fetch(`/api${subPath}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(json), + }).then((res) => res.json()); + +export const useServerStatus = (server) => + useQuery( + [`server-status-${server}`], + fetchApiPost("/server/status", { name: server }) + ); +export const useServerMetrics = (server) => + useQuery( + [`server-metrics-${server}`], + fetchApiPost("/server/metrics", { name: server }), + { refetchInterval: 10000 } + ); +export const useStartServer = (server) => + postJsonApi("/server/start", { name: server }, "server-instances"); +export const useStopServer = (server) => + postJsonApi("/server/stop", { name: server }, "server-instances"); +export const useDeleteServer = (server) => + postJsonApi("/server/delete", { name: server }, "server-instances", "DELETE"); +export const useCreateServer = (spec) => + postJsonApi("/server/create", spec, "server-list"); +export const useServerList = () => + useQuery(["server-list"], fetchApi("/server/list")); +export const useServerInstances = () => + useQuery(["server-instances"], fetchApi("/server/instances"), { + refetchInterval: 5000, + }); +export const useSystemAvailable = () => + useQuery(["system-available"], fetchApi("/system/available")); +export const useVersionList = () => + useQuery(["minecraft-versions"], () => + fetch("https://piston-meta.mojang.com/mc/game/version_manifest.json").then( + (r) => r.json() + ) + ); + +const postJsonApi = (subPath, body, invalidate, method = "POST") => { + const qc = useQueryClient(); + return async () => { + const res = await fetch(`/api${subPath}`, { + method, + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + qc.invalidateQueries([invalidate]); + }; +}; diff --git a/vite.config.js b/vite.config.js index fcb7553..c94b8b1 100644 --- a/vite.config.js +++ b/vite.config.js @@ -16,7 +16,7 @@ export default () => { "/socket.io": backendUrl, }, hmr: { - protocol: process.env.MCL, + protocol: process.env.MCL_VITE_DEV_PROTOCOL, }, }, build: { @@ -25,6 +25,10 @@ export default () => { base: "/mcl/", resolve: { alias: { + "@mcl/css": path.resolve("./public/css"), + "@mcl/settings": path.resolve("./src/ctx/SettingsContext.jsx"), + "@mcl/pages": path.resolve("./src/pages"), + "@mcl/queries": path.resolve("./src/util/queries.js"), "@mcl": path.resolve("./src"), }, },