From d9ab9486d00d4c62ecfc02d602a3f2f97b404a9b Mon Sep 17 00:00:00 2001 From: dunemask Date: Sat, 7 Oct 2023 12:08:02 -0600 Subject: [PATCH 01/56] [HOTFIX] Disable Non-clusterrole permissions --- lib/routes/system-route.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/routes/system-route.js b/lib/routes/system-route.js index ddc5638..5c5ec40 100644 --- a/lib/routes/system-route.js +++ b/lib/routes/system-route.js @@ -7,6 +7,8 @@ kc.loadFromDefault(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); // Get Routes router.get("/available", (req, res) => { + return res.json({cpu: 8000, memory: 16000}); + // TODO Workaround to detect available k8sApi.listNode().then((nodeRes) => { const nodeAllocatable = nodeRes.body.items.map((i) => i.status.allocatable); const nodeResources = nodeAllocatable.map(({ cpu, memory }) => ({ From 02c3a9680fb4519f3b475f8fa078ac9e49d3f953 Mon Sep 17 00:00:00 2001 From: dunemask Date: Sun, 8 Oct 2023 11:21:08 -0600 Subject: [PATCH 02/56] [CHORE] Bump deps --- package-lock.json | 549 +++++++++++++++++++++++++--------------------- package.json | 20 +- 2 files changed, 314 insertions(+), 255 deletions(-) diff --git a/package-lock.json b/package-lock.json index d8e509a..39895d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1-alpha.0", "license": "LGPL-2.1", "dependencies": { - "@kubernetes/client-node": "^0.18.1", + "@kubernetes/client-node": "^0.19.0", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", @@ -17,23 +17,23 @@ "js-yaml": "^4.1.0", "rcon-client": "^4.2.3", "socket.io": "^4.7.2", - "uuid": "^9.0.0" + "uuid": "^9.0.1" }, "devDependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/material": "^5.14.5", - "@tanstack/react-query": "^4.33.0", - "@vitejs/plugin-react": "^4.0.4", - "concurrently": "^8.2.0", + "@mui/icons-material": "^5.14.12", + "@mui/material": "^5.14.12", + "@tanstack/react-query": "^4.36.1", + "@vitejs/plugin-react": "^4.1.0", + "concurrently": "^8.2.1", "nodemon": "^3.0.1", - "prettier": "^3.0.2", + "prettier": "^3.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.15.0", + "react-router-dom": "^6.16.0", "socket.io-client": "^4.7.2", - "vite": "^4.4.9" + "vite": "^4.4.11" } }, "node_modules/@ampproject/remapping": { @@ -50,12 +50,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "engines": { @@ -113,34 +113,34 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", + "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", - "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", + "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.10", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -151,13 +151,19 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -167,13 +173,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", - "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -183,22 +189,22 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -217,28 +223,28 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -290,44 +296,44 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", - "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", + "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -386,9 +392,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -428,9 +434,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", - "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", + "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -440,33 +446,33 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", + "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -475,13 +481,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -986,6 +992,44 @@ "node": ">=12" } }, + "node_modules/@floating-ui/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", + "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", + "dev": true, + "dependencies": { + "@floating-ui/utils": "^0.1.3" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", + "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "dev": true, + "dependencies": { + "@floating-ui/core": "^1.4.2", + "@floating-ui/utils": "^0.1.3" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.2.tgz", + "integrity": "sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==", + "dev": true, + "dependencies": { + "@floating-ui/dom": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", + "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==", + "dev": true + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -1035,12 +1079,12 @@ } }, "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==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.19.0.tgz", + "integrity": "sha512-WTOjGuFQ8yeW3+qD6JrAYhpwpoQbe9R8cA/61WCyFrNawSTUgLstHu7EsZRYEs39er3jDn3wCEaczz+VOFlc2Q==", "dependencies": { "@types/js-yaml": "^4.0.1", - "@types/node": "^18.11.17", + "@types/node": "^20.1.1", "@types/request": "^2.47.1", "@types/ws": "^8.5.3", "byline": "^5.0.0", @@ -1051,9 +1095,7 @@ "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": { @@ -1124,19 +1166,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.11.tgz", - "integrity": "sha512-FdKZGPd8qmC3ZNke7CNhzcEgToc02M6WYZc9hcBsNQ17bgAd3s9F//1bDDYgMVBYxDM71V0sv/hBHlOY4I1ZVA==", + "version": "5.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.18.tgz", + "integrity": "sha512-e9ZCy/ndhyt5MTshAS3qAUy/40UiO0jX+kAo6a+XirrPJE+rrQW+mKPSI0uyp+5z4Vh+z0pvNoJ2S2gSrNz3BQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@emotion/is-prop-valid": "^1.2.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.1", + "@floating-ui/react-dom": "^2.0.2", + "@mui/types": "^7.2.5", + "@mui/utils": "^5.14.12", "@popperjs/core": "^2.11.8", "clsx": "^2.0.0", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" @@ -1157,9 +1198,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.5.tgz", - "integrity": "sha512-+wpGH1USwPcKMFPMvXqYPC6fEvhxM3FzxC8lyDiNK/imLyyJ6y2DPb1Oue7OGIKJWBmYBqrWWtfovrxd1aJHTA==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.12.tgz", + "integrity": "sha512-WZhCkKqhrXaSVBzoC6LNcVkIawS000OOt7gmnp4g9HhyvN0PSclRXc/JrkC7EwfzUAZJh+hiK2LaVsbtOpNuOg==", "dev": true, "funding": { "type": "opencollective", @@ -1167,12 +1208,12 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.3.tgz", - "integrity": "sha512-XkxWPhageu1OPUm2LWjo5XqeQ0t2xfGe8EiLkRW9oz2LHMMZmijvCxulhgquUVTF1DnoSh+3KoDLSsoAFtVNVw==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.12.tgz", + "integrity": "sha512-aFm6g/AIB3RQN9h/4MKoBoBybLZXeR3aDHWNx6KzemEpIlElUxv5uXRX5Qk1VC6v/YPkhbaPsiLLjsRSTiZF3w==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6" + "@babel/runtime": "^7.23.1" }, "engines": { "node": ">=12.0.0" @@ -1193,17 +1234,17 @@ } }, "node_modules/@mui/material": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.5.tgz", - "integrity": "sha512-4qa4GMfuZH0Ai3mttk5ccXP8a3sf7aPlAJwyMrUSz6h9hPri6BPou94zeu3rENhhmKLby9S/W1y+pmficy8JKA==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.12.tgz", + "integrity": "sha512-EelF2L46VcVqhg3KjzIGBBpOtcBgRh0MMy9Efuk6Do81QdcZsFC9RebCVAflo5jIdbHiBmxBs5/l5Q9NjONozg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@mui/base": "5.0.0-beta.11", - "@mui/core-downloads-tracker": "^5.14.5", - "@mui/system": "^5.14.5", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.1", + "@mui/base": "5.0.0-beta.18", + "@mui/core-downloads-tracker": "^5.14.12", + "@mui/system": "^5.14.12", + "@mui/types": "^7.2.5", + "@mui/utils": "^5.14.12", "@types/react-transition-group": "^4.4.6", "clsx": "^2.0.0", "csstype": "^3.1.2", @@ -1238,13 +1279,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.5.tgz", - "integrity": "sha512-cC4C5RrpXpDaaZyH9QwmPhRLgz+f2SYbOty3cPkk4qPSOSfif2ZEcDD9HTENKDDd9deB+xkPKzzZhi8cxIx8Ig==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.12.tgz", + "integrity": "sha512-TWwm+9+BgHFpoR3w04FG+IqID4ALa74A27RuKq2CEaWgxliBZB24EVeI6djfjFt5t4FYmIb8BMw2ZJEir7YjLQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.1", + "@mui/utils": "^5.14.12", "prop-types": "^15.8.1" }, "engines": { @@ -1265,12 +1306,12 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz", - "integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.12.tgz", + "integrity": "sha512-bocxt1nDmXfB3gpLfCCmFCyJ7sVmscFs+PuheO210QagZwHVp47UIRT1AiswLDYSQo1ZqmVGn7KLEJEYK0d4Xw==", "dev": true, "dependencies": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.23.1", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1297,16 +1338,16 @@ } }, "node_modules/@mui/system": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.5.tgz", - "integrity": "sha512-mextXZHDeGcR7E1kx43TRARrVXy+gI4wzpUgNv7MqZs1dvTVXQGVeAT6ydj9d6FUqHBPMNLGV/21vJOrpqsL+w==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.12.tgz", + "integrity": "sha512-6DXfjjLhW0/ia5qU3Crke7j+MnfDbMBOHlLIrqbrEqNs0AuSBv8pXniEGb+kqO0H804NJreRTEJRjCngwOX5CA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@mui/private-theming": "^5.14.5", - "@mui/styled-engine": "^5.13.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.1", + "@mui/private-theming": "^5.14.12", + "@mui/styled-engine": "^5.14.12", + "@mui/types": "^7.2.5", + "@mui/utils": "^5.14.12", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1337,12 +1378,12 @@ } }, "node_modules/@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.5.tgz", + "integrity": "sha512-S2BwfNczr7VwS6ki8GoAXJyARoeSJDLuxOEPs3vEMyTALlf9PrdHv+sluX7kk3iKrCg/ML2mIWwapZvWbkMCQA==", "dev": true, "peerDependencies": { - "@types/react": "*" + "@types/react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1351,14 +1392,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.5.tgz", - "integrity": "sha512-6Hzw63VR9C5xYv+CbjndoRLU6Gntal8rJ5W+GUzkyHrGWIyYPWZPa6AevnyGioySNETATe1H9oXS8f/7qgIHJA==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.12.tgz", + "integrity": "sha512-RFNXnhKQlzIkIUig6mmv0r5VbtjPdWoaBPYicq25LETdZux59HAqoRdWw15T7lp3c7gXOoE8y67+hTB8C64m2g==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.1", + "@babel/runtime": "^7.23.1", + "@types/prop-types": "^15.7.7", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1370,7 +1410,13 @@ "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/@popperjs/core": { @@ -1384,9 +1430,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz", - "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.9.0.tgz", + "integrity": "sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA==", "dev": true, "engines": { "node": ">=14.0.0" @@ -1398,9 +1444,9 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@tanstack/query-core": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.33.0.tgz", - "integrity": "sha512-qYu73ptvnzRh6se2nyBIDHGBQvPY1XXl3yR769B7B6mIDD7s+EZhdlWHQ67JI6UOTFRaI7wupnTnwJ3gE0Mr/g==", + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", + "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", "dev": true, "funding": { "type": "github", @@ -1408,12 +1454,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.33.0.tgz", - "integrity": "sha512-97nGbmDK0/m0B86BdiXzx3EW9RcDYKpnyL2+WwyuLHEgpfThYAnXFaMMmnTDuAO4bQJXEhflumIEUfKmP7ESGA==", + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.36.1.tgz", + "integrity": "sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==", "dev": true, "dependencies": { - "@tanstack/query-core": "4.33.0", + "@tanstack/query-core": "4.36.1", "use-sync-external-store": "^1.2.0" }, "funding": { @@ -1434,6 +1480,47 @@ } } }, + "node_modules/@types/babel__core": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", + "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", + "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", + "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", + "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, "node_modules/@types/caseless": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", @@ -1458,9 +1545,9 @@ "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==" + "version": "20.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", + "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -1469,9 +1556,9 @@ "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==", + "version": "15.7.8", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", + "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==", "dev": true }, "node_modules/@types/react": { @@ -1485,15 +1572,6 @@ "csstype": "^3.0.2" } }, - "node_modules/@types/react-is": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", - "integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-transition-group": { "version": "4.4.6", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", @@ -1534,14 +1612,15 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz", - "integrity": "sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", + "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", "dev": true, "dependencies": { - "@babel/core": "^7.22.9", + "@babel/core": "^7.22.20", "@babel/plugin-transform-react-jsx-self": "^7.22.5", "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "@types/babel__core": "^7.20.2", "react-refresh": "^0.14.0" }, "engines": { @@ -1807,9 +1886,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "dev": true, "funding": [ { @@ -1826,10 +1905,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -1876,9 +1955,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001522", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", - "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==", + "version": "1.0.30001546", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", + "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", "dev": true, "funding": [ { @@ -2012,9 +2091,9 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concurrently": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.0.tgz", - "integrity": "sha512-nnLMxO2LU492mTUj9qX/az/lESonSZu81UznYDoXtz1IQf996ixVqPAgHXwvHiHCAef/7S8HIK+fTFK7Ifk8YA==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.1.tgz", + "integrity": "sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==", "dev": true, "dependencies": { "chalk": "^4.1.2", @@ -2278,9 +2357,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.497", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.497.tgz", - "integrity": "sha512-9cvj6XkrgyxDySKJWYVIyq7p9bOAkH3M3jANgvWNX/F2jIAfbBN4oBNLJg1i68I8wAKVuih2IL4y1n9hqbL3Aw==", + "version": "1.4.544", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.544.tgz", + "integrity": "sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==", "dev": true }, "node_modules/emoji-regex": { @@ -3633,9 +3712,9 @@ } }, "node_modules/prettier": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", - "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -3780,12 +3859,12 @@ } }, "node_modules/react-router": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz", - "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.16.0.tgz", + "integrity": "sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA==", "dev": true, "dependencies": { - "@remix-run/router": "1.8.0" + "@remix-run/router": "1.9.0" }, "engines": { "node": ">=14.0.0" @@ -3795,13 +3874,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz", - "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.16.0.tgz", + "integrity": "sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg==", "dev": true, "dependencies": { - "@remix-run/router": "1.8.0", - "react-router": "6.15.0" + "@remix-run/router": "1.9.0", + "react-router": "6.16.0" }, "engines": { "node": ">=14.0.0" @@ -4375,25 +4454,6 @@ "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", @@ -4505,11 +4565,6 @@ "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", @@ -4519,9 +4574,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -4579,9 +4634,13 @@ } }, "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==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -4608,9 +4667,9 @@ } }, "node_modules/vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/package.json b/package.json index d51e3a1..1e9d5c0 100644 --- a/package.json +++ b/package.json @@ -24,21 +24,21 @@ "devDependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/material": "^5.14.5", - "@tanstack/react-query": "^4.33.0", - "@vitejs/plugin-react": "^4.0.4", - "concurrently": "^8.2.0", + "@mui/icons-material": "^5.14.12", + "@mui/material": "^5.14.12", + "@tanstack/react-query": "^4.36.1", + "@vitejs/plugin-react": "^4.1.0", + "concurrently": "^8.2.1", "nodemon": "^3.0.1", - "prettier": "^3.0.2", + "prettier": "^3.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.15.0", + "react-router-dom": "^6.16.0", "socket.io-client": "^4.7.2", - "vite": "^4.4.9" + "vite": "^4.4.11" }, "dependencies": { - "@kubernetes/client-node": "^0.18.1", + "@kubernetes/client-node": "^0.19.0", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", @@ -46,6 +46,6 @@ "js-yaml": "^4.1.0", "rcon-client": "^4.2.3", "socket.io": "^4.7.2", - "uuid": "^9.0.0" + "uuid": "^9.0.1" } } From cee971e0063d541c9915602a803c38b0c7f4d267 Mon Sep 17 00:00:00 2001 From: dunemask Date: Sun, 8 Oct 2023 11:50:52 -0600 Subject: [PATCH 03/56] [FEATURE] Adjust creation page --- src/pages/Create.jsx | 157 +++--------------------------------- src/pages/CreateOptions.jsx | 154 +++++++++++++++++++++++++++++++++++ src/pages/Home.jsx | 1 + 3 files changed, 164 insertions(+), 148 deletions(-) create mode 100644 src/pages/CreateOptions.jsx diff --git a/src/pages/Create.jsx b/src/pages/Create.jsx index 7507514..0338087 100644 --- a/src/pages/Create.jsx +++ b/src/pages/Create.jsx @@ -1,152 +1,13 @@ -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"; +import CreateOptions from "./CreateOptions.jsx"; +export default function Create(){ + return ( + + {/**/} + {/**/} -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/CreateOptions.jsx b/src/pages/CreateOptions.jsx new file mode 100644 index 0000000..ea66102 --- /dev/null +++ b/src/pages/CreateOptions.jsx @@ -0,0 +1,154 @@ +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: "5", + gamemode: "survival", + memory: "1024", + motd: `\\u00A7e\\u00A7ka\\u00A7l\\u00A7aMine\\u00A76Cluster\\u00A7r\\u00A78\\u00A7b\\u00A7ka`, +}; + +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 index 1c79043..d94f78f 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -53,6 +53,7 @@ export default function Home() { dialogToggle={rconToggle} serverName={server} /> + ); } From ef00eef4640d5ab5a782d3fdc751e99a86b02762 Mon Sep 17 00:00:00 2001 From: dunemask Date: Sun, 8 Oct 2023 11:51:08 -0600 Subject: [PATCH 04/56] [FEATURE] Adjust creation page --- lib/index.js | 0 lib/k8s.js | 8 - lib/storage/s3-integration.js | 35 + package-lock.json | 1958 +++++++++++++++++++++++++++++++++ package.json | 3 + src/nav/MCLMenu.jsx | 36 - 6 files changed, 1996 insertions(+), 44 deletions(-) delete mode 100644 lib/index.js delete mode 100644 lib/k8s.js create mode 100644 lib/storage/s3-integration.js diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/lib/k8s.js b/lib/k8s.js deleted file mode 100644 index b842159..0000000 --- a/lib/k8s.js +++ /dev/null @@ -1,8 +0,0 @@ -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/storage/s3-integration.js b/lib/storage/s3-integration.js new file mode 100644 index 0000000..2802214 --- /dev/null +++ b/lib/storage/s3-integration.js @@ -0,0 +1,35 @@ +import multer from "multer"; +import multerS3 from "multer-s3"; +import AWS from "aws-sdk"; + +// Environment Variables +const { + MCL_S3_ENDPOINT: s3Endpoint, + MCL_S3_ACCESS_KEY_ID: s3KeyId, + MCL_S3_ACCESS_KEY: s3Key, +} = process.env; + +export const mcl = "mcl"; + +export const s3 = new AWS.S3({ + endpoint: s3Endpoint, + accessKeyId: s3KeyId, + secretAccessKey: s3Key, + sslEnabled: true, + s3ForcePathStyle: true, +}); + +const storage = multerS3({ + s3, + bucket, + contentType: multerS3.AUTO_CONTENT_TYPE, + metadata: (req, file, cb) => { + cb(null, { fieldName: file.fieldname }); + }, + key: (req, file, cb) => { + cb(null, Date.now().toString()); + }, +}); + +export const upload = multer({ storage }); + diff --git a/package-lock.json b/package-lock.json index 39895d7..1c1570f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,14 @@ "license": "LGPL-2.1", "dependencies": { "@kubernetes/client-node": "^0.19.0", + "aws-sdk": "^2.1472.0", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", "figlet": "^1.6.0", "js-yaml": "^4.1.0", + "multer": "^1.4.5-lts.1", + "multer-s3": "^3.0.1", "rcon-client": "^4.2.3", "socket.io": "^4.7.2", "uuid": "^9.0.1" @@ -49,6 +52,826 @@ "node": ">=6.0.0" } }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "peer": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/crc32c": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", + "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", + "peer": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32c/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "peer": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", + "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", + "peer": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "peer": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "peer": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "peer": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.427.0.tgz", + "integrity": "sha512-YKjJ9zgn0oE393HURKgvjNoX6lxUjb+dkTBE1GymFnGCPl6VxQbKXajXWNqUyN+oPPlZ2osEiljPaN0RserUjA==", + "peer": true, + "dependencies": { + "@aws-crypto/sha1-browser": "3.0.0", + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.427.0", + "@aws-sdk/credential-provider-node": "3.427.0", + "@aws-sdk/middleware-bucket-endpoint": "3.425.0", + "@aws-sdk/middleware-expect-continue": "3.425.0", + "@aws-sdk/middleware-flexible-checksums": "3.425.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-location-constraint": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-sdk-s3": "3.427.0", + "@aws-sdk/middleware-signing": "3.425.0", + "@aws-sdk/middleware-ssec": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/region-config-resolver": "3.425.0", + "@aws-sdk/signature-v4-multi-region": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@aws-sdk/xml-builder": "3.310.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/eventstream-serde-browser": "^2.0.10", + "@smithy/eventstream-serde-config-resolver": "^2.0.10", + "@smithy/eventstream-serde-node": "^2.0.10", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-blob-browser": "^2.0.10", + "@smithy/hash-node": "^2.0.10", + "@smithy/hash-stream-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/md5-js": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-stream": "^2.0.14", + "@smithy/util-utf8": "^2.0.0", + "@smithy/util-waiter": "^2.0.10", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.427.0.tgz", + "integrity": "sha512-sFVFEmsQ1rmgYO1SgrOTxE/MTKpeE4hpOkm1WqhLQK7Ij136vXpjCxjH1JYZiHiUzO1wr9t4ex4dlB5J3VS/Xg==", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/region-config-resolver": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.427.0.tgz", + "integrity": "sha512-le2wLJKILyWuRfPz2HbyaNtu5kEki+ojUkTqCU6FPDRrqUvEkaaCBH9Awo/2AtrCfRkiobop8RuTTj6cAnpiJg==", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.427.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-sdk-sts": "3.425.0", + "@aws-sdk/middleware-signing": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/region-config-resolver": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.425.0.tgz", + "integrity": "sha512-J20etnLvMKXRVi5FK4F8yOCNm2RTaQn5psQTGdDEPWJNGxohcSpzzls8U2KcMyUJ+vItlrThr4qwgpHG3i/N0w==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.427.0.tgz", + "integrity": "sha512-NmH1cO/w98CKMltYec3IrJIIco19wRjATFNiw83c+FGXZ+InJwReqBnruxIOmKTx2KDzd6fwU1HOewS7UjaaaQ==", + "peer": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.425.0", + "@aws-sdk/credential-provider-process": "3.425.0", + "@aws-sdk/credential-provider-sso": "3.427.0", + "@aws-sdk/credential-provider-web-identity": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.427.0.tgz", + "integrity": "sha512-wYYbQ57nKL8OfgRbl8k6uXcdnYml+p3LSSfDUAuUEp1HKlQ8lOXFJ3BdLr5qrk7LhpyppSRnWBmh2c3kWa7ANQ==", + "peer": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.425.0", + "@aws-sdk/credential-provider-ini": "3.427.0", + "@aws-sdk/credential-provider-process": "3.425.0", + "@aws-sdk/credential-provider-sso": "3.427.0", + "@aws-sdk/credential-provider-web-identity": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.425.0.tgz", + "integrity": "sha512-YY6tkLdvtb1Fgofp3b1UWO+5vwS14LJ/smGmuGpSba0V7gFJRdcrJ9bcb9vVgAGuMdjzRJ+bUKlLLtqXkaykEw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.427.0.tgz", + "integrity": "sha512-c+tXyS/i49erHs4bAp6vKNYeYlyQ0VNMBgoco0LCn1rL0REtHbfhWMnqDLF6c2n3yIWDOTrQu0D73Idnpy16eA==", + "peer": true, + "dependencies": { + "@aws-sdk/client-sso": "3.427.0", + "@aws-sdk/token-providers": "3.427.0", + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.425.0.tgz", + "integrity": "sha512-/0R65TgRzL01JU3SzloivWNwdkbIhr06uY/F5pBHf/DynQqaspKNfdHn6AiozgSVDfwRHFjKBTUy6wvf3QFkuA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.427.0.tgz", + "integrity": "sha512-JE26Zo4SMMY2SGlD/FilF5MpLuP8D2IrW+ye/J77dwh91gyGnNa/lubJ7WbVjIAxgeaDHsAkcpNO4VR5k6JCKg==", + "dependencies": { + "@smithy/abort-controller": "^2.0.1", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/smithy-client": "^2.1.9", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.425.0.tgz", + "integrity": "sha512-7UTfA10fmDw9cgHLApxRUNPywZTG4S/1TNZgTxndO/1OM9ZHtIatw1iLbqJD35gHrpEYI8Vo14YvcnD2ITuiMw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.425.0.tgz", + "integrity": "sha512-CqAmnDST2o7+sKKw2/ffHKiYKE+jZb/Ce9U0P//ZYzqp9R1Wb016ID+W6DoxufyPJAS9dpRMcUDnAssmMIC/EA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.425.0.tgz", + "integrity": "sha512-BDwn2vVVsC/AzmHXQlaZhEpKXL7GfKFpH7ZFccZuwEQBcyn8lVCcwtfaRe5P1mEe2wklVzOXd1dw8bt0+BOUPA==", + "peer": true, + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@aws-crypto/crc32c": "3.0.0", + "@aws-sdk/types": "3.425.0", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.425.0.tgz", + "integrity": "sha512-E5Gt41LObQ+cr8QnLthwsH3MtVSNXy1AKJMowDr85h0vzqA/FHUkgHyOGntgozzjXT5M0MaSRYxS0xwTR5D4Ew==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.425.0.tgz", + "integrity": "sha512-3rt0LpGmL1LCRFuEObS1yERd9OEV+AEIAvhY7b53M7u7SyrjWQtpntWkI365L/QljhgMXQBfps2qO4JtrhQnsA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.425.0.tgz", + "integrity": "sha512-INE9XWRXx2f4a/r2vOU0tAmgctVp7nEaEasemNtVBYhqbKLZvr9ndLBSgKGgJ8LIcXAoISipaMuFiqIGkFsm7A==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.425.0.tgz", + "integrity": "sha512-77gnzJ5b91bgD75L/ugpOyerx6lR3oyS4080X1YI58EzdyBMkDrHM4FbMcY2RynETi3lwXCFzLRyZjWXY1mRlw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.427.0.tgz", + "integrity": "sha512-virGCf9vsqYCLpmngLOZOVSYgVr2cCOCvTuRoT9vf5tD/63JwaC173jnbdoJO6CWI7ID5Iz0eNdgITXVQ2mpew==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.425.0.tgz", + "integrity": "sha512-JFojrg76oKAoBknnr9EL5N2aJ1mRCtBqXoZYST58GSx8uYdFQ89qS65VNQ8JviBXzsrCNAn4vDhZ5Ch5E6TxGQ==", + "peer": true, + "dependencies": { + "@aws-sdk/middleware-signing": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.425.0.tgz", + "integrity": "sha512-ZpOfgJHk7ovQ0sSwg3tU4NxFOnz53lJlkJRf7S+wxQALHM0P2MJ6LYBrZaFMVsKiJxNIdZBXD6jclgHg72ZW6Q==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.425.0.tgz", + "integrity": "sha512-9HTuXnHYAZWkwPC8x9tElsQjFPxDT//orbIFauS7VF5HkLCKn9J6O6lW1wKMxrEnDwfN/Vi3nw479MoPj5Ss0Q==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.427.0.tgz", + "integrity": "sha512-y9HxYsNvnA3KqDl8w1jHeCwz4P9CuBEtu/G+KYffLeAMBsMZmh4SIkFFCO9wE/dyYg6+yo07rYcnnIfy7WA0bw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.425.0.tgz", + "integrity": "sha512-u7uv/iUOapIJdRgRkO3wnpYsUgV6ponsZJQgVg/8L+n+Vo5PQL5gAcIuAOwcYSKQPFaeK+KbmByI4SyOK203Vw==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.425.0.tgz", + "integrity": "sha512-7n2FRPE9rLaVa26xXQJ8TExrt53dWN824axQd1a0r5va0SmMQYG/iV5LBmwUlAntUSq46Lse4Q5YnbOVedGOmw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.427.0.tgz", + "integrity": "sha512-4E5E+4p8lJ69PBY400dJXF06LUHYx5lkKzBEsYqWWhoZcoftrvi24ltIhUDoGVLkrLcTHZIWSdFAWSos4hXqeg==", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.425.0.tgz", + "integrity": "sha512-6lqbmorwerN4v+J5dqbHPAsjynI0mkEF+blf+69QTaKKGaxBBVaXgqoqul9RXYcK5MMrrYRbQIMd0zYOoy90kA==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz", + "integrity": "sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.427.0.tgz", + "integrity": "sha512-rSyiAIFF/EVvity/+LWUqoTMJ0a25RAc9iqx0WZ4tf1UjuEXRRXxZEb+jEZg1bk+pY84gdLdx9z5E+MSJCZxNQ==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/node-config-provider": "^2.0.13", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.425.0.tgz", + "integrity": "sha512-22Y9iMtjGcFjGILR6/xdp1qRezlHVLyXtnpEsbuPTiernRCPk6zfAnK/ATH77r02MUjU057tdxVkd5umUBTn9Q==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.425.0.tgz", + "integrity": "sha512-SIR4F5uQeeVAi8lv4OgRirtdtNi5zeyogTuQgGi9su8F/WP1N6JqxofcwpUY5f8/oJ2UlXr/tx1f09UHfJJzvA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "peer": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz", + "integrity": "sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", @@ -1438,6 +2261,644 @@ "node": ">=14.0.0" } }, + "node_modules/@smithy/abort-controller": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.11.tgz", + "integrity": "sha512-MSzE1qR2JNyb7ot3blIOT3O3H0Jn06iNDEgHRaqZUwBgx5EG+VIx24Y21tlKofzYryIOcWpIohLrIIyocD6LMA==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz", + "integrity": "sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.0.tgz", + "integrity": "sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==", + "peer": true, + "dependencies": { + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.14.tgz", + "integrity": "sha512-K1K+FuWQoy8j/G7lAmK85o03O89s2Vvh6kMFmzEmiHUoQCRH1rzbDtMnGNiaMHeSeYJ6y79IyTusdRG+LuWwtg==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.1", + "@smithy/types": "^2.3.5", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.16.tgz", + "integrity": "sha512-tKa2xF+69TvGxJT+lnJpGrKxUuAZDLYXFhqnPEgnHz+psTpkpcB4QRjHj63+uj83KaeFJdTfW201eLZeRn6FfA==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.1", + "@smithy/property-provider": "^2.0.12", + "@smithy/types": "^2.3.5", + "@smithy/url-parser": "^2.0.11", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.11.tgz", + "integrity": "sha512-BQCTjxhCYRZIfXapa2LmZSaH8QUBGwMZw7XRN83hrdixbLjIcj+o549zjkedFS07Ve2TlvWUI6BTzP+nv7snBA==", + "peer": true, + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.5", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.11.tgz", + "integrity": "sha512-p9IK4uvwT6B3pT1VGlODvcVBfPVikjBFHAcKpvvNF+7lAEI+YiC6d0SROPkpjnvCgVBYyGXa3ciqrWnFze6mwQ==", + "peer": true, + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.11.tgz", + "integrity": "sha512-vN32E8yExo0Z8L7kXhlU9KRURrhqOpPdLxQMp3MwfMThrjiqbr1Sk5srUXc1ed2Ygl/l0TEN9vwNG0bQHg6AjQ==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.11.tgz", + "integrity": "sha512-Gjqbpg7UmD+YzkpgNShNcDNZcUpBWIkvX2XCGptz5PoxJU/UQbuF9eSc93ZlIb7j4aGjtFfqk23HUMW8Hopg2Q==", + "peer": true, + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.11.tgz", + "integrity": "sha512-F8FsxLTbFN4+Esgpo+nNKcEajrgRZJ+pG9c8+MhLM4Odp5ejLHw2GMCXd81cGsgmfcbnzdDEXazPPVzOwj89MQ==", + "peer": true, + "dependencies": { + "@smithy/eventstream-codec": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.2.tgz", + "integrity": "sha512-K7aRtRuaBjzlk+jWWeyfDTLAmRRvmA4fU8eHUXtjsuEDgi3f356ZE32VD2ssxIH13RCLVZbXMt5h7wHzYiSuVA==", + "dependencies": { + "@smithy/protocol-http": "^3.0.7", + "@smithy/querystring-builder": "^2.0.11", + "@smithy/types": "^2.3.5", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.11.tgz", + "integrity": "sha512-/6vq/NiH2EN3mWdwcLdjVohP+VCng+ZA1GnlUdx959egsfgIlLWQvCyjnB2ze9Hr6VHV5XEFLLpLQH2dHA6Sgw==", + "peer": true, + "dependencies": { + "@smithy/chunked-blob-reader": "^2.0.0", + "@smithy/chunked-blob-reader-native": "^2.0.0", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.11.tgz", + "integrity": "sha512-PbleVugN2tbhl1ZoNWVrZ1oTFFas/Hq+s6zGO8B9bv4w/StTriTKA9W+xZJACOj9X7zwfoTLbscM+avCB1KqOQ==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.0.11.tgz", + "integrity": "sha512-Jn2yl+Dn0kvwKvSavvR1/BFVYa2wIkaJKWeTH48kno89gqHAJxMh1hrtBN6SJ7F8VhodNZTiNOlQVqCSfLheNQ==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.11.tgz", + "integrity": "sha512-zazq99ujxYv/NOf9zh7xXbNgzoVLsqE0wle8P/1zU/XdhPi/0zohTPKWUzIxjGdqb5hkkwfBkNkl5H+LE0mvgw==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.0.11.tgz", + "integrity": "sha512-YBIv+e95qeGvQA05ucwstmTeQ/bUzWgU+nO2Ffmif5awu6IzSR0Jfk3XLYh4mdy7f8DCgsn8qA63u7N9Lu0+5A==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.13.tgz", + "integrity": "sha512-Md2kxWpaec3bXp1oERFPQPBhOXCkGSAF7uc1E+4rkwjgw3/tqAXRtbjbggu67HJdwaif76As8AV6XxbD1HzqTQ==", + "peer": true, + "dependencies": { + "@smithy/protocol-http": "^3.0.7", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.11.tgz", + "integrity": "sha512-mCugsvB15up6fqpzUEpMT4CuJmFkEI+KcozA7QMzYguXCaIilyMKsyxgamwmr+o7lo3QdjN0//XLQ9bWFL129g==", + "dependencies": { + "@smithy/middleware-serde": "^2.0.11", + "@smithy/types": "^2.3.5", + "@smithy/url-parser": "^2.0.11", + "@smithy/util-middleware": "^2.0.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.16.tgz", + "integrity": "sha512-Br5+0yoiMS0ugiOAfJxregzMMGIRCbX4PYo1kDHtLgvkA/d++aHbnHB819m5zOIAMPvPE7AThZgcsoK+WOsUTA==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.1", + "@smithy/protocol-http": "^3.0.7", + "@smithy/service-error-classification": "^2.0.4", + "@smithy/types": "^2.3.5", + "@smithy/util-middleware": "^2.0.4", + "@smithy/util-retry": "^2.0.4", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.11.tgz", + "integrity": "sha512-NuxnjMyf4zQqhwwdh0OTj5RqpnuT6HcH5Xg5GrPijPcKzc2REXVEVK4Yyk8ckj8ez1XSj/bCmJ+oNjmqB02GWA==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.5.tgz", + "integrity": "sha512-bVQU/rZzBY7CbSxIrDTGZYnBWKtIw+PL/cRc9B7etZk1IKSOe0NvKMJyWllfhfhrTeMF6eleCzOihIQympAvPw==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.1.tgz", + "integrity": "sha512-1lF6s1YWBi1LBu2O30tD3jyTgMtuvk/Z1twzXM4GPYe4dmZix4nNREPJIPOcfFikNU2o0eTYP80+izx5F2jIJA==", + "peer": true, + "dependencies": { + "@smithy/property-provider": "^2.0.12", + "@smithy/shared-ini-file-loader": "^2.2.0", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.7.tgz", + "integrity": "sha512-PQIKZXlp3awCDn/xNlCSTFE7aYG/5Tx33M05NfQmWYeB5yV1GZZOSz4dXpwiNJYTXb9jPqjl+ueXXkwtEluFFA==", + "dependencies": { + "@smithy/abort-controller": "^2.0.11", + "@smithy/protocol-http": "^3.0.7", + "@smithy/querystring-builder": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.12.tgz", + "integrity": "sha512-Un/OvvuQ1Kg8WYtoMCicfsFFuHb/TKL3pCA6ZIo/WvNTJTR94RtoRnL7mY4XkkUAoFMyf6KjcQJ76y1FX7S5rw==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.7.tgz", + "integrity": "sha512-HnZW8y+r66ntYueCDbLqKwWcMNWW8o3eVpSrHNluwtBJ/EUWfQHRKSiu6vZZtc6PGfPQWgVfucoCE/C3QufMAA==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.11.tgz", + "integrity": "sha512-b4kEbVMxpmfv2VWUITn2otckTi7GlMteZQxi+jlwedoATOGEyrCJPfRcYQJjbCi3fZ2QTfh3PcORvB27+j38Yg==", + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.11.tgz", + "integrity": "sha512-YXe7jhi7s3dQ0Fu9dLoY/gLu6NCyy8tBWJL/v2c9i7/RLpHgKT+uT96/OqZkHizCJ4kr0ZD46tzMjql/o60KLg==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.4.tgz", + "integrity": "sha512-77506l12I5gxTZqBkx3Wb0RqMG81bMYLaVQ+EqIWFwQDJRs5UFeXogKxSKojCmz1wLUziHZQXm03MBzPQiumQw==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.0.tgz", + "integrity": "sha512-xFXqs4vAb5BdkzHSRrTapFoaqS4/3m/CGZzdw46fBjYZ0paYuLAoMY60ICCn1FfGirG+PiJ3eWcqJNe4/SkfyA==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.11.tgz", + "integrity": "sha512-EFVU1dT+2s8xi227l1A9O27edT/GNKvyAK6lZnIZ0zhIHq/jSLznvkk15aonGAM1kmhmZBVGpI7Tt0odueZK9A==", + "peer": true, + "dependencies": { + "@smithy/eventstream-codec": "^2.0.11", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.5", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.4", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.10.tgz", + "integrity": "sha512-2OEmZDiW1Z196QHuQZ5M6cBE8FCSG0H2HADP1G+DY8P3agsvb0YJyfhyKuJbxIQy15tr3eDAK6FOrlbxgKOOew==", + "dependencies": { + "@smithy/middleware-stack": "^2.0.5", + "@smithy/types": "^2.3.5", + "@smithy/util-stream": "^2.0.15", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.5.tgz", + "integrity": "sha512-ehyDt8M9hehyxrLQGoA1BGPou8Js1Ocoh5M0ngDhJMqbFmNK5N6Xhr9/ZExWkyIW8XcGkiMPq3ZUEE0ScrhbuQ==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.11.tgz", + "integrity": "sha512-h89yXMCCF+S5k9XIoKltMIWTYj+FcEkU/IIFZ6RtE222fskOTL4Iak6ZRG+ehSvZDt8yKEcxqheTDq7JvvtK3g==", + "dependencies": { + "@smithy/querystring-parser": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.14.tgz", + "integrity": "sha512-NupG7SWUucm3vJrvlpt9jG1XeoPJphjcivgcUUXhDJbUPy4F04LhlTiAhWSzwlCNcF8OJsMvZ/DWbpYD3pselw==", + "peer": true, + "dependencies": { + "@smithy/property-provider": "^2.0.12", + "@smithy/smithy-client": "^2.1.10", + "@smithy/types": "^2.3.5", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.18.tgz", + "integrity": "sha512-+3jMom/b/Cdp21tDnY4vKu249Al+G/P0HbRbct7/aSZDlROzv1tksaYukon6UUv7uoHn+/McqnsvqZHLlqvQ0g==", + "peer": true, + "dependencies": { + "@smithy/config-resolver": "^2.0.14", + "@smithy/credential-provider-imds": "^2.0.16", + "@smithy/node-config-provider": "^2.1.1", + "@smithy/property-provider": "^2.0.12", + "@smithy/smithy-client": "^2.1.10", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.4.tgz", + "integrity": "sha512-Pbu6P4MBwRcjrLgdTR1O4Y3c0sTZn2JdOiJNcgL7EcIStcQodj+6ZTXtbyU/WTEU3MV2NMA10LxFc3AWHZ3+4A==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.4.tgz", + "integrity": "sha512-b+n1jBBKc77C1E/zfBe1Zo7S9OXGBiGn55N0apfhZHxPUP/fMH5AhFUUcWaJh7NAnah284M5lGkBKuhnr3yK5w==", + "peer": true, + "dependencies": { + "@smithy/service-error-classification": "^2.0.4", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.15.tgz", + "integrity": "sha512-A/hkYJPH2N5MCWYvky4tTpQihpYAEzqnUfxDyG3L/yMndy/2sLvxnyQal9Opuj1e9FiKSTeMyjnU9xxZGs0mRw==", + "dependencies": { + "@smithy/fetch-http-handler": "^2.2.2", + "@smithy/node-http-handler": "^2.1.7", + "@smithy/types": "^2.3.5", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.11.tgz", + "integrity": "sha512-8SJWUl9O1YhjC77EccgltI3q4XZQp3vp9DGEW6o0OdkUcwqm/H4qOLnMkA2n+NDojuM5Iia2jWoCdbluIiG7TA==", + "peer": true, + "dependencies": { + "@smithy/abort-controller": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "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", @@ -1709,6 +3170,11 @@ "node": ">= 8" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -1757,6 +3223,45 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1472.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1472.0.tgz", + "integrity": "sha512-U7kAHRbvTy753IXKV8Oom/AqlqnsbXG+Kw5gRbKi6VcsZ3hR/EpNMzdRXTWO5U415bnLWGo8WAqIz67PIaaKsw==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1790,6 +3295,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -1864,6 +3388,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "peer": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1917,6 +3447,32 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/byline": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", @@ -2090,6 +3646,47 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/concurrently": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.1.tgz", @@ -2504,6 +4101,14 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -2581,6 +4186,28 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "peer": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/figlet": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.6.0.tgz", @@ -2592,6 +4219,14 @@ "node": ">= 0.4.0" } }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2640,6 +4275,14 @@ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2826,6 +4469,17 @@ "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2878,6 +4532,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "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", @@ -2898,6 +4566,11 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -2950,6 +4623,11 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -2994,6 +4672,21 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3012,6 +4705,17 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", @@ -3041,6 +4745,20 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3062,11 +4780,30 @@ "node": ">=0.12.0" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "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/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/isomorphic-ws": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", @@ -3080,6 +4817,14 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/jose": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", @@ -3287,6 +5032,14 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", @@ -3339,6 +5092,51 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/multer-s3": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/multer-s3/-/multer-s3-3.0.1.tgz", + "integrity": "sha512-BFwSO80a5EW4GJRBdUuSHblz2jhVSAze33ZbnGpcfEicoT0iRolx4kWR+AJV07THFRCQ78g+kelKFdjkCCaXeQ==", + "dependencies": { + "@aws-sdk/lib-storage": "^3.46.0", + "file-type": "^3.3.0", + "html-comment-regex": "^1.1.2", + "run-parallel": "^1.1.6" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/multer/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -3726,6 +5524,11 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -3788,6 +5591,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -4068,6 +5899,28 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -4101,6 +5954,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -4363,6 +6221,15 @@ "node": ">= 0.8" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, "node_modules/stream-buffers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", @@ -4371,6 +6238,14 @@ "node": ">= 0.10.0" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4403,6 +6278,12 @@ "node": ">=8" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "peer": true + }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -4559,6 +6440,11 @@ "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-0.1.0.tgz", "integrity": "sha512-Tfay0l6gJMP5rkil8CzGbLthukn+9BN/VXWcABVFPjOoelJ+koW8BuPZYk+h/L+lEeIp1fSzVRiWRPIjKVjPdg==" }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -4611,6 +6497,20 @@ "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, "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", @@ -4620,6 +6520,18 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4735,6 +6647,24 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -4785,6 +6715,26 @@ } } }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", @@ -4794,6 +6744,14 @@ "node": ">=0.4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 1e9d5c0..4b12741 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,14 @@ }, "dependencies": { "@kubernetes/client-node": "^0.19.0", + "aws-sdk": "^2.1472.0", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", "figlet": "^1.6.0", "js-yaml": "^4.1.0", + "multer": "^1.4.5-lts.1", + "multer-s3": "^3.0.1", "rcon-client": "^4.2.3", "socket.io": "^4.7.2", "uuid": "^9.0.1" diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index aa688b3..a80092a 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -39,42 +39,6 @@ export default function MCLMenu() { - - - - - - - - {pages.map((page, index) => ( - - {page.icon} - - - ))} - - - {navHeader()} From 5a9212a8144523f721fb4676c0ffce369de960d9 Mon Sep 17 00:00:00 2001 From: dunemask Date: Mon, 9 Oct 2023 13:42:11 -0600 Subject: [PATCH 05/56] [FEATURE] Autocomplete & theming --- src/MCL.jsx | 10 +++-- src/{ => components}/overview/Overview.jsx | 0 .../overview/OverviewVisual.jsx | 0 src/{ => components}/servers/RconDialog.jsx | 0 src/{ => components}/servers/RconSocket.js | 0 src/{ => components}/servers/RconView.jsx | 0 src/{ => components}/servers/ServerCard.jsx | 0 {public => src}/css/overview.css | 0 {public => src}/css/rcon.css | 0 {public => src}/css/server-card.css | 0 src/nav/MCLMenu.jsx | 24 ++++++++++-- src/nav/Viewport.jsx | 2 + src/pages/Create.jsx | 19 +++++----- src/pages/CreateOptions.jsx | 38 ++++++++++++++----- src/pages/Home.jsx | 29 ++++++++++++-- src/util/queries.js | 8 ++-- src/util/theme.js | 16 ++++++++ vite.config.js | 3 +- 18 files changed, 114 insertions(+), 35 deletions(-) rename src/{ => components}/overview/Overview.jsx (100%) rename src/{ => components}/overview/OverviewVisual.jsx (100%) rename src/{ => components}/servers/RconDialog.jsx (100%) rename src/{ => components}/servers/RconSocket.js (100%) rename src/{ => components}/servers/RconView.jsx (100%) rename src/{ => components}/servers/ServerCard.jsx (100%) rename {public => src}/css/overview.css (100%) rename {public => src}/css/rcon.css (100%) rename {public => src}/css/server-card.css (100%) create mode 100644 src/util/theme.js diff --git a/src/MCL.jsx b/src/MCL.jsx index c24ec3e..e15b85e 100644 --- a/src/MCL.jsx +++ b/src/MCL.jsx @@ -1,4 +1,6 @@ // Imports +import { ThemeProvider } from "@mui/material/styles"; +import mclTheme from "./util/theme.js"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { SettingsProvider } from "@mcl/settings"; import Viewport from "./nav/Viewport.jsx"; @@ -11,9 +13,11 @@ export default function MCL() {
- - - + + + + +
diff --git a/src/overview/Overview.jsx b/src/components/overview/Overview.jsx similarity index 100% rename from src/overview/Overview.jsx rename to src/components/overview/Overview.jsx diff --git a/src/overview/OverviewVisual.jsx b/src/components/overview/OverviewVisual.jsx similarity index 100% rename from src/overview/OverviewVisual.jsx rename to src/components/overview/OverviewVisual.jsx diff --git a/src/servers/RconDialog.jsx b/src/components/servers/RconDialog.jsx similarity index 100% rename from src/servers/RconDialog.jsx rename to src/components/servers/RconDialog.jsx diff --git a/src/servers/RconSocket.js b/src/components/servers/RconSocket.js similarity index 100% rename from src/servers/RconSocket.js rename to src/components/servers/RconSocket.js diff --git a/src/servers/RconView.jsx b/src/components/servers/RconView.jsx similarity index 100% rename from src/servers/RconView.jsx rename to src/components/servers/RconView.jsx diff --git a/src/servers/ServerCard.jsx b/src/components/servers/ServerCard.jsx similarity index 100% rename from src/servers/ServerCard.jsx rename to src/components/servers/ServerCard.jsx diff --git a/public/css/overview.css b/src/css/overview.css similarity index 100% rename from public/css/overview.css rename to src/css/overview.css diff --git a/public/css/rcon.css b/src/css/rcon.css similarity index 100% rename from public/css/rcon.css rename to src/css/rcon.css diff --git a/public/css/server-card.css b/src/css/server-card.css similarity index 100% rename from public/css/server-card.css rename to src/css/server-card.css diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index a80092a..2c58fbf 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -13,7 +13,7 @@ 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 HomeIcon from "@mui/icons-material/Home"; import ListItemText from "@mui/material/ListItemText"; import List from "@mui/material/List"; import ListItemButton from "@mui/material/ListItemButton"; @@ -36,11 +36,27 @@ export default function MCLMenu() { theme.zIndex.modal + 2 - (isDrawer ? 1 : 0); return ( - + - - {navHeader()} + + + + + + {navHeader()}{" "} + diff --git a/src/nav/Viewport.jsx b/src/nav/Viewport.jsx index af78dff..a6b7622 100644 --- a/src/nav/Viewport.jsx +++ b/src/nav/Viewport.jsx @@ -1,6 +1,8 @@ import Box from "@mui/material/Box"; import Toolbar from "@mui/material/Toolbar"; import MCLPortal from "./MCLPortal.jsx"; +import Button from "@mui/material/Button"; +import SpeedDialIcon from "@mui/material/SpeedDialIcon"; // Import Navbar /*import Navbar from "./Navbar.jsx";*/ import MCLMenu from "./MCLMenu.jsx"; diff --git a/src/pages/Create.jsx b/src/pages/Create.jsx index 0338087..b42e3fe 100644 --- a/src/pages/Create.jsx +++ b/src/pages/Create.jsx @@ -1,13 +1,12 @@ import Box from "@mui/material/Box"; import CreateOptions from "./CreateOptions.jsx"; -export default function Create(){ - return ( - - {/**/} - {/**/} - - - ); - +export default function Create() { + return ( + + {/**/} + + + + + ); } - diff --git a/src/pages/CreateOptions.jsx b/src/pages/CreateOptions.jsx index ea66102..51b0705 100644 --- a/src/pages/CreateOptions.jsx +++ b/src/pages/CreateOptions.jsx @@ -1,4 +1,5 @@ import { useState, useEffect } from "react"; +import Autocomplete from "@mui/material/Autocomplete"; import TextField from "@mui/material/TextField"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; @@ -20,6 +21,8 @@ const defaultServer = { }; export default function Create() { + const [wl, setWl] = useState([]); + const [spec, setSpec] = useState(defaultServer); const versionList = useVersionList(); const [versions, setVersions] = useState(["latest"]); @@ -42,6 +45,9 @@ export default function Create() { const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); + const whitelistUpdate = (e) => alert("Whitelist not Implimented"); + const opUpdate = (e) => alert("Op not implimented"); + function upsertSpec() { if (validateSpec() !== "validated") return; createServer(spec); @@ -60,23 +66,31 @@ export default function Create() { } return ( - - - + + - + {versions.map((v, k) => ( @@ -109,9 +123,16 @@ export default function Create() { Hard - + } + /> - + {/**/} Spectator - + {/**/} - ); } diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index d94f78f..d076200 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,9 +1,14 @@ +import { Link } from "react-router-dom"; 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 ServerCard from "@mcl/components/servers/ServerCard.jsx"; +import RconDialog, { + useRconDialog, +} from "@mcl/components/servers/RconDialog.jsx"; +import Overview from "@mcl/components/overview/Overview.jsx"; +import Button from "@mui/material/Button"; +import SpeedDialIcon from "@mui/material/SpeedDialIcon"; import "@mcl/css/server-card.css"; import "@mcl/css/overview.css"; import { useServerInstances } from "@mcl/queries"; @@ -53,7 +58,23 @@ export default function Home() { dialogToggle={rconToggle} serverName={server} /> - + ); } diff --git a/src/util/queries.js b/src/util/queries.js index 9636fe4..6a45f07 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -14,13 +14,13 @@ const fetchApiPost = (subPath, json) => async () => export const useServerStatus = (server) => useQuery( [`server-status-${server}`], - fetchApiPost("/server/status", { name: server }) + fetchApiPost("/server/status", { name: server }), ); export const useServerMetrics = (server) => useQuery( [`server-metrics-${server}`], fetchApiPost("/server/metrics", { name: server }), - { refetchInterval: 10000 } + { refetchInterval: 10000 }, ); export const useStartServer = (server) => postJsonApi("/server/start", { name: server }, "server-instances"); @@ -41,8 +41,8 @@ export const useSystemAvailable = () => export const useVersionList = () => useQuery(["minecraft-versions"], () => fetch("https://piston-meta.mojang.com/mc/game/version_manifest.json").then( - (r) => r.json() - ) + (r) => r.json(), + ), ); const postJsonApi = (subPath, body, invalidate, method = "POST") => { diff --git a/src/util/theme.js b/src/util/theme.js new file mode 100644 index 0000000..26347a4 --- /dev/null +++ b/src/util/theme.js @@ -0,0 +1,16 @@ +// Generated using https://zenoo.github.io/mui-theme-creator/ +import { createTheme } from "@mui/material/styles"; + +const themeOptions = { + palette: { + mode: "light", + primary: { + main: "rgba(109,216,144,255)", + }, + secondary: { + main: "#f50057", + }, + }, +}; + +export default createTheme(themeOptions); diff --git a/vite.config.js b/vite.config.js index c71a2b2..a0f6847 100644 --- a/vite.config.js +++ b/vite.config.js @@ -26,10 +26,11 @@ export default () => { base: "/mcl/", resolve: { alias: { - "@mcl/css": path.resolve("./public/css"), + "@mcl/css": path.resolve("./src/css"), "@mcl/settings": path.resolve("./src/ctx/SettingsContext.jsx"), "@mcl/pages": path.resolve("./src/pages"), "@mcl/queries": path.resolve("./src/util/queries.js"), + "@mcl/components": path.resolve("./src/components"), "@mcl": path.resolve("./src"), }, }, From d47a8c3cc4de4eb1a039191d7e2fd429c249ea4f Mon Sep 17 00:00:00 2001 From: dunemask Date: Tue, 10 Oct 2023 17:51:03 -0600 Subject: [PATCH 06/56] [FEATURE] Fix Autocomplete --- src/pages/CreateOptions.jsx | 81 +++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/src/pages/CreateOptions.jsx b/src/pages/CreateOptions.jsx index 51b0705..bb36ef7 100644 --- a/src/pages/CreateOptions.jsx +++ b/src/pages/CreateOptions.jsx @@ -3,6 +3,7 @@ import Autocomplete from "@mui/material/Autocomplete"; import TextField from "@mui/material/TextField"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; +import Chip from "@mui/material/Chip"; import Select from "@mui/material/Select"; import MenuItem from "@mui/material/MenuItem"; import InputLabel from "@mui/material/InputLabel"; @@ -22,7 +23,7 @@ const defaultServer = { export default function Create() { const [wl, setWl] = useState([]); - + const [ops, setOps] = useState([]); const [spec, setSpec] = useState(defaultServer); const versionList = useVersionList(); const [versions, setVersions] = useState(["latest"]); @@ -31,6 +32,7 @@ export default function Create() { const s = { ...spec }; s[attr] = val; setSpec(s); + console.log(s); }; useEffect(() => { @@ -45,7 +47,46 @@ export default function Create() { const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); - const whitelistUpdate = (e) => alert("Whitelist not Implimented"); + function opsAdd(e) { + const opEntry = e.target.innerHTML ?? e.target.value; + if (!opEntry) return; + const newOps = [...ops, opEntry]; + setOps(newOps); + updateSpec("ops", newOps.join(",")); + } + + function whitelistAdd(e) { + const wlEntry = e.target.value; + if (!wlEntry) return; + const newWl = [...wl, wlEntry]; + setWl(newWl); + updateSpec("whitelist", newWl.join(",")); + } + + const opsRemove = + (name, { onDelete: updateAutoComplete }) => + (e) => { + updateAutoComplete(e); + const newOps = [...ops]; + const entryIndex = newOps.indexOf(name); + if (entryIndex === -1) return; + newOps.splice(entryIndex, 1); + setOps(newOps); + updateSpec("ops", newOps.join(",")); + }; + + const whitelistRemove = + (name, { onDelete: updateAutocomplete }) => + (e) => { + updateAutocomplete(e); + const newWl = [...wl]; + const entryIndex = newWl.indexOf(name); + if (entryIndex === -1) return; + newWl.splice(entryIndex, 1); + setWl(newWl); + updateSpec("whitelist", newWl.join(",")); + }; + const opUpdate = (e) => alert("Op not implimented"); function upsertSpec() { @@ -127,11 +168,43 @@ export default function Create() { multiple id="whitelist-autocomplete" options={[]} - onChange={whitelistUpdate} + onChange={whitelistAdd} freeSolo renderInput={(p) => } + renderTags={(value, getTagProps) => + value.map((option, index) => { + const defaultChipProps = getTagProps({ index }); + return ( + + ); + }) + } /> - + } + renderTags={(value, getTagProps) => + value.map((option, index) => { + const defaultChipProps = getTagProps({ index }); + return ( + + ); + }) + } + /> + {/**/} {/**/} Date: Fri, 8 Dec 2023 14:19:02 -0700 Subject: [PATCH 07/56] [FEATURE} Adjust error handling and bump versions --- dist/app.js | 8 +- lib/Minecluster.js | 5 +- .../migrations/1_create_servers_table.sql | 8 + lib/database/pg-query.js | 121 ++ lib/database/postgres.js | 63 + lib/k8s/live-logging.js | 2 +- lib/k8s/server-control.js | 36 +- lib/k8s/server-create.js | 53 +- lib/k8s/server-delete.js | 10 +- lib/routes/error-route.js | 17 + lib/routes/react-route.js | 2 +- lib/routes/system-route.js | 2 +- lib/server/rcon.js | 2 +- lib/server/router.js | 10 +- lib/storage/s3-integration.js | 1 - package-lock.json | 1096 +++++++++++------ package.json | 29 +- src/util/queries.js | 41 +- vite.config.js | 1 + 19 files changed, 1052 insertions(+), 455 deletions(-) create mode 100644 lib/database/migrations/1_create_servers_table.sql create mode 100644 lib/database/pg-query.js create mode 100644 lib/database/postgres.js create mode 100644 lib/routes/error-route.js diff --git a/dist/app.js b/dist/app.js index 74122c5..2f46e88 100644 --- a/dist/app.js +++ b/dist/app.js @@ -1,4 +1,3 @@ -import stream from "stream"; import k8s from "@kubernetes/client-node"; import Minecluster from "../lib/Minecluster.js"; const mcl = new Minecluster(); @@ -7,11 +6,6 @@ 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)}); diff --git a/lib/Minecluster.js b/lib/Minecluster.js index 0fa918b..983371e 100644 --- a/lib/Minecluster.js +++ b/lib/Minecluster.js @@ -7,6 +7,7 @@ import { INFO, OK, logInfo } from "./util/logging.js"; // Import Core Modules import buildRoutes from "./server/router.js"; import injectSockets from "./server/sockets.js"; +import pg from "./database/postgres.js"; // Constants const title = "MCL"; @@ -23,6 +24,7 @@ export default class Minecluster { logInfo(fig.textSync(title, "Larry 3D")); INFO("INIT", "Initializing..."); this.app = express(); + this.pg = pg; this.server = http.createServer(this.app); this.sockets = injectSockets(this.server, this.jobs); this.routes = buildRoutes(this.sockets); @@ -31,11 +33,12 @@ export default class Minecluster { } async _connect() { - // await this.pg.connect(); + await this.pg.connect(); } start() { const mcl = this; + return new Promise(async function init(res) { mcl._preinitialize(); await mcl._connect(); diff --git a/lib/database/migrations/1_create_servers_table.sql b/lib/database/migrations/1_create_servers_table.sql new file mode 100644 index 0000000..375eafd --- /dev/null +++ b/lib/database/migrations/1_create_servers_table.sql @@ -0,0 +1,8 @@ +/*CREATE SEQUENCE servers_id_seq; +CREATE TABLE servers ( + id bigint NOT NULL DEFAULT nextval('servers_id_seq') PRIMARY KEY, + name varchar(255) DEFAULT NULL, + host varchar(255) DEFAULT NULL, + CONSTRAINT unique_host UNIQUE(host) +); +ALTER SEQUENCE servers_id_seq OWNED BY servers.id;*/ \ No newline at end of file diff --git a/lib/database/pg-query.js b/lib/database/pg-query.js new file mode 100644 index 0000000..ce21af6 --- /dev/null +++ b/lib/database/pg-query.js @@ -0,0 +1,121 @@ +const buildPostgresEntry = (entry) => { + const pgEntry = { ...entry }; + Object.keys(pgEntry).forEach((col) => { + if (pgEntry[col] === undefined) delete pgEntry[col]; + }); + return pgEntry; +}; + +export const buildPostgresValue = (jsVar) => { + if (jsVar === null) return "null"; + if (typeof jsVar === "string") return buildPostgresString(jsVar); + if (Array.isArray(jsVar) && jsVar.length === 0) return "null"; + if (Array.isArray(jsVar) && isTypeArray(jsVar, "string")) + return buildPostgresStringArray(jsVar); + return jsVar; +}; + +const buildPostgresStringArray = (jsonArray) => { + if (jsonArray.length === 0) return null; + var pgArray = [...jsonArray]; + var arrayString = "ARRAY ["; + pgArray.forEach((e, i) => (pgArray[i] = `'${e}'`)); + arrayString += pgArray.join(","); + arrayString += "]"; + return arrayString; +}; + +const isTypeArray = (jsonArray, type) => + jsonArray.every((e) => typeof e === type); + +const buildPostgresString = (jsonString) => + (jsonString && `'${jsonString.replaceAll("'", "''")}'`) || null; + +export const insertQuery = (table, jsEntry) => { + if (typeof jsEntry !== "object") throw Error("PG Inserts must be objects!"); + const entry = buildPostgresEntry(jsEntry); + const cols = Object.keys(entry); + cols.forEach((col, i) => { + entry[col] = buildPostgresValue(entry[col]); + cols[i] = `"${col}"`; + }); + var query = `INSERT INTO ${table}(${cols.join(",")})\n`; + query += `VALUES(${Object.values(entry).join(",")})`; + return query; +}; + +export const deleteQuery = (table, jsEntry) => { + if (typeof jsEntry !== "object") + throw Error("PG Delete conditionals must be an object!"); + const entry = buildPostgresEntry(jsEntry); + const cols = Object.keys(entry); + const conditionals = []; + for (var col of cols) { + entry[col] = buildPostgresValue(entry[col]); + if (entry[col] === "null") conditionals.push(`x.${col} IS NULL`); + else conditionals.push(`x.${col}=${entry[col]}`); + } + return `DELETE FROM ${table} x WHERE ${conditionals.join(" AND ")}`; +}; +export const onConflictUpdate = (conflicts, updates) => { + if (!Array.isArray(conflicts)) throw Error("PG Conflicts must be an array!"); + if (typeof updates !== "object") throw Error("PG Updates must be objects!"); + const entry = buildPostgresEntry(updates); + var query = `ON CONFLICT (${conflicts.join(",")}) DO UPDATE SET\n`; + const cols = Object.keys(entry); + for (var col of cols) { + entry[col] = buildPostgresValue(entry[col]); + } + query += cols.map((c) => `${c}=${entry[c]}`).join(","); + return query; +}; +export const clearTableQuery = (table) => { + return `TRUNCATE ${table}`; +}; + +export const selectWhereQuery = (table, jsEntry, joinWith) => { + if (typeof jsEntry !== "object") throw Error("PG Where must be an object!"); + const where = buildPostgresEntry(jsEntry); + const cols = Object.keys(where); + var query = `SELECT * FROM ${table} AS x WHERE\n`; + for (var col of cols) { + where[col] = buildPostgresValue(where[col]); + } + return (query += cols.map((c) => `x.${c}=${where[c]}`).join(joinWith)); +}; +export const updateWhereQuery = (table, updates, wheres, joinWith) => { + if (typeof updates !== "object") throw Error("PG Updates must be an object!"); + if (typeof wheres !== "object") throw Error("PG Wheres must be an object!"); + const update = buildPostgresEntry(updates); + const where = buildPostgresEntry(wheres); + const updateCols = Object.keys(update); + const whereCols = Object.keys(where); + var query = `UPDATE ${table}\n`; + var updateQuery = updateCols + .map((c) => `${c} = ${buildPostgresValue(update[c])}`) + .join(","); + var whereQuery = whereCols + .map((c) => `${c} = ${buildPostgresValue(where[c])}`) + .join(joinWith); + return (query += `SET ${updateQuery} WHERE ${whereQuery}`); +}; +export const updateWhereAnyQuery = (table, updates, wheres) => + updateWhereQuery(table, updates, wheres, " OR "); +export const updateWhereAllQuery = (table, updates, wheres) => + updateWhereQuery(table, updates, wheres, " AND "); +export const selectWhereAnyQuery = (table, where) => + selectWhereQuery(table, where, " OR "); +export const selectWhereAllQuery = (table, where) => + selectWhereQuery(table, where, " AND "); + +export default { + selectWhereAnyQuery, + selectWhereAllQuery, + updateWhereAnyQuery, + updateWhereAllQuery, + insertQuery, + deleteQuery, + buildPostgresValue, + onConflictUpdate, + clearTableQuery, +}; diff --git a/lib/database/postgres.js b/lib/database/postgres.js new file mode 100644 index 0000000..eb2a037 --- /dev/null +++ b/lib/database/postgres.js @@ -0,0 +1,63 @@ +// Imports +import path from "node:path"; +import { URL } from "node:url"; +import { migrate } from "postgres-migrations"; +import createPgp from "pg-promise"; +import moment from "moment"; +import { INFO, WARN, OK, VERB } from "../util/logging.js"; + +// Environment Variables +const { + MCL_POSTGRES_DATABASE: database, + MCL_POSTGRES_ENABLED: pgEnabled, + MCL_POSTGRES_HOST: host, + MCL_POSTGRES_PASSWORD: password, + MCL_POSTGRES_PORT: port, + MCL_POSTGRES_USER: user, +} = process.env; + +// Postgres-promise Configuration +// Ensure dates get saved as UTC date strings +// This prevents the parser from doing strange datetime operations +const pgp = createPgp(); +pgp.pg.types.setTypeParser(1114, (str) => moment.utc(str).format()); + +// Database Config +const dbConfig = { + database: database ?? "minecluster", + user: user ?? "postgres", + password: password ?? "postgres", + host: host ?? "localhost", + port: port ?? 5432, + ensureDatabaseExists: true, +}; + +const databaseDir = new URL(".", import.meta.url).pathname; +const migrationsDir = path.resolve(databaseDir, "migrations/"); + +const queryMock = (str) => INFO("POSTGRES MOCK", str); + +const connect = (pg) => async () => { + if (pgEnabled === "false") { + WARN("POSTGRES", "Postgres Disabled!"); + return { query: queryMock }; + } + VERB("POSTGRES", "Migrating..."); + await migrate(dbConfig, migrationsDir); + // Override fake methods + const pgInstance = pgp(dbConfig); + for (var k in pgInstance) pg[k] = pgInstance[k]; + VERB("POSTGRES", "Migrated Successfully!"); + await pg.connect(); + VERB("POSTGRES", "Postgres connected Successfully!"); + + OK("POSTGRES", `Connected to database ${dbConfig.database}!`); +}; + +const buildPostgres = () => { + var pg = { query: queryMock }; + pg.connect = connect(pg); + return pg; +}; + +export default buildPostgres(); diff --git a/lib/k8s/live-logging.js b/lib/k8s/live-logging.js index c65b34b..93cc273 100644 --- a/lib/k8s/live-logging.js +++ b/lib/k8s/live-logging.js @@ -18,7 +18,7 @@ export default async function liveLogging(socket, serverNamespace) { const log = new k8s.Log(kc); const logStream = new stream.PassThrough(); logStream.on("data", (chunk) => - socket.emit("push", Buffer.from(chunk).toString()) + socket.emit("push", Buffer.from(chunk).toString()), ); log .log(serverNamespace, mcsPods[0], containerName, logStream, { diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js index 4bda593..351c806 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -8,21 +8,35 @@ const k8sCore = kc.makeApiClient(k8s.CoreV1Api); const k8sMetrics = new k8s.Metrics(kc); const namespace = process.env.MCL_SERVER_NAMESPACE; +async function findDeployment(serverName) { + try { + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + return deploymentRes.body.items.find( + (i) => i.metadata.name === `mcl-${serverName}`, + ); + } catch (e) { + ERR("SERVER CONTROL", `Error finding deployment: mcl-${serverName}`); + } +} + 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!"); + const dep = await findDeployment(name); + + if (!dep || !dep.spec) 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); + k8sDeps + .replaceNamespacedDeployment(`mcl-${name}`, namespace, dep) + .then(() => res.sendStatus(200)) + .catch((e) => { + ERR("SERVER CONTROL", e); + res.status(500).send("Error updating server!"); + }); } export async function stopServer(req, res) { @@ -32,7 +46,7 @@ export async function stopServer(req, res) { const { name } = serverSpec; const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); const dep = deploymentRes.body.items.find( - (i) => i.metadata.name === `mcl-${name}` + (i) => i.metadata.name === `mcl-${name}`, ); if (!dep) return res.status(409).send("Server does not exist!"); if (dep.spec.replicas === 0) @@ -56,7 +70,7 @@ export async function getServers(req, res) { const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace); // TODO Add an annotation and manage using that const serverDeployments = deployments.filter((d) => - d.metadata.name.startsWith("mcl-") + d.metadata.name.startsWith("mcl-"), ); var name, metrics, started; const servers = serverDeployments.map((s) => { @@ -68,10 +82,10 @@ export async function getServers(req, res) { }); if (pod) { const podCpus = pod.containers.map( - ({ usage }) => parseInt(usage.cpu) / 1_000_000 + ({ usage }) => parseInt(usage.cpu) / 1_000_000, ); const podMems = pod.containers.map( - ({ usage }) => parseInt(usage.memory) / 1024 + ({ usage }) => parseInt(usage.memory) / 1024, ); metrics = { cpu: Math.ceil(podCpus.reduce((a, b) => a + b)), diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 0cf0e2e..bda98b4 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -30,7 +30,7 @@ function payloadFilter(req, res) { function createRconSecret(serverSpec) { const { name } = serverSpec; const rconYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/rcon-secret.yml"), "utf8") + fs.readFileSync(path.resolve("lib/k8s/configs/rcon-secret.yml"), "utf8"), ); // TODO: Dyamic rconPassword @@ -45,7 +45,7 @@ function createRconSecret(serverSpec) { function createServerVolume(serverSpec) { const { name } = serverSpec; const volumeYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/server-pvc.yml"), "utf8") + fs.readFileSync(path.resolve("lib/k8s/configs/server-pvc.yml"), "utf8"), ); volumeYaml.metadata.labels.service = `mcl-${name}-server`; volumeYaml.metadata.name = `mcl-${name}-volume`; @@ -72,8 +72,8 @@ function createServerDeploy(serverSpec) { const deployYaml = yaml.load( fs.readFileSync( path.resolve("lib/k8s/configs/server-deployment.yml"), - "utf8" - ) + "utf8", + ), ); deployYaml.metadata.name = `mcl-${name}`; deployYaml.metadata.namespace = namespace; @@ -83,30 +83,25 @@ function createServerDeploy(serverSpec) { deployYaml.spec.template.spec.containers.splice(0, 1); //TODO: Currently removing backup container const serverContainer = deployYaml.spec.template.spec.containers[0]; + const findEnv = (k) => serverContainer.env.find(({ name: n }) => n === k); + const updateEnv = (k, v) => (findEnv.value = v); // 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; + updateEnv("TYPE", serverType); + updateEnv("VERSION", version); + updateEnv("DIFFICULTY", difficulty); + updateEnv("MODE", gamemode); + updateEnv("MOTD", motd); + updateEnv("MAX_PLAYERS", maxPlayers); + updateEnv("SEED", seed); + updateEnv("OPS", ops); + updateEnv("WHITELIST", whitelist); + updateEnv("MEMORY", `${memory}M`); + + if (version !== "VANILLA") delete findEnv("MODPACK").value; + else updateEnv("MODPACK", modpack); + findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = + `mcl-${name}-rcon-secret`; - serverContainer.env.find( - ({ name }) => name === "RCON_PASSWORD" - ).valueFrom.secretKeyRef.name = `mcl-${name}-rcon-secret`; // Server Container Name serverContainer.name = `mcl-${name}`; // Resources @@ -114,7 +109,7 @@ function createServerDeploy(serverSpec) { // serverContainer.resources.limits.memory = `${memory}Mi`; // TODO Allow for limits beyond initial startup // Volumes deployYaml.spec.template.spec.volumes.find( - ({ name }) => name === "datadir" + ({ name }) => name === "datadir", ).persistentVolumeClaim.claimName = `mcl-${name}-volume`; deployYaml.spec.template.spec.containers[0] = serverContainer; return deployYaml; @@ -123,7 +118,7 @@ function createServerDeploy(serverSpec) { function createServerService(serverSpec) { const { name, url } = serverSpec; const serviceYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/server-svc.yml"), "utf8") + 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`; @@ -136,7 +131,7 @@ function createServerService(serverSpec) { function createRconService(serverSpec) { const { name, url } = serverSpec; const rconSvcYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/rcon-svc.yml"), "utf8") + fs.readFileSync(path.resolve("lib/k8s/configs/rcon-svc.yml"), "utf8"), ); rconSvcYaml.metadata.labels.app = `mcl-${name}-app`; rconSvcYaml.metadata.name = `mcl-${name}-rcon`; diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js index 76b540c..89733b8 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -25,24 +25,24 @@ export default async function deleteServer(req, res) { // Delete in reverse order const deleteDeploy = k8sDeps.deleteNamespacedDeployment( `mcl-${serverSpec.name}`, - namespace + namespace, ); const deleteService = k8sCore.deleteNamespacedService( `mcl-${name}-server`, - namespace + namespace, ); const deleteRconService = k8sCore.deleteNamespacedService( `mcl-${name}-rcon`, - namespace + namespace, ); await deleteDeploy.catch(deleteError(res)); const deleteRconSecret = k8sCore.deleteNamespacedSecret( `mcl-${name}-rcon-secret`, - namespace + namespace, ); const deleteVolume = k8sCore.deleteNamespacedPersistentVolumeClaim( `mcl-${name}-volume`, - namespace + namespace, ); Promise.all([ deleteService, diff --git a/lib/routes/error-route.js b/lib/routes/error-route.js new file mode 100644 index 0000000..7b4e2ce --- /dev/null +++ b/lib/routes/error-route.js @@ -0,0 +1,17 @@ +export function logErrors(err, req, res, next) { + console.error(err.stack); + next(err); +} + +export function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: "Something failed!" }); + } else { + next(err); + } +} + +export function errorHandler(err, req, res, next) { + res.status(500); + res.render("error", { error: err }); +} diff --git a/lib/routes/react-route.js b/lib/routes/react-route.js index 9438566..e581fe3 100644 --- a/lib/routes/react-route.js +++ b/lib/routes/react-route.js @@ -3,6 +3,6 @@ import path from "path"; const router = Router(); router.use("/", express.static(path.resolve("./build"))); router.get("/*", (req, res) => - res.sendFile(path.resolve("./build/index.html")) + res.sendFile(path.resolve("./build/index.html")), ); export default router; diff --git a/lib/routes/system-route.js b/lib/routes/system-route.js index 5c5ec40..66e1022 100644 --- a/lib/routes/system-route.js +++ b/lib/routes/system-route.js @@ -7,7 +7,7 @@ kc.loadFromDefault(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); // Get Routes router.get("/available", (req, res) => { - return res.json({cpu: 8000, memory: 16000}); + return res.json({ cpu: 8000, memory: 16000 }); // TODO Workaround to detect available k8sApi.listNode().then((nodeRes) => { const nodeAllocatable = nodeRes.body.items.map((i) => i.status.allocatable); diff --git a/lib/server/rcon.js b/lib/server/rcon.js index d2535b1..81cf46a 100644 --- a/lib/server/rcon.js +++ b/lib/server/rcon.js @@ -13,7 +13,7 @@ export default async function rconInterface(socket) { const rconRes = await k8sCore.readNamespacedSecret(rconSecret, namespace); const rconPassword = Buffer.from( rconRes.body.data["rcon-password"], - "base64" + "base64", ).toString("utf8"); const rconHost = `mcl-${socket.mcs.serverName}-rcon`; const rcon = new RconClient({ diff --git a/lib/server/router.js b/lib/server/router.js index 58326bc..fdf381a 100644 --- a/lib/server/router.js +++ b/lib/server/router.js @@ -6,6 +6,11 @@ import vitals from "../routes/vitals-route.js"; import systemRoute from "../routes/system-route.js"; import serverRoute from "../routes/server-route.js"; import reactRoute from "../routes/react-route.js"; +import { + logErrors, + clientErrorHandler, + errorHandler, +} from "../routes/error-route.js"; export default function buildRoutes(pg, skio) { const router = express.Router(); @@ -18,7 +23,10 @@ export default function buildRoutes(pg, skio) { // Routes router.use("/api/system", systemRoute); router.use("/api/server", serverRoute); - router.use(["/mcl","/mcl/*"], reactRoute); // Static Build Route + router.use(["/mcl", "/mcl/*"], reactRoute); // Static Build Route + /*router.use(logErrors); + router.use(clientErrorHandler); + router.use(errorHandler);*/ return router; } diff --git a/lib/storage/s3-integration.js b/lib/storage/s3-integration.js index 2802214..34ed5d5 100644 --- a/lib/storage/s3-integration.js +++ b/lib/storage/s3-integration.js @@ -32,4 +32,3 @@ const storage = multerS3({ }); export const upload = multer({ storage }); - diff --git a/package-lock.json b/package-lock.json index 1c1570f..1b70a3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,34 +9,37 @@ "version": "0.0.1-alpha.0", "license": "LGPL-2.1", "dependencies": { - "@kubernetes/client-node": "^0.19.0", - "aws-sdk": "^2.1472.0", + "@kubernetes/client-node": "^0.20.0", + "aws-sdk": "^2.1514.0", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", - "figlet": "^1.6.0", + "figlet": "^1.7.0", "js-yaml": "^4.1.0", + "moment": "^2.29.4", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", - "rcon-client": "^4.2.3", + "pg-promise": "^11.5.4", + "postgres-migrations": "^5.3.0", + "rcon-client": "^4.2.4", "socket.io": "^4.7.2", "uuid": "^9.0.1" }, "devDependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.12", - "@mui/material": "^5.14.12", - "@tanstack/react-query": "^4.36.1", - "@vitejs/plugin-react": "^4.1.0", - "concurrently": "^8.2.1", - "nodemon": "^3.0.1", - "prettier": "^3.0.3", + "@mui/icons-material": "^5.14.19", + "@mui/material": "^5.14.20", + "@tanstack/react-query": "^5.12.2", + "@vitejs/plugin-react": "^4.2.1", + "concurrently": "^8.2.2", + "nodemon": "^3.0.2", + "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0", + "react-router-dom": "^6.20.1", "socket.io-client": "^4.7.2", - "vite": "^4.4.11" + "vite": "^5.0.7" } }, "node_modules/@ampproject/remapping": { @@ -873,12 +876,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -936,30 +939,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", - "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", - "@babel/parser": "^7.23.0", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -981,12 +984,12 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.5", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -1058,9 +1061,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -1110,9 +1113,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1128,32 +1131,32 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -1215,9 +1218,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1227,9 +1230,9 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", - "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1242,9 +1245,9 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", - "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -1257,9 +1260,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", + "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1283,19 +1286,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1304,12 +1307,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, @@ -1464,9 +1467,9 @@ "dev": true }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz", + "integrity": "sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==", "cpu": [ "arm" ], @@ -1480,9 +1483,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz", + "integrity": "sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==", "cpu": [ "arm64" ], @@ -1496,9 +1499,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.8.tgz", + "integrity": "sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==", "cpu": [ "x64" ], @@ -1512,9 +1515,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz", + "integrity": "sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==", "cpu": [ "arm64" ], @@ -1528,9 +1531,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz", + "integrity": "sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==", "cpu": [ "x64" ], @@ -1544,9 +1547,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz", + "integrity": "sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==", "cpu": [ "arm64" ], @@ -1560,9 +1563,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz", + "integrity": "sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==", "cpu": [ "x64" ], @@ -1576,9 +1579,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz", + "integrity": "sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==", "cpu": [ "arm" ], @@ -1592,9 +1595,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz", + "integrity": "sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==", "cpu": [ "arm64" ], @@ -1608,9 +1611,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz", + "integrity": "sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==", "cpu": [ "ia32" ], @@ -1624,9 +1627,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz", + "integrity": "sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==", "cpu": [ "loong64" ], @@ -1640,9 +1643,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz", + "integrity": "sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==", "cpu": [ "mips64el" ], @@ -1656,9 +1659,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz", + "integrity": "sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==", "cpu": [ "ppc64" ], @@ -1672,9 +1675,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz", + "integrity": "sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==", "cpu": [ "riscv64" ], @@ -1688,9 +1691,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz", + "integrity": "sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==", "cpu": [ "s390x" ], @@ -1704,9 +1707,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz", + "integrity": "sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==", "cpu": [ "x64" ], @@ -1720,9 +1723,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz", + "integrity": "sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==", "cpu": [ "x64" ], @@ -1736,9 +1739,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz", + "integrity": "sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==", "cpu": [ "x64" ], @@ -1752,9 +1755,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz", + "integrity": "sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==", "cpu": [ "x64" ], @@ -1768,9 +1771,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz", + "integrity": "sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==", "cpu": [ "arm64" ], @@ -1784,9 +1787,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz", + "integrity": "sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==", "cpu": [ "ia32" ], @@ -1800,9 +1803,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz", + "integrity": "sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==", "cpu": [ "x64" ], @@ -1816,9 +1819,9 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", - "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz", + "integrity": "sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==", "dev": true, "dependencies": { "@floating-ui/utils": "^0.1.3" @@ -1835,9 +1838,9 @@ } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.2.tgz", - "integrity": "sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", + "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", "dev": true, "dependencies": { "@floating-ui/dom": "^1.5.1" @@ -1892,9 +1895,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1902,9 +1905,9 @@ } }, "node_modules/@kubernetes/client-node": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.19.0.tgz", - "integrity": "sha512-WTOjGuFQ8yeW3+qD6JrAYhpwpoQbe9R8cA/61WCyFrNawSTUgLstHu7EsZRYEs39er3jDn3wCEaczz+VOFlc2Q==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.20.0.tgz", + "integrity": "sha512-xxlv5GLX4FVR/dDKEsmi4SPeuB49aRc35stndyxcC73XnUEEwF39vXbROpHOirmDse8WE9vxOjABnSVS+jb7EA==", "dependencies": { "@types/js-yaml": "^4.0.1", "@types/node": "^20.1.1", @@ -1989,15 +1992,15 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.18", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.18.tgz", - "integrity": "sha512-e9ZCy/ndhyt5MTshAS3qAUy/40UiO0jX+kAo6a+XirrPJE+rrQW+mKPSI0uyp+5z4Vh+z0pvNoJ2S2gSrNz3BQ==", + "version": "5.0.0-beta.26", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", + "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1", - "@floating-ui/react-dom": "^2.0.2", - "@mui/types": "^7.2.5", - "@mui/utils": "^5.14.12", + "@babel/runtime": "^7.23.4", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", "@popperjs/core": "^2.11.8", "clsx": "^2.0.0", "prop-types": "^15.8.1" @@ -2007,7 +2010,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -2021,29 +2024,29 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.12.tgz", - "integrity": "sha512-WZhCkKqhrXaSVBzoC6LNcVkIawS000OOt7gmnp4g9HhyvN0PSclRXc/JrkC7EwfzUAZJh+hiK2LaVsbtOpNuOg==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", + "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==", "dev": true, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.12.tgz", - "integrity": "sha512-aFm6g/AIB3RQN9h/4MKoBoBybLZXeR3aDHWNx6KzemEpIlElUxv5uXRX5Qk1VC6v/YPkhbaPsiLLjsRSTiZF3w==", + "version": "5.14.19", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.19.tgz", + "integrity": "sha512-yjP8nluXxZGe3Y7pS+yxBV+hWZSsSBampCxkZwaw+1l+feL+rfP74vbEFbMrX/Kil9I/Y1tWfy5bs/eNvwNpWw==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1" + "@babel/runtime": "^7.23.4" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@mui/material": "^5.0.0", @@ -2057,18 +2060,18 @@ } }, "node_modules/@mui/material": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.12.tgz", - "integrity": "sha512-EelF2L46VcVqhg3KjzIGBBpOtcBgRh0MMy9Efuk6Do81QdcZsFC9RebCVAflo5jIdbHiBmxBs5/l5Q9NjONozg==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", + "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1", - "@mui/base": "5.0.0-beta.18", - "@mui/core-downloads-tracker": "^5.14.12", - "@mui/system": "^5.14.12", - "@mui/types": "^7.2.5", - "@mui/utils": "^5.14.12", - "@types/react-transition-group": "^4.4.6", + "@babel/runtime": "^7.23.4", + "@mui/base": "5.0.0-beta.26", + "@mui/core-downloads-tracker": "^5.14.20", + "@mui/system": "^5.14.20", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@types/react-transition-group": "^4.4.9", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", @@ -2080,7 +2083,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -2102,13 +2105,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.12.tgz", - "integrity": "sha512-TWwm+9+BgHFpoR3w04FG+IqID4ALa74A27RuKq2CEaWgxliBZB24EVeI6djfjFt5t4FYmIb8BMw2ZJEir7YjLQ==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", + "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1", - "@mui/utils": "^5.14.12", + "@babel/runtime": "^7.23.4", + "@mui/utils": "^5.14.20", "prop-types": "^15.8.1" }, "engines": { @@ -2116,7 +2119,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -2129,12 +2132,12 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.12.tgz", - "integrity": "sha512-bocxt1nDmXfB3gpLfCCmFCyJ7sVmscFs+PuheO210QagZwHVp47UIRT1AiswLDYSQo1ZqmVGn7KLEJEYK0d4Xw==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", + "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1", + "@babel/runtime": "^7.23.4", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -2144,7 +2147,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -2161,16 +2164,16 @@ } }, "node_modules/@mui/system": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.12.tgz", - "integrity": "sha512-6DXfjjLhW0/ia5qU3Crke7j+MnfDbMBOHlLIrqbrEqNs0AuSBv8pXniEGb+kqO0H804NJreRTEJRjCngwOX5CA==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", + "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1", - "@mui/private-theming": "^5.14.12", - "@mui/styled-engine": "^5.14.12", - "@mui/types": "^7.2.5", - "@mui/utils": "^5.14.12", + "@babel/runtime": "^7.23.4", + "@mui/private-theming": "^5.14.20", + "@mui/styled-engine": "^5.14.19", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -2180,7 +2183,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -2201,9 +2204,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.5.tgz", - "integrity": "sha512-S2BwfNczr7VwS6ki8GoAXJyARoeSJDLuxOEPs3vEMyTALlf9PrdHv+sluX7kk3iKrCg/ML2mIWwapZvWbkMCQA==", + "version": "7.2.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", + "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", "dev": true, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" @@ -2215,13 +2218,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.12", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.12.tgz", - "integrity": "sha512-RFNXnhKQlzIkIUig6mmv0r5VbtjPdWoaBPYicq25LETdZux59HAqoRdWw15T7lp3c7gXOoE8y67+hTB8C64m2g==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", + "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.1", - "@types/prop-types": "^15.7.7", + "@babel/runtime": "^7.23.4", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -2230,7 +2233,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -2253,14 +2256,183 @@ } }, "node_modules/@remix-run/router": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.9.0.tgz", - "integrity": "sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz", + "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==", "dev": true, "engines": { "node": ">=14.0.0" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.7.0.tgz", + "integrity": "sha512-rGku10pL1StFlFvXX5pEv88KdGW6DHUghsxyP/aRYb9eH+74jTGJ3U0S/rtlsQ4yYq1Hcc7AMkoJOb1xu29Fxw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.7.0.tgz", + "integrity": "sha512-/EBw0cuJ/KVHiU2qyVYUhogXz7W2vXxBzeE9xtVIMC+RyitlY2vvaoysMUqASpkUtoNIHlnKTu/l7mXOPgnKOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.7.0.tgz", + "integrity": "sha512-4VXG1bgvClJdbEYYjQ85RkOtwN8sqI3uCxH0HC5w9fKdqzRzgG39K7GAehATGS8jghA7zNoS5CjSKkDEqWmNZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.7.0.tgz", + "integrity": "sha512-/ImhO+T/RWJ96hUbxiCn2yWI0/MeQZV/aeukQQfhxiSXuZJfyqtdHPUPrc84jxCfXTxbJLmg4q+GBETeb61aNw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.7.0.tgz", + "integrity": "sha512-zhye8POvTyUXlKbfPBVqoHy3t43gIgffY+7qBFqFxNqVtltQLtWeHNAbrMnXiLIfYmxcoL/feuLDote2tx+Qbg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.7.0.tgz", + "integrity": "sha512-RAdr3OJnUum6Vs83cQmKjxdTg31zJnLLTkjhcFt0auxM6jw00GD6IPFF42uasYPr/wGC6TRm7FsQiJyk0qIEfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.7.0.tgz", + "integrity": "sha512-nhWwYsiJwZGq7SyR3afS3EekEOsEAlrNMpPC4ZDKn5ooYSEjDLe9W/xGvoIV8/F/+HNIY6jY8lIdXjjxfxopXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.7.0.tgz", + "integrity": "sha512-rlfy5RnQG1aop1BL/gjdH42M2geMUyVQqd52GJVirqYc787A/XVvl3kQ5NG/43KXgOgE9HXgCaEH05kzQ+hLoA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.7.0.tgz", + "integrity": "sha512-cCkoGlGWfBobdDtiiypxf79q6k3/iRVGu1HVLbD92gWV5WZbmuWJCgRM4x2N6i7ljGn1cGytPn9ZAfS8UwF6vg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.7.0.tgz", + "integrity": "sha512-R2oBf2p/Arc1m+tWmiWbpHBjEcJnHVnv6bsypu4tcKdrYTpDfl1UT9qTyfkIL1iiii5D4WHxUHCg5X0pzqmxFg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.7.0.tgz", + "integrity": "sha512-CPtgaQL1aaPc80m8SCVEoxFGHxKYIt3zQYC3AccL/SqqiWXblo3pgToHuBwR8eCP2Toa+X1WmTR/QKFMykws7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.7.0.tgz", + "integrity": "sha512-pmioUlttNh9GXF5x2CzNa7Z8kmRTyhEzzAC+2WOOapjewMbl+3tGuAnxbwc5JyG8Jsz2+hf/QD/n5VjimOZ63g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.7.0.tgz", + "integrity": "sha512-SeZzC2QhhdBQUm3U0c8+c/P6UlRyBcLL2Xp5KX7z46WXZxzR8RJSIWL9wSUeBTgxog5LTPJuPj0WOT9lvrtP7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@smithy/abort-controller": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.11.tgz", @@ -2905,9 +3077,9 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@tanstack/query-core": { - "version": "4.36.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", - "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.12.1.tgz", + "integrity": "sha512-WbZztNmKq0t6QjdNmHzezbi/uifYo9j6e2GLJkodsYaYUlzMbAp91RDyeHkIZrm7EfO4wa6Sm5sxJZm5SPlh6w==", "dev": true, "funding": { "type": "github", @@ -2915,36 +3087,25 @@ } }, "node_modules/@tanstack/react-query": { - "version": "4.36.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.36.1.tgz", - "integrity": "sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==", + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.12.2.tgz", + "integrity": "sha512-BeWZu8zVFH20oRc+S/K9ADPgWjEzP/XQCGBNz5IbApUwPQAdwkQYbXODVL5AyAlWiSxhx+P2xlARPBApj2Yrog==", "dev": true, "dependencies": { - "@tanstack/query-core": "4.36.1", - "use-sync-external-store": "^1.2.0" + "@tanstack/query-core": "5.12.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } + "react": "^18.0.0" } }, "node_modules/@types/babel__core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", - "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -2955,18 +3116,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", - "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", - "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -2974,9 +3135,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", - "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -3017,9 +3178,9 @@ "dev": true }, "node_modules/@types/prop-types": { - "version": "15.7.8", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", - "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==", + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", "dev": true }, "node_modules/@types/react": { @@ -3034,9 +3195,9 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", - "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dev": true, "dependencies": { "@types/react": "*" @@ -3073,22 +3234,22 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", - "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", "dev": true, "dependencies": { - "@babel/core": "^7.22.20", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "@types/babel__core": "^7.20.2", + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0" + "vite": "^4.2.0 || ^5.0.0" } }, "node_modules/abbrev": { @@ -3210,6 +3371,14 @@ "safer-buffer": "~2.1.0" } }, + "node_modules/assert-options": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.1.tgz", + "integrity": "sha512-5lNGRB5g5i2bGIzb+J1QQE1iKU/WEMVBReFIc5pPDWjcPj23otPL0eI6PB2v7QPi0qU6Mhym5D3y0ZiSIOf3GA==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -3235,9 +3404,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1472.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1472.0.tgz", - "integrity": "sha512-U7kAHRbvTy753IXKV8Oom/AqlqnsbXG+Kw5gRbKi6VcsZ3hR/EpNMzdRXTWO5U415bnLWGo8WAqIz67PIaaKsw==", + "version": "2.1514.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1514.0.tgz", + "integrity": "sha512-ZQE5kHhJozwBB+Zaa21Gglm2pSQVU+8fFZNOn4pr+Kc1scYPlmVBPR3a0w19Vc4HNXPzjApAk2G4xMvzZDktAw==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -3416,9 +3585,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, "funding": [ { @@ -3435,9 +3604,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, "bin": { @@ -3462,6 +3631,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -3511,9 +3688,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001546", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", - "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", "dev": true, "funding": [ { @@ -3688,9 +3865,9 @@ } }, "node_modules/concurrently": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.1.tgz", - "integrity": "sha512-nVraf3aXOpIcNud5pB9M82p1tynmZkrSGQ1p6X/VY8cJ+2LMVqAgXsJxYYefACSHbTYlm92O1xuhdGTjwoEvbQ==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", "dev": true, "dependencies": { "chalk": "^4.1.2", @@ -3954,9 +4131,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.544", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.544.tgz", - "integrity": "sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==", + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==", "dev": true }, "node_modules/emoji-regex": { @@ -4031,9 +4208,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz", + "integrity": "sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==", "dev": true, "hasInstallScript": true, "bin": { @@ -4043,28 +4220,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/android-arm": "0.19.8", + "@esbuild/android-arm64": "0.19.8", + "@esbuild/android-x64": "0.19.8", + "@esbuild/darwin-arm64": "0.19.8", + "@esbuild/darwin-x64": "0.19.8", + "@esbuild/freebsd-arm64": "0.19.8", + "@esbuild/freebsd-x64": "0.19.8", + "@esbuild/linux-arm": "0.19.8", + "@esbuild/linux-arm64": "0.19.8", + "@esbuild/linux-ia32": "0.19.8", + "@esbuild/linux-loong64": "0.19.8", + "@esbuild/linux-mips64el": "0.19.8", + "@esbuild/linux-ppc64": "0.19.8", + "@esbuild/linux-riscv64": "0.19.8", + "@esbuild/linux-s390x": "0.19.8", + "@esbuild/linux-x64": "0.19.8", + "@esbuild/netbsd-x64": "0.19.8", + "@esbuild/openbsd-x64": "0.19.8", + "@esbuild/sunos-x64": "0.19.8", + "@esbuild/win32-arm64": "0.19.8", + "@esbuild/win32-ia32": "0.19.8", + "@esbuild/win32-x64": "0.19.8" } }, "node_modules/escalade": { @@ -4209,9 +4386,9 @@ } }, "node_modules/figlet": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.6.0.tgz", - "integrity": "sha512-31EQGhCEITv6+hi2ORRPyn3bulaV9Fl4xOdR169cBzH/n1UqcxsiSB/noo6SJdD7Kfb1Ljit+IgR1USvF/XbdA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.7.0.tgz", + "integrity": "sha512-gO8l3wvqo0V7wEFLXPbkX83b7MVjRrk1oRLfYlZXol8nEpb/ON9pcKLI4qpBv5YtOTfrINtqb7b40iYY2FTWFg==", "bin": { "figlet": "bin/index.js" }, @@ -4353,9 +4530,9 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -5087,6 +5264,14 @@ "node": ">=10" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5138,9 +5323,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -5188,19 +5373,19 @@ } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/nodemon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", - "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", "dev": true, "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", @@ -5221,15 +5406,6 @@ "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/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5392,6 +5568,11 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "optional": true }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5463,6 +5644,111 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-minify": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/pg-minify/-/pg-minify-1.6.3.tgz", + "integrity": "sha512-NoSsPqXxbkD8RIe+peQCqiea4QzXgosdTKY8p7PsbbGsh2F8TifDj/vJxfuR8qJwNYrijdSs7uf0tAe6WOyCsQ==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-promise": { + "version": "11.5.4", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.4.tgz", + "integrity": "sha512-esYSkDt2h6NQOkfotGAm1Ld5OjoITJLpB88Z1PIlcAU/RQ0XQE2PxW0bLJEOMHPGV5iaRnj1Y7ARznXbgN4FNw==", + "dependencies": { + "assert-options": "0.8.1", + "pg": "8.11.3", + "pg-minify": "1.6.3", + "spex": "3.3.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -5482,9 +5768,9 @@ } }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "dev": true, "funding": [ { @@ -5501,7 +5787,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -5509,10 +5795,60 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-migrations": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/postgres-migrations/-/postgres-migrations-5.3.0.tgz", + "integrity": "sha512-gnTHWJZVWbW8T3mXIxJm1JRU853TqBVWkhgfsTJr7zqT3VexjRmJj9kNi96rVhfTezDU4FVW6pf701kLOZiKIA==", + "dependencies": { + "pg": "^8.6.0", + "sql-template-strings": "^2.2.2" + }, + "bin": { + "pg-validate-migrations": "dist/bin/validate.js" + }, + "engines": { + "node": ">10.17.0" + } + }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -5642,9 +5978,9 @@ } }, "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==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/rcon-client/-/rcon-client-4.2.4.tgz", + "integrity": "sha512-sTHYLbcu2qrrOX4TOD3rvcLZNs7xiAhTsnZZIvxviSpa0yeV63sPAVI0PeScn5IvhKOCMURGt1NmnQ8h/GxjtA==", "dependencies": { "typed-emitter": "^0.1.0" } @@ -5690,12 +6026,12 @@ } }, "node_modules/react-router": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.16.0.tgz", - "integrity": "sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA==", + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.20.1.tgz", + "integrity": "sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==", "dev": true, "dependencies": { - "@remix-run/router": "1.9.0" + "@remix-run/router": "1.13.1" }, "engines": { "node": ">=14.0.0" @@ -5705,13 +6041,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.16.0.tgz", - "integrity": "sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg==", + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.20.1.tgz", + "integrity": "sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==", "dev": true, "dependencies": { - "@remix-run/router": "1.9.0", - "react-router": "6.16.0" + "@remix-run/router": "1.13.1", + "react-router": "6.20.1" }, "engines": { "node": ">=14.0.0" @@ -5884,18 +6220,31 @@ } }, "node_modules/rollup": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.7.0.tgz", + "integrity": "sha512-7Kw0dUP4BWH78zaZCqF1rPyQ8D5DSU6URG45v1dqS/faNsx9WXyess00uTOZxKr7oR/4TOjO1CPudT8L1UsEgw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.7.0", + "@rollup/rollup-android-arm64": "4.7.0", + "@rollup/rollup-darwin-arm64": "4.7.0", + "@rollup/rollup-darwin-x64": "4.7.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.7.0", + "@rollup/rollup-linux-arm64-gnu": "4.7.0", + "@rollup/rollup-linux-arm64-musl": "4.7.0", + "@rollup/rollup-linux-riscv64-gnu": "4.7.0", + "@rollup/rollup-linux-x64-gnu": "4.7.0", + "@rollup/rollup-linux-x64-musl": "4.7.0", + "@rollup/rollup-win32-arm64-msvc": "4.7.0", + "@rollup/rollup-win32-ia32-msvc": "4.7.0", + "@rollup/rollup-win32-x64-msvc": "4.7.0", "fsevents": "~2.3.2" } }, @@ -6189,6 +6538,30 @@ "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, + "node_modules/spex": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/spex/-/spex-3.3.0.tgz", + "integrity": "sha512-VNiXjFp6R4ldPbVRYbpxlD35yRHceecVXlct1J4/X80KuuPnW2AXMq3sGwhnJOhKkUsOxAT6nRGfGE5pocVw5w==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sql-template-strings": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sql-template-strings/-/sql-template-strings-2.2.2.tgz", + "integrity": "sha512-UXhXR2869FQaD+GMly8jAMCRZ94nU5KcrFetZfWEMd+LVVG6y0ExgHAhatEcKZ/wk8YcKPdi+hiD2wm75lq3/Q==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -6511,15 +6884,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" }, - "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", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "dev": true, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -6579,29 +6943,29 @@ } }, "node_modules/vite": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", - "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.7.tgz", + "integrity": "sha512-B4T4rJCDPihrQo2B+h1MbeGL/k/GMAHzhQ8S0LjQ142s6/+l3hHTT095ORvsshj4QCkoWu3Xtmob5mazvakaOw==", "dev": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", diff --git a/package.json b/package.json index 4b12741..e6b3936 100644 --- a/package.json +++ b/package.json @@ -24,30 +24,33 @@ "devDependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.12", - "@mui/material": "^5.14.12", - "@tanstack/react-query": "^4.36.1", - "@vitejs/plugin-react": "^4.1.0", - "concurrently": "^8.2.1", - "nodemon": "^3.0.1", - "prettier": "^3.0.3", + "@mui/icons-material": "^5.14.19", + "@mui/material": "^5.14.20", + "@tanstack/react-query": "^5.12.2", + "@vitejs/plugin-react": "^4.2.1", + "concurrently": "^8.2.2", + "nodemon": "^3.0.2", + "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0", + "react-router-dom": "^6.20.1", "socket.io-client": "^4.7.2", - "vite": "^4.4.11" + "vite": "^5.0.7" }, "dependencies": { - "@kubernetes/client-node": "^0.19.0", - "aws-sdk": "^2.1472.0", + "@kubernetes/client-node": "^0.20.0", + "aws-sdk": "^2.1514.0", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", - "figlet": "^1.6.0", + "figlet": "^1.7.0", "js-yaml": "^4.1.0", + "moment": "^2.29.4", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", - "rcon-client": "^4.2.3", + "pg-promise": "^11.5.4", + "postgres-migrations": "^5.3.0", + "rcon-client": "^4.2.4", "socket.io": "^4.7.2", "uuid": "^9.0.1" } diff --git a/src/util/queries.js b/src/util/queries.js index 6a45f07..4c0dc5a 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -12,16 +12,16 @@ const fetchApiPost = (subPath, json) => async () => }).then((res) => res.json()); export const useServerStatus = (server) => - useQuery( - [`server-status-${server}`], - fetchApiPost("/server/status", { name: server }), - ); + useQuery({ + queryKey: [`server-status-${server}`], + queryFn: fetchApiPost("/server/status", { name: server }), + }); export const useServerMetrics = (server) => - useQuery( - [`server-metrics-${server}`], - fetchApiPost("/server/metrics", { name: server }), - { refetchInterval: 10000 }, - ); + useQuery({ + queryKey: [`server-metrics-${server}`], + queryFn: fetchApiPost("/server/metrics", { name: server }), + refetchInterval: 10000, + }); export const useStartServer = (server) => postJsonApi("/server/start", { name: server }, "server-instances"); export const useStopServer = (server) => @@ -31,19 +31,26 @@ export const useDeleteServer = (server) => export const useCreateServer = (spec) => postJsonApi("/server/create", spec, "server-list"); export const useServerList = () => - useQuery(["server-list"], fetchApi("/server/list")); + useQuery({ queryKey: ["server-list"], queryFn: fetchApi("/server/list") }); export const useServerInstances = () => - useQuery(["server-instances"], fetchApi("/server/instances"), { + useQuery({ + queryKey: ["server-instances"], + queryFn: fetchApi("/server/instances"), refetchInterval: 5000, }); export const useSystemAvailable = () => - useQuery(["system-available"], fetchApi("/system/available")); + useQuery({ + queryKey: ["system-available"], + queryFn: fetchApi("/system/available"), + }); export const useVersionList = () => - useQuery(["minecraft-versions"], () => - fetch("https://piston-meta.mojang.com/mc/game/version_manifest.json").then( - (r) => r.json(), - ), - ); + useQuery({ + queryKey: ["minecraft-versions"], + queryFn: () => + 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(); diff --git a/vite.config.js b/vite.config.js index a0f6847..fc924d1 100644 --- a/vite.config.js +++ b/vite.config.js @@ -15,6 +15,7 @@ export default () => { proxy: { "/api": backendUrl, "/socket.io": backendUrl, + "/healthz": backendUrl, }, hmr: { protocol: process.env.MCL_VITE_DEV_PROTOCOL, From 61bf66c5c167a2ba4f8a033542cf058a316c25ec Mon Sep 17 00:00:00 2001 From: Dunemask Date: Fri, 15 Dec 2023 21:00:02 -0700 Subject: [PATCH 08/56] [FEATURE] Adjust resource flow --- lib/k8s/configs/rcon-secret.yml | 2 + lib/k8s/configs/rcon-svc.yml | 1 + lib/k8s/configs/server-deployment.yml | 2 + lib/k8s/configs/server-pvc.yml | 2 + lib/k8s/configs/server-svc.yml | 1 + lib/k8s/k8s-server-control.js | 105 ++++++++++++++++++++++++++ lib/k8s/server-control.js | 84 ++++++++++----------- lib/k8s/server-create.js | 34 ++++----- lib/k8s/server-delete.js | 50 +++++++----- lib/routes/server-route.js | 2 + src/pages/CreateOptions.jsx | 5 +- 11 files changed, 202 insertions(+), 86 deletions(-) create mode 100644 lib/k8s/k8s-server-control.js diff --git a/lib/k8s/configs/rcon-secret.yml b/lib/k8s/configs/rcon-secret.yml index 6b7bd80..ff52e1a 100644 --- a/lib/k8s/configs/rcon-secret.yml +++ b/lib/k8s/configs/rcon-secret.yml @@ -3,6 +3,8 @@ data: rcon-password: UEphT3V2aGJlQjNvc3M0dElwQU5YTUZrSkltR1RsRVl0ZGx3elFqZjJLdVZrZXNtV0hja1VhUUd3bmZDcElpbA== kind: Secret metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app-label name: changeme-rcon-secret diff --git a/lib/k8s/configs/rcon-svc.yml b/lib/k8s/configs/rcon-svc.yml index bcb34a7..9a68813 100644 --- a/lib/k8s/configs/rcon-svc.yml +++ b/lib/k8s/configs/rcon-svc.yml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app name: changeme-rcon diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml index bb6611a..fef67d8 100644 --- a/lib/k8s/configs/server-deployment.yml +++ b/lib/k8s/configs/server-deployment.yml @@ -1,6 +1,8 @@ apiVersion: apps/v1 kind: Deployment metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name name: changeme-name namespace: changeme-namespace spec: diff --git a/lib/k8s/configs/server-pvc.yml b/lib/k8s/configs/server-pvc.yml index caeaa2b..f502e8a 100644 --- a/lib/k8s/configs/server-pvc.yml +++ b/lib/k8s/configs/server-pvc.yml @@ -1,6 +1,8 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: service: changeme-service-name name: changeme-pvc-name diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml index c6678e6..a14e769 100644 --- a/lib/k8s/configs/server-svc.yml +++ b/lib/k8s/configs/server-svc.yml @@ -4,6 +4,7 @@ metadata: annotations: ingress.qumine.io/hostname: changeme-url ingress.qumine.io/portname: minecraft + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app name: changeme-name diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js new file mode 100644 index 0000000..77dae90 --- /dev/null +++ b/lib/k8s/k8s-server-control.js @@ -0,0 +1,105 @@ +import k8s from "@kubernetes/client-node"; +import { VERB } 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 mineclusterManaged = (o) => + o.metadata && + o.metadata.annotations && + o.metadata.annotations["minecluster.dunemask.net/server-name"] !== undefined; + +const serverMatch = (serverName) => (o) => + o.metadata.annotations["minecluster.dunemask.net/server-name"] === serverName; + +export async function getDeployments() { + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const serverDeployments = deploymentRes.body.items.filter(mineclusterManaged); + return serverDeployments; +} + +export async function getServices() { + const serviceRes = await k8sCore.listNamespacedService(namespace); + const serverServices = serviceRes.body.items.filter(mineclusterManaged); + return serverServices; +} + +export async function getSecrets() { + const secretRes = await k8sCore.listNamespacedSecret(namespace); + const serverSecrets = secretRes.body.items.filter(mineclusterManaged); + return serverSecrets; +} + +export async function getVolumes() { + const volumeRes = + await k8sCore.listNamespacedPersistentVolumeClaim(namespace); + const serverVolumes = volumeRes.body.items.filter(mineclusterManaged); + return serverVolumes; +} + +export function getServerAssets(serverName) { + const serverFilter = serverMatch(serverName); + return Promise.all([ + getDeployments(), + getServices(), + getSecrets(), + getVolumes(), + ]) + .then(([deps, svcs, scrts, vols]) => { + const deployments = deps.filter(serverFilter); + const services = svcs.filter(serverFilter); + const secrets = scrts.filter(serverFilter); + const volumes = vols.filter(serverFilter); + + if (deployments.length > 1) throw Error("Deployment filter broken!"); + if (volumes.length > 1) throw Error("Volume filter broken!"); + if (secrets.length > 1) throw Error("Secrets broken!"); + const serverAssets = { + deployment: deployments[0], + service: services.find( + (s) => s.metadata.name === `mcl-${serverName}-rcon`, + ), + volume: volumes[0], + rconService: services.find( + (s) => s.metadata.name === `mcl-${serverName}-server`, + ), + rconSecret: secrets[0], + }; + for (var k in serverAssets) if (serverAssets[k]) return serverAssets; + // If no assets exist, return nothing + }) + .catch((e) => console.log(e)); +} + +export async function getDeployment(serverName) { + const servers = await getDeployments(); + const serverDeployment = servers.find( + (s) => + s.metadata.annotations["minecluster.dunemask.net/server-name"] === + serverName, + ); + if (!serverDeployment) { + console.log(servers.map((s) => s.metadata.annotations)); + throw Error(`MCL Deployment '${serverName}' could not be found!`); + } + return serverDeployment; +} + +export async function scaleDeployment(serverName, scaleUp = false) { + const deployment = await getDeployment(serverName); + if (deployment.spec.replicas === 1 && scaleUp) + return VERB( + "KSC", + `MCL Deployment '${serverName}' is already scaled! Ignoring scale adjustment.`, + ); + deployment.spec.replicas = scaleUp ? 1 : 0; + return k8sDeps.replaceNamespacedDeployment( + deployment.metadata.name, + namespace, + deployment, + ); +} diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js index 351c806..8e14c64 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -1,22 +1,26 @@ import k8s from "@kubernetes/client-node"; +import { + getDeployment, + getDeployments, + getServerAssets, + scaleDeployment, +} from "./k8s-server-control.js"; 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; -async function findDeployment(serverName) { - try { - const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); - return deploymentRes.body.items.find( - (i) => i.metadata.name === `mcl-${serverName}`, - ); - } catch (e) { - ERR("SERVER CONTROL", `Error finding deployment: mcl-${serverName}`); - } +// Gets the all assets for the server +export async function getServer(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; + getServerAssets(name) + .then((server) => res.status(200).json(server)) + .catch((e) => res.status(500).send(e)); } export async function startServer(req, res) { @@ -24,19 +28,13 @@ export async function startServer(req, res) { if (!serverSpec) return res.sendStatus(400); if (!serverSpec.name) return res.status(400).send("Server name required!"); const { name } = serverSpec; - const dep = await findDeployment(name); - - if (!dep || !dep.spec) 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) - .then(() => res.sendStatus(200)) - .catch((e) => { - ERR("SERVER CONTROL", e); - res.status(500).send("Error updating server!"); - }); + try { + await scaleDeployment(name, true); + res.sendStatus(200); + } catch (e) { + ERR("SERVER CONTROL", e); + res.status(500).send(`Error updating server '${name}'!`); + } } export async function stopServer(req, res) { @@ -44,34 +42,28 @@ export async function stopServer(req, res) { 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); + try { + await scaleDeployment(name, false); + res.sendStatus(200); + } catch (e) { + ERR("SERVER CONTROL", e); + res.status(500).send(`Error updating server '${name}'!`); + } } -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 function serverList(req, res) { + getDeployments() + .then((sd) => res.json(sd.map((s) => s.metadata.name.substring(4)))) + .catch((e) => { + ERR("SERVER CONTROL", e); + res.status(500).send("Couldn't get server list"); + }); } export async function getServers(req, res) { - const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); - const deployments = deploymentRes.body.items; + const serverDeployments = await getDeployments(); 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); diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index bda98b4..23dfe85 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -10,6 +10,8 @@ const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const k8sCore = kc.makeApiClient(k8s.CoreV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; +const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); + function payloadFilter(req, res) { const serverSpec = req.body; if (!serverSpec) return res.sendStatus(400); @@ -29,9 +31,7 @@ function payloadFilter(req, res) { function createRconSecret(serverSpec) { const { name } = serverSpec; - const rconYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/rcon-secret.yml"), "utf8"), - ); + const rconYaml = loadYaml("lib/k8s/configs/rcon-secret.yml"); // TODO: Dyamic rconPassword const rconPassword = bcrypt.hashSync(uuidv4(), 10); @@ -39,17 +39,18 @@ function createRconSecret(serverSpec) { rconYaml.metadata.labels.app = `mcl-${name}-app`; rconYaml.metadata.name = `mcl-${name}-rcon-secret`; rconYaml.metadata.namespace = namespace; + rconYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = name; return rconYaml; } function createServerVolume(serverSpec) { const { name } = serverSpec; - const volumeYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/server-pvc.yml"), "utf8"), - ); + const volumeYaml = loadYaml("lib/k8s/configs/server-pvc.yml"); volumeYaml.metadata.labels.service = `mcl-${name}-server`; volumeYaml.metadata.name = `mcl-${name}-volume`; volumeYaml.metadata.namespace = namespace; + volumeYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; volumeYaml.spec.resources.requests.storage = "1Gi"; // TODO: Changeme return volumeYaml; } @@ -69,14 +70,11 @@ function createServerDeploy(serverSpec) { ops, whitelist, } = serverSpec; - const deployYaml = yaml.load( - fs.readFileSync( - path.resolve("lib/k8s/configs/server-deployment.yml"), - "utf8", - ), - ); + const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); deployYaml.metadata.name = `mcl-${name}`; deployYaml.metadata.namespace = namespace; + deployYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; 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`; @@ -117,25 +115,25 @@ function createServerDeploy(serverSpec) { function createServerService(serverSpec) { const { name, url } = serverSpec; - const serviceYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/server-svc.yml"), "utf8"), - ); + const serviceYaml = loadYaml("lib/k8s/configs/server-svc.yml"); 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.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; 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"), - ); + const rconSvcYaml = loadYaml("lib/k8s/configs/rcon-svc.yml"); rconSvcYaml.metadata.labels.app = `mcl-${name}-app`; rconSvcYaml.metadata.name = `mcl-${name}-rcon`; rconSvcYaml.metadata.namespace = namespace; + rconSvcYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; rconSvcYaml.spec.selector.app = `mcl-${name}-app`; return rconSvcYaml; } diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js index 89733b8..c53a95e 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -1,5 +1,6 @@ import k8s from "@kubernetes/client-node"; import { ERR } from "../util/logging.js"; +import { getServerAssets } from "./k8s-server-control.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -12,38 +13,47 @@ const deleteError = (res) => (err) => { ERR("K8S", "An error occurred while deleting a resource", err); }; +async function deleteOnExist(o, fn) { + if (!o) return; + return fn(o.metadata.name); +} + 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!"); + const server = await getServerAssets(name); + if (!server) return res.status(404).send("No Resources for that server were found!"); // Delete in reverse order - const deleteDeploy = k8sDeps.deleteNamespacedDeployment( - `mcl-${serverSpec.name}`, - namespace, + const deleteDeploy = deleteOnExist( + server.deployment, + (name)=> k8sDeps.deleteNamespacedDeployment(name, namespace), ); - const deleteService = k8sCore.deleteNamespacedService( - `mcl-${name}-server`, - namespace, + + const deleteService = deleteOnExist( + server.service, + (name) => k8sCore.deleteNamespacedService(name, namespace), ); - const deleteRconService = k8sCore.deleteNamespacedService( - `mcl-${name}-rcon`, - namespace, + const deleteRconService = deleteOnExist( + server.rconService, + (name) => k8sCore.deleteNamespacedService(name, namespace), ); - await deleteDeploy.catch(deleteError(res)); - const deleteRconSecret = k8sCore.deleteNamespacedSecret( - `mcl-${name}-rcon-secret`, - namespace, + try { + await deleteDeploy; + } catch (e) { + return deleteError(res)(e); + } + const deleteRconSecret = deleteOnExist( + server.rconSecret, + (name)=> k8sCore.deleteNamespacedSecret(name, namespace), ); - const deleteVolume = k8sCore.deleteNamespacedPersistentVolumeClaim( - `mcl-${name}-volume`, - namespace, + const deleteVolume = deleteOnExist( + server.volume, + (name)=>k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), ); + Promise.all([ deleteService, deleteRconService, diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js index 4c7eb35..8a39c0e 100644 --- a/lib/routes/server-route.js +++ b/lib/routes/server-route.js @@ -4,6 +4,7 @@ import { stopServer, serverList, getServers, + getServer, } from "../k8s/server-control.js"; import createServer from "../k8s/server-create.js"; import deleteServer from "../k8s/server-delete.js"; @@ -14,6 +15,7 @@ router.post("/create", createServer); router.delete("/delete", deleteServer); router.post("/start", startServer); router.post("/stop", stopServer); +// router.post("/get", getServer) // SHOULD BE DISABLED EXCEPT FOR DEBUGGING; router.get("/list", serverList); router.get("/instances", getServers); export default router; diff --git a/src/pages/CreateOptions.jsx b/src/pages/CreateOptions.jsx index bb36ef7..b5993cf 100644 --- a/src/pages/CreateOptions.jsx +++ b/src/pages/CreateOptions.jsx @@ -12,12 +12,11 @@ import { useCreateServer, useVersionList } from "@mcl/queries"; const defaultServer = { version: "latest", - name: "example", serverType: "VANILLA", difficulty: "easy", maxPlayers: "5", gamemode: "survival", - memory: "1024", + memory: "512", motd: `\\u00A7e\\u00A7ka\\u00A7l\\u00A7aMine\\u00A76Cluster\\u00A7r\\u00A78\\u00A7b\\u00A7ka`, }; @@ -115,7 +114,9 @@ export default function Create() { Date: Fri, 15 Dec 2023 21:07:04 -0700 Subject: [PATCH 09/56] [FEATURE] Adjust resource flow --- lib/k8s/server-delete.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js index c53a95e..db8612e 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -13,9 +13,8 @@ const deleteError = (res) => (err) => { ERR("K8S", "An error occurred while deleting a resource", err); }; -async function deleteOnExist(o, fn) { - if (!o) return; - return fn(o.metadata.name); +function deleteOnExist(o, fn) { + if (o) return fn(o.metadata.name); } export default async function deleteServer(req, res) { @@ -26,10 +25,11 @@ export default async function deleteServer(req, res) { // Ensure deployment exists const server = await getServerAssets(name); if (!server) return res.status(404).send("No Resources for that server were found!"); + // Delete in reverse order const deleteDeploy = deleteOnExist( server.deployment, - (name)=> k8sDeps.deleteNamespacedDeployment(name, namespace), + (name) => k8sDeps.deleteNamespacedDeployment(name, namespace), ); const deleteService = deleteOnExist( @@ -40,18 +40,15 @@ export default async function deleteServer(req, res) { server.rconService, (name) => k8sCore.deleteNamespacedService(name, namespace), ); - try { - await deleteDeploy; - } catch (e) { - return deleteError(res)(e); - } + if(deleteDeploy) await deleteDeploy.catch(deleteError(res)) + const deleteRconSecret = deleteOnExist( server.rconSecret, - (name)=> k8sCore.deleteNamespacedSecret(name, namespace), + (name) => k8sCore.deleteNamespacedSecret(name, namespace), ); const deleteVolume = deleteOnExist( server.volume, - (name)=>k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), + (name) => k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), ); Promise.all([ From 7348b073523623d6a9fe897a124fa490eabdb204 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Sat, 16 Dec 2023 09:28:06 -0700 Subject: [PATCH 10/56] [FEATURE] Initial FTP data --- lib/k8s/configs/containers/ftp-server.yml | 36 ++++ .../configs/containers/minecraft-backup.yml | 63 ++++++ .../configs/containers/minecraft-server.yml | 112 +++++++++++ lib/k8s/configs/server-deployment.yml | 183 +----------------- lib/k8s/configs/server-svc.yml | 6 +- lib/k8s/k8s-server-control.js | 4 +- lib/k8s/server-create.js | 44 ++++- lib/k8s/server-delete.js | 32 ++- lib/k8s/server-files.js | 35 ++++ lib/routes/files-route.js | 7 + lib/server/router.js | 2 + package-lock.json | 9 + package.json | 1 + 13 files changed, 330 insertions(+), 204 deletions(-) create mode 100644 lib/k8s/configs/containers/ftp-server.yml create mode 100644 lib/k8s/configs/containers/minecraft-backup.yml create mode 100644 lib/k8s/configs/containers/minecraft-server.yml create mode 100644 lib/k8s/server-files.js create mode 100644 lib/routes/files-route.js diff --git a/lib/k8s/configs/containers/ftp-server.yml b/lib/k8s/configs/containers/ftp-server.yml new file mode 100644 index 0000000..de6f49e --- /dev/null +++ b/lib/k8s/configs/containers/ftp-server.yml @@ -0,0 +1,36 @@ +env: + - name: FTP_USER + value: "minecluster" + - name: FTP_PASS + value: "minecluster" +image: garethflowers/ftp-server +imagePullPolicy: IfNotPresent +livenessProbe: +exec: + command: ["echo"] +failureThreshold: 20 +initialDelaySeconds: 30 +periodSeconds: 5 +successThreshold: 1 +timeoutSeconds: 1 +name: changeme-name-ftp +ports: [] # Programatically add all the ports for easier readability, Ports include: 20,21,40000-400009 +readinessProbe: + exec: + command: ["echo"] + 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: /home/minecluster + name: datadir diff --git a/lib/k8s/configs/containers/minecraft-backup.yml b/lib/k8s/configs/containers/minecraft-backup.yml new file mode 100644 index 0000000..074025a --- /dev/null +++ b/lib/k8s/configs/containers/minecraft-backup.yml @@ -0,0 +1,63 @@ +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 diff --git a/lib/k8s/configs/containers/minecraft-server.yml b/lib/k8s/configs/containers/minecraft-server.yml new file mode 100644 index 0000000..26b01d2 --- /dev/null +++ b/lib/k8s/configs/containers/minecraft-server.yml @@ -0,0 +1,112 @@ +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 diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml index fef67d8..1607944 100644 --- a/lib/k8s/configs/server-deployment.yml +++ b/lib/k8s/configs/server-deployment.yml @@ -19,188 +19,13 @@ spec: 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 + containers: [] dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler - securityContext: - fsGroup: 2000 - runAsUser: 1000 + # securityContext: + # fsGroup: 2000 + # runAsUser: 1000 terminationGracePeriodSeconds: 30 volumes: - name: datadir diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml index a14e769..c7e7fa2 100644 --- a/lib/k8s/configs/server-svc.yml +++ b/lib/k8s/configs/server-svc.yml @@ -14,11 +14,15 @@ spec: ipFamilies: - IPv4 ipFamilyPolicy: SingleStack - ports: + ports: # Programatically add all FTP ports. Port range includes 20, 21, 40000-40001 - name: minecraft port: 25565 protocol: TCP targetPort: minecraft + # - name: ftp-data + # port: 20 + # protocol: TCP + # targetPort: ftp-data selector: app: changeme-app sessionAffinity: None diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js index 77dae90..7d82bb0 100644 --- a/lib/k8s/k8s-server-control.js +++ b/lib/k8s/k8s-server-control.js @@ -61,11 +61,11 @@ export function getServerAssets(serverName) { const serverAssets = { deployment: deployments[0], service: services.find( - (s) => s.metadata.name === `mcl-${serverName}-rcon`, + (s) => s.metadata.name === `mcl-${serverName}-server`, ), volume: volumes[0], rconService: services.find( - (s) => s.metadata.name === `mcl-${serverName}-server`, + (s) => s.metadata.name === `mcl-${serverName}-rcon`, ), rconSecret: secrets[0], }; diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 23dfe85..dd7cbbc 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -55,6 +55,22 @@ function createServerVolume(serverSpec) { return volumeYaml; } +function getFtpContainer() { + const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); + const ftpPortList = [ + { p: 20, n: "ftp-data" }, + { p: 21, n: "ftp-commands" }, + ]; + for (var p = 40000; p <= 40009; p++) + ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); + ftpContainer.ports = ftpPortList.map(({ p: containerPort, n: name }) => ({ + containerPort, + name, + protocol: "TCP", + })); + return ftpContainer; +} + function createServerDeploy(serverSpec) { const { name, @@ -71,16 +87,21 @@ function createServerDeploy(serverSpec) { whitelist, } = serverSpec; const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); + const serverContainer = loadYaml( + "lib/k8s/configs/containers/minecraft-server.yml", + ); + const backupContainer = loadYaml( + "lib/k8s/configs/containers/minecraft-backup.yml", + ); + const ftpContainer = getFtpContainer(); deployYaml.metadata.name = `mcl-${name}`; + deployYaml.metadata.namespace = namespace; deployYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = name; 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]; - const findEnv = (k) => serverContainer.env.find(({ name: n }) => n === k); const updateEnv = (k, v) => (findEnv.value = v); // Enviornment variables @@ -109,7 +130,8 @@ function createServerDeploy(serverSpec) { deployYaml.spec.template.spec.volumes.find( ({ name }) => name === "datadir", ).persistentVolumeClaim.claimName = `mcl-${name}-volume`; - deployYaml.spec.template.spec.containers[0] = serverContainer; + deployYaml.spec.template.spec.containers.push(serverContainer); + deployYaml.spec.template.spec.containers.push(ftpContainer); return deployYaml; } @@ -123,6 +145,20 @@ function createServerService(serverSpec) { serviceYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = name; serviceYaml.spec.selector.app = `mcl-${name}-app`; + + // Apply FTP Port List + const ftpPortList = [ + { p: 20, n: "ftp-data" }, + { p: 21, n: "ftp-commands" }, + ]; + for (var p = 40000; p <= 40009; p++) + ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); + serviceYaml.spec.ports = ftpPortList.map(({ p: port, n: name }) => ({ + port, + name, + protocol: "TCP", + targetPort: port, + })); return serviceYaml; } diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js index db8612e..e620f4b 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -24,31 +24,27 @@ export default async function deleteServer(req, res) { const { name } = serverSpec; // Ensure deployment exists const server = await getServerAssets(name); - if (!server) return res.status(404).send("No Resources for that server were found!"); - + if (!server) + return res.status(404).send("No Resources for that server were found!"); + // Delete in reverse order - const deleteDeploy = deleteOnExist( - server.deployment, - (name) => k8sDeps.deleteNamespacedDeployment(name, namespace), + const deleteDeploy = deleteOnExist(server.deployment, (name) => + k8sDeps.deleteNamespacedDeployment(name, namespace), ); - const deleteService = deleteOnExist( - server.service, - (name) => k8sCore.deleteNamespacedService(name, namespace), + const deleteService = deleteOnExist(server.service, (name) => + k8sCore.deleteNamespacedService(name, namespace), ); - const deleteRconService = deleteOnExist( - server.rconService, - (name) => k8sCore.deleteNamespacedService(name, namespace), + const deleteRconService = deleteOnExist(server.rconService, (name) => + k8sCore.deleteNamespacedService(name, namespace), ); - if(deleteDeploy) await deleteDeploy.catch(deleteError(res)) + if (deleteDeploy) await deleteDeploy.catch(deleteError(res)); - const deleteRconSecret = deleteOnExist( - server.rconSecret, - (name) => k8sCore.deleteNamespacedSecret(name, namespace), + const deleteRconSecret = deleteOnExist(server.rconSecret, (name) => + k8sCore.deleteNamespacedSecret(name, namespace), ); - const deleteVolume = deleteOnExist( - server.volume, - (name) => k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), + const deleteVolume = deleteOnExist(server.volume, (name) => + k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), ); Promise.all([ diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js new file mode 100644 index 0000000..077158f --- /dev/null +++ b/lib/k8s/server-files.js @@ -0,0 +1,35 @@ +import ftp from "basic-ftp"; +import { ERR } from "../util/logging.js"; +import { getServerAssets } from "./k8s-server-control.js"; + +const namespace = process.env.MCL_SERVER_NAMESPACE; + +export async function listFiles(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 server = await getServerAssets(name); + if (!server) + return res.status(404).send("No Resources for that server were found!"); + if (!server.service) + return res + .status(409) + .send("Service doesn't exist, please contact your hosting provider!"); + const client = new ftp.Client(0); + client.ftp.verbose = true; + try { + await client.access({ + host: `${server.service.metadata.name}.${namespace}.svc.cluster.local`, + user: "minecluster", + password: "minecluster", + }); + const files = await client.list(); + res.json(files); + } catch (err) { + console.log(err); + ERR("SERVER FILES", "Error loading client files:"); + res.status(500).send(err); + } + client.close(); +} diff --git a/lib/routes/files-route.js b/lib/routes/files-route.js new file mode 100644 index 0000000..c326cd9 --- /dev/null +++ b/lib/routes/files-route.js @@ -0,0 +1,7 @@ +import { Router, json as jsonMiddleware } from "express"; +import { listFiles } from "../k8s/server-files.js"; +const router = Router(); +router.use(jsonMiddleware()); +router.post("/list", listFiles); + +export default router; diff --git a/lib/server/router.js b/lib/server/router.js index fdf381a..ccedebb 100644 --- a/lib/server/router.js +++ b/lib/server/router.js @@ -5,6 +5,7 @@ import express from "express"; import vitals from "../routes/vitals-route.js"; import systemRoute from "../routes/system-route.js"; import serverRoute from "../routes/server-route.js"; +import filesRoute from "../routes/files-route.js"; import reactRoute from "../routes/react-route.js"; import { logErrors, @@ -23,6 +24,7 @@ export default function buildRoutes(pg, skio) { // Routes router.use("/api/system", systemRoute); router.use("/api/server", serverRoute); + router.use("/api/files", filesRoute); router.use(["/mcl", "/mcl/*"], reactRoute); // Static Build Route /*router.use(logErrors); router.use(clientErrorHandler); diff --git a/package-lock.json b/package-lock.json index 1b70a3e..86ebdf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@kubernetes/client-node": "^0.20.0", "aws-sdk": "^2.1514.0", + "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", @@ -3491,6 +3492,14 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/basic-ftp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", + "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", diff --git a/package.json b/package.json index e6b3936..6d78841 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "dependencies": { "@kubernetes/client-node": "^0.20.0", "aws-sdk": "^2.1514.0", + "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", From 62c966a6bd7887ae88bd110fc64e399abbc32715 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Sun, 17 Dec 2023 12:25:14 -0700 Subject: [PATCH 11/56] [FEATURE] Adjust server control --- .../configs/containers/minecraft-server.yml | 3 +- lib/k8s/configs/server-deployment.yml | 2 + lib/k8s/k8s-server-control.js | 26 +++++-- lib/k8s/live-logging.js | 11 ++- lib/k8s/server-control.js | 1 + lib/k8s/server-create.js | 77 ++++++++++++------- lib/k8s/server-files.js | 38 +++++---- lib/server/rcon.js | 8 +- 8 files changed, 109 insertions(+), 57 deletions(-) diff --git a/lib/k8s/configs/containers/minecraft-server.yml b/lib/k8s/configs/containers/minecraft-server.yml index 26b01d2..09bcb90 100644 --- a/lib/k8s/configs/containers/minecraft-server.yml +++ b/lib/k8s/configs/containers/minecraft-server.yml @@ -52,7 +52,8 @@ env: - name: GENERATOR_SETTINGS - name: LEVEL value: world - - name: MODPACK + # - name: MODPACK + # value: https://somemodpack.com - name: ONLINE_MODE value: "true" - name: MEMORY diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml index 1607944..0d5d335 100644 --- a/lib/k8s/configs/server-deployment.yml +++ b/lib/k8s/configs/server-deployment.yml @@ -16,6 +16,8 @@ spec: type: Recreate template: metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app spec: diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js index 7d82bb0..978fe9e 100644 --- a/lib/k8s/k8s-server-control.js +++ b/lib/k8s/k8s-server-control.js @@ -1,5 +1,5 @@ import k8s from "@kubernetes/client-node"; -import { VERB } from "../util/logging.js"; +import { VERB, ERR } from "../util/logging.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -13,7 +13,7 @@ const mineclusterManaged = (o) => o.metadata.annotations && o.metadata.annotations["minecluster.dunemask.net/server-name"] !== undefined; -const serverMatch = (serverName) => (o) => +export const serverMatch = (serverName) => (o) => o.metadata.annotations["minecluster.dunemask.net/server-name"] === serverName; export async function getDeployments() { @@ -72,7 +72,7 @@ export function getServerAssets(serverName) { for (var k in serverAssets) if (serverAssets[k]) return serverAssets; // If no assets exist, return nothing }) - .catch((e) => console.log(e)); + .catch((e) => ERR("SERVER ASSETS", e)); } export async function getDeployment(serverName) { @@ -82,13 +82,26 @@ export async function getDeployment(serverName) { s.metadata.annotations["minecluster.dunemask.net/server-name"] === serverName, ); - if (!serverDeployment) { - console.log(servers.map((s) => s.metadata.annotations)); + if (!serverDeployment) throw Error(`MCL Deployment '${serverName}' could not be found!`); - } + return serverDeployment; } +export async function toggleServer(serverName, scaleUp = false) { + const deployment = await getDeployment(serverName); + const { containers } = deployment.spec.template.spec; + const ftpContainer = containers.find((c) => c.name.endsWith("-ftp")); + + res.sendStatus(200); + deployment.spec.template.spec.containers = containers; + return k8sDeps.replaceNamespacedDeployment( + deployment.metadata.name, + namespace, + deployment, + ); +} + export async function scaleDeployment(serverName, scaleUp = false) { const deployment = await getDeployment(serverName); if (deployment.spec.replicas === 1 && scaleUp) @@ -97,6 +110,7 @@ export async function scaleDeployment(serverName, scaleUp = false) { `MCL Deployment '${serverName}' is already scaled! Ignoring scale adjustment.`, ); deployment.spec.replicas = scaleUp ? 1 : 0; + return k8sDeps.replaceNamespacedDeployment( deployment.metadata.name, namespace, diff --git a/lib/k8s/live-logging.js b/lib/k8s/live-logging.js index 93cc273..8a21f58 100644 --- a/lib/k8s/live-logging.js +++ b/lib/k8s/live-logging.js @@ -5,15 +5,18 @@ 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 { serverName } = socket.mcs; + const podName = `mcl-${serverName}`; + const containerName = `${podName}-server`; const podResponse = await k8sApi.listNamespacedPod(serverNamespace); const pods = podResponse.body.items.map((vp1) => vp1.metadata.name); - const mcsPods = pods.filter((p) => p.startsWith(containerName)); + const mcsPods = pods.filter((p) => p.startsWith(podName)); if (mcsPods.length === 0) - throw Error(`Could not find a pod that starts with ${containerName}`); + throw Error(`Could not find a pod that starts with ${podName}`); if (mcsPods.length > 1) - throw Error(`Multiple pods match the name ${containerName}`); + throw Error(`Multiple pods match the name ${podName}`); const log = new k8s.Log(kc); const logStream = new stream.PassThrough(); diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js index 8e14c64..558c77d 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -10,6 +10,7 @@ const kc = new k8s.KubeConfig(); kc.loadFromDefault(); const k8sMetrics = new k8s.Metrics(kc); +const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; // Gets the all assets for the server diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index dd7cbbc..0486e92 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -55,8 +55,10 @@ function createServerVolume(serverSpec) { return volumeYaml; } -function getFtpContainer() { +function getFtpContainer(serverSpec) { + const { name } = serverSpec; const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); + ftpContainer.name = `mcl-${name}-ftp`; const ftpPortList = [ { p: 20, n: "ftp-data" }, { p: 21, n: "ftp-commands" }, @@ -71,7 +73,7 @@ function getFtpContainer() { return ftpContainer; } -function createServerDeploy(serverSpec) { +function getServerContainer(serverSpec) { const { name, version, @@ -86,24 +88,16 @@ function createServerDeploy(serverSpec) { ops, whitelist, } = serverSpec; - const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); - const serverContainer = loadYaml( - "lib/k8s/configs/containers/minecraft-server.yml", - ); - const backupContainer = loadYaml( - "lib/k8s/configs/containers/minecraft-backup.yml", - ); - const ftpContainer = getFtpContainer(); - deployYaml.metadata.name = `mcl-${name}`; + const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml"); + + // Container Updates + container.name = `mcl-${name}-server`; + container.resources.requests.memory = `${memory}Mi`; + // container.resources.limits.memory = `${memory}Mi`; // TODO Allow for limits beyond initial startup + + const findEnv = (k) => container.env.find(({ name: n }) => n === k); + const updateEnv = (k, v) => (findEnv(k).value = v); - deployYaml.metadata.namespace = namespace; - deployYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = - name; - 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`; - const findEnv = (k) => serverContainer.env.find(({ name: n }) => n === k); - const updateEnv = (k, v) => (findEnv.value = v); // Enviornment variables updateEnv("TYPE", serverType); updateEnv("VERSION", version); @@ -116,22 +110,49 @@ function createServerDeploy(serverSpec) { updateEnv("WHITELIST", whitelist); updateEnv("MEMORY", `${memory}M`); - if (version !== "VANILLA") delete findEnv("MODPACK").value; - else updateEnv("MODPACK", modpack); - findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = - `mcl-${name}-rcon-secret`; + // RCON + const rs = `mcl-${name}-rcon-secret`; + findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + // Mods // TODO: remove these once files are managable + /*if (version !== "VANILLA") delete findEnv("MODPACK").value; + else updateEnv("MODPACK", modpack);*/ + + return container; +} + +function getBackupContainer(serverSpec) { + const container = loadYaml("lib/k8s/configs/containers/minecraft-backup.yml"); + return container; +} + +function createServerDeploy(serverSpec) { + const { name } = serverSpec; + const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); + const { metadata } = deployYaml; + const serverContainer = getServerContainer(serverSpec); + const backupContainer = getBackupContainer(serverSpec); + const ftpContainer = getFtpContainer(serverSpec); + + // Configure Metadata; + metadata.name = `mcl-${name}`; + metadata.namespace = namespace; + metadata.annotations["minecluster.dunemask.net/server-name"] = name; + deployYaml.metadata = metadata; + + // Configure Lables & Selectors + deployYaml.spec.selector.matchLabels.app = `mcl-${name}-app`; + deployYaml.spec.template.metadata.labels.app = `mcl-${name}-app`; - // 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`; + + // Apply Containers deployYaml.spec.template.spec.containers.push(serverContainer); deployYaml.spec.template.spec.containers.push(ftpContainer); + // TODO: User control for autostart + deployYaml.spec.replicas = 0; return deployYaml; } diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js index 077158f..1e1b13b 100644 --- a/lib/k8s/server-files.js +++ b/lib/k8s/server-files.js @@ -4,6 +4,22 @@ import { getServerAssets } from "./k8s-server-control.js"; const namespace = process.env.MCL_SERVER_NAMESPACE; +export async function useFtp(serverService) { + const { name } = serverService.metadata; + const client = new ftp.Client(); + await client.access({ + host: `${name}.${namespace}.svc.cluster.local`, + user: "minecluster", + password: "minecluster", + }); + return client; +} + +const handleError = (res) => (e) => { + ERR("SERVER FILES", "Error occurred while preforming FTP operation!", e); + res.status(500).send("Error occurred while performing FTP operation!"); +}; + export async function listFiles(req, res) { const serverSpec = req.body; if (!serverSpec) return res.sendStatus(400); @@ -16,20 +32,12 @@ export async function listFiles(req, res) { return res .status(409) .send("Service doesn't exist, please contact your hosting provider!"); - const client = new ftp.Client(0); - client.ftp.verbose = true; - try { - await client.access({ - host: `${server.service.metadata.name}.${namespace}.svc.cluster.local`, - user: "minecluster", - password: "minecluster", - }); - const files = await client.list(); - res.json(files); - } catch (err) { - console.log(err); - ERR("SERVER FILES", "Error loading client files:"); - res.status(500).send(err); - } + // client.ftp.verbose = true; + const client = await useFtp(server.service).catch(handleError(res)); + if (!client) return; + await client + .list() + .then((f) => res.json(f)) + .catch(handleError(res)); client.close(); } diff --git a/lib/server/rcon.js b/lib/server/rcon.js index 81cf46a..82a3def 100644 --- a/lib/server/rcon.js +++ b/lib/server/rcon.js @@ -1,6 +1,6 @@ import k8s from "@kubernetes/client-node"; import { Rcon as RconClient } from "rcon-client"; -import { ERR } from "../util/logging.js"; +import { ERR, WARN } from "../util/logging.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); const k8sCore = kc.makeApiClient(k8s.CoreV1Api); @@ -15,7 +15,8 @@ export default async function rconInterface(socket) { rconRes.body.data["rcon-password"], "base64", ).toString("utf8"); - const rconHost = `mcl-${socket.mcs.serverName}-rcon`; + const { serverName } = socket.mcs; + const rconHost = `mcl-${serverName}-rcon.${namespace}.svc.cluster.local`; const rcon = new RconClient({ host: rconHost, port: 25575, @@ -25,7 +26,8 @@ export default async function rconInterface(socket) { try { await rcon.connect(); } catch (error) { - ERR("RCON", `Could not connect to 'mcl-${socket.mcs.serverName}-rcon'`); + socket.emit("push", "Could not connect RCON Input to server!"); + WARN("RCON", `Could not connect to '${rconHost}'`); } socket.rconClient = rcon; } From 37e3dc2ae93372fbbc8acf39acf596129bc108a1 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Mon, 18 Dec 2023 03:55:27 -0700 Subject: [PATCH 12/56] [FEATURE] Adjust more server controllers --- lib/controllers/file-controller.js | 11 +++ lib/controllers/lifecycle-controller.js | 78 +++++++++++++++++++ lib/controllers/status-controller.js | 18 +++++ .../sub-controllers/console-controller.js | 65 ++++++++++++++++ lib/k8s/k8s-server-control.js | 5 ++ lib/k8s/live-logging.js | 33 -------- lib/k8s/server-control.js | 62 ++++++--------- lib/k8s/server-create.js | 31 ++------ lib/k8s/server-delete.js | 26 ++++--- lib/k8s/server-files.js | 33 ++++---- lib/routes/files-route.js | 2 +- lib/routes/server-route.js | 14 ++-- lib/server/rcon.js | 33 -------- lib/server/sockets.js | 12 +-- lib/util/ExpressClientError.js | 28 +++++++ src/pages/Home.jsx | 3 +- 16 files changed, 281 insertions(+), 173 deletions(-) create mode 100644 lib/controllers/file-controller.js create mode 100644 lib/controllers/lifecycle-controller.js create mode 100644 lib/controllers/status-controller.js create mode 100644 lib/controllers/sub-controllers/console-controller.js delete mode 100644 lib/k8s/live-logging.js delete mode 100644 lib/server/rcon.js create mode 100644 lib/util/ExpressClientError.js diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js new file mode 100644 index 0000000..2f2d8fa --- /dev/null +++ b/lib/controllers/file-controller.js @@ -0,0 +1,11 @@ +import { listServerFiles } from "../k8s/server-files.js"; +import { sendError } from "../util/ExpressClientError.js"; + +export async function listFiles(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + listServerFiles(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js new file mode 100644 index 0000000..6984fc0 --- /dev/null +++ b/lib/controllers/lifecycle-controller.js @@ -0,0 +1,78 @@ +import createServerResources from "../k8s/server-create.js"; +import deleteServerResources from "../k8s/server-delete.js"; +import { sendError } from "../util/ExpressClientError.js"; +import { + startServerContainer, + stopServerContainer, +} from "../k8s/server-control.js"; + +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 checkServerName(serverSpec) { + if (!serverSpec) throw new ExpressClientError({ c: 400 }); + if (!serverSpec.name) + throw new ExpressClientError({ c: 400, m: "Server name required!" }); +} + +export function createServer(req, res) { + if (payloadFilter(req, res) !== "filtered") return; + const serverSpec = req.body; + createServerResources(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function deleteServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerName(serverSpec); + } catch (e) { + return sendError(res)(e); + } + + deleteServerResources(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function startServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerName(serverSpec); + } catch (e) { + return sendError(res)(e); + } + startServerContainer(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function stopServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerName(serverSpec); + } catch (e) { + return sendError(res)(e); + } + stopServerContainer(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} diff --git a/lib/controllers/status-controller.js b/lib/controllers/status-controller.js new file mode 100644 index 0000000..b2fa8b7 --- /dev/null +++ b/lib/controllers/status-controller.js @@ -0,0 +1,18 @@ +import { getDeployments } from "../k8s/k8s-server-control.js"; +import { getInstances } from "../k8s/server-control.js"; +import { sendError } from "../util/ExpressClientError.js"; + +export function serverList(req, res) { + getDeployments() + .then((sd) => res.json(sd.map((s) => s.metadata.name.substring(4)))) + .catch((e) => { + ERR("SERVER CONTROL", e); + res.status(500).send("Couldn't get server list"); + }); +} + +export function serverInstances(req, res) { + getInstances() + .then((i) => res.json(i)) + .catch(sendError(res)); +} diff --git a/lib/controllers/sub-controllers/console-controller.js b/lib/controllers/sub-controllers/console-controller.js new file mode 100644 index 0000000..40cf777 --- /dev/null +++ b/lib/controllers/sub-controllers/console-controller.js @@ -0,0 +1,65 @@ +// Imports +import k8s from "@kubernetes/client-node"; +import { Rcon as RconClient } from "rcon-client"; +import stream from "stream"; +import { ERR, WARN } from "../../util/logging.js"; + +// Kubernetes Configuration +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +// Retrieves logs from the minecraft server container +export async function webConsoleLogs(socket) { + const { serverName } = socket.mcs; + const podName = `mcl-${serverName}`; + const containerName = `${podName}-server`; + const podResponse = await k8sCore.listNamespacedPod(namespace); + const pods = podResponse.body.items.map((vp1) => vp1.metadata.name); + const mcsPods = pods.filter((p) => p.startsWith(podName)); + if (mcsPods.length === 0) + throw Error(`Could not find a pod that starts with ${podName}`); + if (mcsPods.length > 1) + throw Error(`Multiple pods match the name ${podName}`); + + const log = new k8s.Log(kc); + const logStream = new stream.PassThrough(); + logStream.on("data", (chunk) => + socket.emit("push", Buffer.from(chunk).toString()), + ); + log + .log(namespace, mcsPods[0], containerName, logStream, { + follow: true, + pretty: false, + timestamps: false, + }) + .catch((e) => ERR("CONSOLE CONTROLLER", "Error streaming logs", e)); +} + +// Creates an RCON connection to the minecraft container +export async function webConsoleRcon(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 { serverName } = socket.mcs; + const rconHost = `mcl-${serverName}-rcon.${namespace}.svc.cluster.local`; + const rcon = new RconClient({ + host: rconHost, + port: 25575, + password: rconPassword, + }); + rcon.on("error", (error) => socket.emit("push", error)); + try { + await rcon.connect(); + } catch (error) { + socket.emit("push", "Could not connect RCON Input to server!"); + WARN("RCON", `Could not connect to '${rconHost}'`); + } + socket.rconClient = rcon; +} diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js index 978fe9e..fc45560 100644 --- a/lib/k8s/k8s-server-control.js +++ b/lib/k8s/k8s-server-control.js @@ -88,6 +88,11 @@ export async function getDeployment(serverName) { return serverDeployment; } +export async function getContainers(serverName) { + const deployment = await getDeployment(serverName); + return deployment.spec.template.spec.containers; +} + export async function toggleServer(serverName, scaleUp = false) { const deployment = await getDeployment(serverName); const { containers } = deployment.spec.template.spec; diff --git a/lib/k8s/live-logging.js b/lib/k8s/live-logging.js deleted file mode 100644 index 8a21f58..0000000 --- a/lib/k8s/live-logging.js +++ /dev/null @@ -1,33 +0,0 @@ -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 { serverName } = socket.mcs; - const podName = `mcl-${serverName}`; - const containerName = `${podName}-server`; - const podResponse = await k8sApi.listNamespacedPod(serverNamespace); - const pods = podResponse.body.items.map((vp1) => vp1.metadata.name); - const mcsPods = pods.filter((p) => p.startsWith(podName)); - if (mcsPods.length === 0) - throw Error(`Could not find a pod that starts with ${podName}`); - if (mcsPods.length > 1) - throw Error(`Multiple pods match the name ${podName}`); - - 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 index 558c77d..f1d868e 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -6,6 +6,7 @@ import { scaleDeployment, } from "./k8s-server-control.js"; import { ERR } from "../util/logging.js"; +import ExpressClientError from "../util/ExpressClientError.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -13,61 +14,38 @@ const k8sMetrics = new k8s.Metrics(kc); const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; -// Gets the all assets for the server -export async function getServer(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; - getServerAssets(name) - .then((server) => res.status(200).json(server)) - .catch((e) => res.status(500).send(e)); -} - -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!"); +export async function startServerContainer(serverSpec) { const { name } = serverSpec; try { await scaleDeployment(name, true); - res.sendStatus(200); } catch (e) { ERR("SERVER CONTROL", e); - res.status(500).send(`Error updating server '${name}'!`); + throw new ExpressClientError({ + c: 500, + m: `Error updating server '${name}'!\n`, + }); } } -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!"); +export async function stopServerContainer(serverSpec) { const { name } = serverSpec; try { await scaleDeployment(name, false); - res.sendStatus(200); } catch (e) { ERR("SERVER CONTROL", e); - res.status(500).send(`Error updating server '${name}'!`); + throw new ExpressClientError({ + c: 500, + m: `Error updating server '${name}'!`, + }); } } -export function serverList(req, res) { - getDeployments() - .then((sd) => res.json(sd.map((s) => s.metadata.name.substring(4)))) - .catch((e) => { - ERR("SERVER CONTROL", e); - res.status(500).send("Couldn't get server list"); - }); -} - -export async function getServers(req, res) { +export async function getInstances() { const serverDeployments = await getDeployments(); const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace); - var name, metrics, started; - const servers = serverDeployments.map((s) => { - name = s.metadata.name.substring(4); + const serverInstances = serverDeployments.map((s) => { + name = s.metadata.annotations["minecluster.dunemask.net/server-name"]; metrics = null; started = !!s.spec.replicas; const pod = podMetricsResponse.items.find(({ metadata: md }) => { @@ -85,18 +63,22 @@ export async function getServers(req, res) { memory: Math.ceil(podMems.reduce((a, b) => a + b)), }; } - return { name, metrics, started }; }); + return serverInstances; +} + +export async function getNamespaceMetrics() { + const serverInstances = await getInstances(); var clusterMetrics = { cpu: 0, memory: 0 }; if (servers.length > 1) { - const clusterCpu = servers + const clusterCpu = serverInstances .map(({ metrics }) => (metrics ? metrics.cpu : 0)) .reduce((a, b) => a + b); - const clusterMem = servers + const clusterMem = serverInstances .map(({ metrics }) => (metrics ? metrics.memory : 0)) .reduce((a, b) => a + b); clusterMetrics = { cpu: clusterCpu, memory: clusterMem }; } - res.json({ servers, clusterMetrics }); + return clusterMetrics; } diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 0486e92..f326633 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -4,6 +4,8 @@ import k8s from "@kubernetes/client-node"; import yaml from "js-yaml"; import fs from "node:fs"; import path from "node:path"; +import ExpressClientError from "../util/ExpressClientError.js"; + const kc = new k8s.KubeConfig(); kc.loadFromDefault(); const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); @@ -12,27 +14,9 @@ const namespace = process.env.MCL_SERVER_NAMESPACE; const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); -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 = loadYaml("lib/k8s/configs/rcon-secret.yml"); - // TODO: Dyamic rconPassword const rconPassword = bcrypt.hashSync(uuidv4(), 10); rconYaml.data["rcon-password"] = Buffer.from(rconPassword).toString("base64"); @@ -84,7 +68,6 @@ function getServerContainer(serverSpec) { motd, maxPlayers, seed, - modpack, ops, whitelist, } = serverSpec; @@ -195,17 +178,15 @@ function createRconService(serverSpec) { return rconSvcYaml; } -export default async function createServer(req, res) { - if (payloadFilter(req, res) !== "filtered") return; - const serverSpec = req.body; +export default async function createServerResources(serverSpec) { 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!"); + throw new ExpressClientError("Server already exists!", { c: 409 }); 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!"); + throw new ExpressClientError("Server PVC already exists!", { c: 409 }); const rconSecret = createRconSecret(serverSpec); const serverVolume = createServerVolume(serverSpec); const serverDeploy = createServerDeploy(serverSpec); @@ -216,6 +197,4 @@ export default async function createServer(req, res) { 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 index e620f4b..e226fbf 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -1,6 +1,7 @@ import k8s from "@kubernetes/client-node"; import { ERR } from "../util/logging.js"; import { getServerAssets } from "./k8s-server-control.js"; +import ExpressClientError from "../util/ExpressClientError.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -8,24 +9,27 @@ 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!"); +const deleteError = (err) => { ERR("K8S", "An error occurred while deleting a resource", err); + throw new ExpressClientError({ + c: 500, + m: "Error deleting a resource!\n" + err, + }); }; function deleteOnExist(o, fn) { if (o) return fn(o.metadata.name); } -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!"); +export default async function deleteServerResources(serverSpec) { const { name } = serverSpec; // Ensure deployment exists const server = await getServerAssets(name); if (!server) - return res.status(404).send("No Resources for that server were found!"); + throw new ExpressClientError({ + c: 404, + m: "No Resources for that server were found!", + }); // Delete in reverse order const deleteDeploy = deleteOnExist(server.deployment, (name) => @@ -38,7 +42,7 @@ export default async function deleteServer(req, res) { const deleteRconService = deleteOnExist(server.rconService, (name) => k8sCore.deleteNamespacedService(name, namespace), ); - if (deleteDeploy) await deleteDeploy.catch(deleteError(res)); + if (deleteDeploy) await deleteDeploy.catch(deleteError); const deleteRconSecret = deleteOnExist(server.rconSecret, (name) => k8sCore.deleteNamespacedSecret(name, namespace), @@ -47,12 +51,10 @@ export default async function deleteServer(req, res) { k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), ); - Promise.all([ + return Promise.all([ deleteService, deleteRconService, deleteRconSecret, deleteVolume, - ]) - .then(() => res.sendStatus(200)) - .catch(deleteError(res)); + ]).catch(deleteError); } diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js index 1e1b13b..e2e4da0 100644 --- a/lib/k8s/server-files.js +++ b/lib/k8s/server-files.js @@ -1,6 +1,7 @@ import ftp from "basic-ftp"; import { ERR } from "../util/logging.js"; import { getServerAssets } from "./k8s-server-control.js"; +import ExpressClientError from "../util/ExpressClientError.js"; const namespace = process.env.MCL_SERVER_NAMESPACE; @@ -15,29 +16,33 @@ export async function useFtp(serverService) { return client; } -const handleError = (res) => (e) => { +const handleError = (e) => { ERR("SERVER FILES", "Error occurred while preforming FTP operation!", e); - res.status(500).send("Error occurred while performing FTP operation!"); + throw new ExpressClientError({ + c: 500, + m: "Error occurred while performing FTP operation!", + }); }; -export async function listFiles(req, res) { - const serverSpec = req.body; - if (!serverSpec) return res.sendStatus(400); - if (!serverSpec.name) return res.status(400).send("Server name required!"); +export async function listServerFiles(serverSpec) { const { name } = serverSpec; const server = await getServerAssets(name); if (!server) - return res.status(404).send("No Resources for that server were found!"); + throw new ExpressClientError({ + c: 404, + m: "No resources for that server were found!", + }); if (!server.service) - return res - .status(409) - .send("Service doesn't exist, please contact your hosting provider!"); - // client.ftp.verbose = true; - const client = await useFtp(server.service).catch(handleError(res)); - if (!client) return; + throw new ExpressClientError({ + c: 409, + m: "Service doesn't exist, please contact your hosting provider!", + }); + + // FTP Operations; + const client = await useFtp(server.service).catch(handleError); await client .list() .then((f) => res.json(f)) - .catch(handleError(res)); + .catch(handleError); client.close(); } diff --git a/lib/routes/files-route.js b/lib/routes/files-route.js index c326cd9..cab537e 100644 --- a/lib/routes/files-route.js +++ b/lib/routes/files-route.js @@ -1,5 +1,5 @@ import { Router, json as jsonMiddleware } from "express"; -import { listFiles } from "../k8s/server-files.js"; +import { listFiles } from "../controllers/file-controller.js"; const router = Router(); router.use(jsonMiddleware()); router.post("/list", listFiles); diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js index 8a39c0e..7361abd 100644 --- a/lib/routes/server-route.js +++ b/lib/routes/server-route.js @@ -1,13 +1,14 @@ import { Router, json as jsonMiddleware } from "express"; import { + createServer, + deleteServer, startServer, stopServer, +} from "../controllers/lifecycle-controller.js"; +import { + serverInstances, serverList, - getServers, - getServer, -} from "../k8s/server-control.js"; -import createServer from "../k8s/server-create.js"; -import deleteServer from "../k8s/server-delete.js"; +} from "../controllers/status-controller.js"; const router = Router(); router.use(jsonMiddleware()); // Routes @@ -15,7 +16,6 @@ router.post("/create", createServer); router.delete("/delete", deleteServer); router.post("/start", startServer); router.post("/stop", stopServer); -// router.post("/get", getServer) // SHOULD BE DISABLED EXCEPT FOR DEBUGGING; router.get("/list", serverList); -router.get("/instances", getServers); +router.get("/instances", serverInstances); export default router; diff --git a/lib/server/rcon.js b/lib/server/rcon.js deleted file mode 100644 index 82a3def..0000000 --- a/lib/server/rcon.js +++ /dev/null @@ -1,33 +0,0 @@ -import k8s from "@kubernetes/client-node"; -import { Rcon as RconClient } from "rcon-client"; -import { ERR, WARN } 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 { serverName } = socket.mcs; - const rconHost = `mcl-${serverName}-rcon.${namespace}.svc.cluster.local`; - const rcon = new RconClient({ - host: rconHost, - port: 25575, - password: rconPassword, - }); - rcon.on("error", (error) => socket.emit("push", error)); - try { - await rcon.connect(); - } catch (error) { - socket.emit("push", "Could not connect RCON Input to server!"); - WARN("RCON", `Could not connect to '${rconHost}'`); - } - socket.rconClient = rcon; -} diff --git a/lib/server/sockets.js b/lib/server/sockets.js index 2b63ede..370e3d4 100644 --- a/lib/server/sockets.js +++ b/lib/server/sockets.js @@ -1,9 +1,9 @@ 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; +import { + webConsoleLogs, + webConsoleRcon, +} from "../controllers/sub-controllers/console-controller.js"; async function rconSend(socket, m) { if (!socket.rconClient) @@ -20,8 +20,8 @@ const socketConnect = async (io, socket) => { VERB("WS", "Websocket connecting"); socket.mcs = { serverName: socket.handshake.query.serverName }; try { - await liveLogging(socket, namespace); - await rconInterface(socket); + await webConsoleLogs(socket); + await webConsoleRcon(socket); socket.on("msg", (m) => rconSend(socket, m)); } catch (err) { ERR("SOCKETS", err); diff --git a/lib/util/ExpressClientError.js b/lib/util/ExpressClientError.js new file mode 100644 index 0000000..d079c30 --- /dev/null +++ b/lib/util/ExpressClientError.js @@ -0,0 +1,28 @@ +import { VERB } from "./logging.js"; + +export default class ExpressClientError extends Error { + constructor(message, clientOptions = {}) { + var msg; + if (typeof message === "object" && message.m !== undefined) msg = message.m; + else if (typeof message === "object") msg = "Unknown Express Client Error!"; + super(msg); + if (typeof message === "object") this.clientOptions = message; + else this.clientOptions = { message: msg, ...clientOptions }; + } + + sendError(res) { + if (!this.clientOptions.m && this.clientOptions.c) + res.sendStatus(this.clientOptions.c); + else res.status(this.clientOptions.c ?? 500).send(this.toString()); + } + + toString() { + return this.message; + } +} + +export const sendError = (res) => (e) => { + VERB("V", e); + if (e instanceof ExpressClientError) e.sendError(res); + else res.status(500).send(e); +}; diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index d076200..663a2b7 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -14,11 +14,12 @@ import "@mcl/css/overview.css"; import { useServerInstances } from "@mcl/queries"; export default function Home() { + const clusterMetrics = { cpu: 0, memory: 0 }; const [server, setServer] = useState(); const [servers, setServers] = useState([]); const [rdOpen, rconToggle] = useRconDialog(); const { isLoading, data: serversData } = useServerInstances(); - const { servers: serverInstances, clusterMetrics } = serversData ?? {}; + const serverInstances = serversData ?? []; useEffect(() => { if (!serverInstances) return; serverInstances.sort((a, b) => a.name.localeCompare(b.name)); From af44ff710f559b056e467d34452653ca17594e90 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Mon, 18 Dec 2023 08:45:57 -0700 Subject: [PATCH 13/56] [FEATURE] Adjust more server controllers --- lib/k8s/server-create.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index f326633..70d8bf6 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -96,9 +96,6 @@ function getServerContainer(serverSpec) { // RCON const rs = `mcl-${name}-rcon-secret`; findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; - // Mods // TODO: remove these once files are managable - /*if (version !== "VANILLA") delete findEnv("MODPACK").value; - else updateEnv("MODPACK", modpack);*/ return container; } @@ -167,7 +164,7 @@ function createServerService(serverSpec) { } function createRconService(serverSpec) { - const { name, url } = serverSpec; + const { name } = serverSpec; const rconSvcYaml = loadYaml("lib/k8s/configs/rcon-svc.yml"); rconSvcYaml.metadata.labels.app = `mcl-${name}-app`; rconSvcYaml.metadata.name = `mcl-${name}-rcon`; @@ -182,11 +179,11 @@ export default async function createServerResources(serverSpec) { const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); const deployments = deploymentRes.body.items.map((i) => i.metadata.name); if (deployments.includes(`mcl-${serverSpec.name}`)) - throw new ExpressClientError("Server already exists!", { c: 409 }); + throw new ExpressClientError({m: "Server already exists!", c: 409 }); const pvcRes = await k8sCore.listNamespacedPersistentVolumeClaim(namespace); const pvcs = pvcRes.body.items.map((i) => i.metadata.name); if (pvcs.includes(`mcl-${serverSpec.name}-volume`)) - throw new ExpressClientError("Server PVC already exists!", { c: 409 }); + throw new ExpressClientError({ m: "Server PVC already exists!", c: 409 }); const rconSecret = createRconSecret(serverSpec); const serverVolume = createServerVolume(serverSpec); const serverDeploy = createServerDeploy(serverSpec); From e66e685903694bbad62a3c1b36d89e84752a3111 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Mon, 18 Dec 2023 16:50:33 -0700 Subject: [PATCH 14/56] [FEATURE] Initial FS traversal --- lib/controllers/file-controller.js | 15 +- lib/k8s/server-create.js | 2 +- lib/k8s/server-files.js | 13 +- package-lock.json | 1223 ++++++++++++++++++++-- package.json | 2 + src/components/edit/MineclusterFiles.jsx | 55 + src/components/servers/ServerCard.jsx | 19 +- src/nav/MCLPages.jsx | 7 + src/pages/Files.jsx | 20 + src/util/queries.js | 10 + vite.config.js | 2 +- 11 files changed, 1260 insertions(+), 108 deletions(-) create mode 100644 src/components/edit/MineclusterFiles.jsx create mode 100644 src/pages/Files.jsx diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js index 2f2d8fa..88501d2 100644 --- a/lib/controllers/file-controller.js +++ b/lib/controllers/file-controller.js @@ -6,6 +6,19 @@ export async function listFiles(req, res) { if (!serverSpec) return res.sendStatus(400); if (!serverSpec.name) return res.status(400).send("Server name required!"); listServerFiles(serverSpec) - .then(() => res.sendStatus(200)) + .then((f) => { + const fileData = f.map((fi, i) => ({ + name: fi.name, + isDir: fi.type === 2, + id: `${fi.name}-${i}`, + isHidden: fi.name.startsWith("."), + isSymLink: !!fi.link, + size: fi.size, + })); + console.log(fileData); + res.json(fileData); + }) .catch(sendError(res)); } + +export async function uploadFile(req, res) {} diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 70d8bf6..159811b 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -179,7 +179,7 @@ export default async function createServerResources(serverSpec) { const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); const deployments = deploymentRes.body.items.map((i) => i.metadata.name); if (deployments.includes(`mcl-${serverSpec.name}`)) - throw new ExpressClientError({m: "Server already exists!", c: 409 }); + throw new ExpressClientError({ m: "Server already exists!", c: 409 }); const pvcRes = await k8sCore.listNamespacedPersistentVolumeClaim(namespace); const pvcs = pvcRes.body.items.map((i) => i.metadata.name); if (pvcs.includes(`mcl-${serverSpec.name}-volume`)) diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js index e2e4da0..516701d 100644 --- a/lib/k8s/server-files.js +++ b/lib/k8s/server-files.js @@ -25,7 +25,7 @@ const handleError = (e) => { }; export async function listServerFiles(serverSpec) { - const { name } = serverSpec; + const { name, dir } = serverSpec; const server = await getServerAssets(name); if (!server) throw new ExpressClientError({ @@ -40,9 +40,12 @@ export async function listServerFiles(serverSpec) { // FTP Operations; const client = await useFtp(server.service).catch(handleError); - await client - .list() - .then((f) => res.json(f)) + const files = client + .list(dir) + .then((f) => { + client.close(); + return f; + }) .catch(handleError); - client.close(); + return files; } diff --git a/package-lock.json b/package-lock.json index 86ebdf8..d111705 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,8 @@ "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", + "chonky": "^2.3.2", + "chonky-icon-fontawesome": "^2.3.2", "express": "^4.18.2", "figlet": "^1.7.0", "js-yaml": "^4.1.0", @@ -47,7 +49,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -880,7 +881,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" @@ -893,7 +893,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -905,7 +904,6 @@ "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", @@ -919,7 +917,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -927,14 +924,12 @@ "node_modules/@babel/code-frame/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -943,7 +938,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -952,7 +946,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", - "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", @@ -981,14 +974,12 @@ "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/generator": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", - "dev": true, "dependencies": { "@babel/types": "^7.23.5", "@jridgewell/gen-mapping": "^0.3.2", @@ -999,11 +990,21 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.22.9", "@babel/helper-validator-option": "^7.22.15", @@ -1019,7 +1020,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -1028,7 +1028,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -1041,7 +1040,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -1053,7 +1051,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, "dependencies": { "@babel/types": "^7.22.15" }, @@ -1065,7 +1062,6 @@ "version": "7.23.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -1084,7 +1080,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -1093,7 +1088,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -1105,7 +1099,6 @@ "version": "7.22.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -1117,7 +1110,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -1126,7 +1118,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -1135,7 +1126,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -1144,7 +1134,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", - "dev": true, "dependencies": { "@babel/template": "^7.22.15", "@babel/traverse": "^7.23.5", @@ -1158,7 +1147,6 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -1172,7 +1160,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -1184,7 +1171,6 @@ "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", @@ -1198,7 +1184,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -1206,14 +1191,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -1222,7 +1205,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -1230,6 +1212,20 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.23.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", @@ -1264,7 +1260,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1276,7 +1271,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/parser": "^7.22.15", @@ -1290,7 +1284,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.5", @@ -1311,7 +1304,6 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -1363,7 +1355,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", - "dev": true, "dependencies": { "@emotion/memoize": "^0.8.1" } @@ -1371,8 +1362,7 @@ "node_modules/@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", - "dev": true + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "node_modules/@emotion/react": { "version": "11.11.1", @@ -1440,6 +1430,11 @@ } } }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, "node_modules/@emotion/unitless": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", @@ -1857,11 +1852,152 @@ "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==", "dev": true }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", + "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", + "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-skeleton-parser": "1.3.6", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", + "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.2.1.tgz", + "integrity": "sha512-vgvyUOOrzqVaOFYzTf2d3+ToSkH2JpR7x/4U1RyoHQLmvEaTQvXJ7A2qm1Iy3brGNXC/+/7bUlc3lpH+h/LOJA==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "@formatjs/intl-displaynames": "5.4.3", + "@formatjs/intl-listformat": "6.5.3", + "intl-messageformat": "9.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "typescript": "^4.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@formatjs/intl-displaynames": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-5.4.3.tgz", + "integrity": "sha512-4r12A3mS5dp5hnSaQCWBuBNfi9Amgx2dzhU4lTFfhSxgb5DOAiAbMpg6+7gpWZgl4ahsj3l2r/iHIjdmdXOE2Q==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl-listformat": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-6.5.3.tgz", + "integrity": "sha512-ozpz515F/+3CU+HnLi5DYPsLa6JoCfBggBSSg/8nOB5LYSFW9+ZgNQJxJ8tdhKYeODT+4qVHX27EeJLoxLGLNg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.13.1.tgz", + "integrity": "sha512-dKwF+NpIV2LVCNBA7hibH53k+ChF4Wu59P2z35gu3zwRBZpmpLVhS9k1/RiSqUqkyXUQvA2rSv48GY6wp5axZQ==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.29" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", + "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.x" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1875,7 +2011,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1884,7 +2019,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1892,14 +2026,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.20", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1992,6 +2124,19 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/base": { "version": "5.0.0-beta.26", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", @@ -2256,6 +2401,44 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-dnd/asap": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", + "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==" + }, + "node_modules/@react-dnd/invariant": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", + "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz", @@ -3149,6 +3332,15 @@ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, + "node_modules/@types/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A==", + "deprecated": "This is a stub types definition. classnames provides its own type definitions, so you do not need this installed.", + "dependencies": { + "classnames": "*" + } + }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -3162,11 +3354,30 @@ "@types/node": "*" } }, + "node_modules/@types/fuzzy-search": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/fuzzy-search/-/fuzzy-search-2.1.5.tgz", + "integrity": "sha512-Yw8OsjhVKbKw83LMDOZ9RXc+N+um48DmZYMrz7QChpHkQuygsc5O40oCL7SfvWgpaaviCx2TbNXYUBwhMtBH5w==" + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "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/memoizee": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@types/memoizee/-/memoizee-0.4.11.tgz", + "integrity": "sha512-2gyorIBZu8GoDr9pYjROkxWWcFtHCquF7TVbN2I+/OvgZhnIGQS0vX5KJz4lXNKb8XOSfxFOSG5OLru1ESqLUg==" + }, "node_modules/@types/node": { "version": "20.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", @@ -3181,29 +3392,58 @@ "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "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, + "version": "17.0.73", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.73.tgz", + "integrity": "sha512-6AcjgPIVsXTIsFDgsGW0iQhvg0xb2vt2qAWgXyncnVNRaW9ZXTTwAh7RQoh7PzK1AhjPoGDvUBkdAREih9n5oQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-redux": { + "version": "7.1.33", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz", + "integrity": "sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.10", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", - "dev": true, "dependencies": { "@types/react": "*" } }, + "node_modules/@types/react-virtualized-auto-sizer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.4.tgz", + "integrity": "sha512-nhYwlFiYa8M3S+O2T9QO/e1FQUYMr/wJENUdf/O0dhRi1RS/93rjrYQFYdbUqtdFySuhrtnEDX29P6eKOttY+A==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-window": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz", + "integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/redux-watch": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/redux-watch/-/redux-watch-1.1.2.tgz", + "integrity": "sha512-pooK4MLNYmTyfOU7jy/ZmS2mpbSHkEVpWIcK4/BRbaegOnCB4PYA2JY88vBXE2LVkhPM+du1Z+lVzRiewMz6wg==" + }, "node_modules/@types/request": { "version": "2.48.8", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz", @@ -3218,8 +3458,12 @@ "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 + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/shortid": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", + "integrity": "sha512-9BCYD9btg2CY4kPcpMQ+vCR8U6V8f/KvixYD5ZbxoWlkhddNF5IeZMVL3p+QFUkg+Hb+kPAG9Jgk4bnnF1v/Fw==" }, "node_modules/@types/tough-cookie": { "version": "4.0.2", @@ -3460,6 +3704,21 @@ "npm": ">=6" } }, + "node_modules/babel-plugin-styled-components": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz", + "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "lodash": "^4.17.21", + "picomatch": "^2.3.1" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3597,7 +3856,6 @@ "version": "4.22.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3696,11 +3954,18 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001566", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3759,6 +4024,236 @@ "fsevents": "~2.3.2" } }, + "node_modules/chonky": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chonky/-/chonky-2.3.2.tgz", + "integrity": "sha512-ed2u+SEjEPSn8bv/zC0sXfMG/XS6Ydm4J2leLCvRb7a/2BZxKqE1DFETxqfLeJ2OA1IRujvwnuvmJO8ZgyOGyA==", + "dependencies": { + "@material-ui/core": "4.11.3", + "@reduxjs/toolkit": "^1.5.0", + "@types/classnames": "^2.2.11", + "@types/fuzzy-search": "^2.1.0", + "@types/memoizee": "^0.4.5", + "@types/react": "^17.0.3", + "@types/react-redux": "^7.1.16", + "@types/react-virtualized-auto-sizer": "^1.0.0", + "@types/react-window": "^1.8.2", + "@types/redux-watch": "^1.1.0", + "@types/shortid": "^0.0.29", + "classnames": "^2.2.6", + "deepmerge": "^4.2.2", + "exact-trie": "^1.0.13", + "fast-sort": "^2.2.0", + "filesize": "^6.1.0", + "fuzzy-search": "^3.2.1", + "hotkeys-js": "^3.8.3", + "react-dnd": "11", + "react-dnd-html5-backend": "11", + "react-intl": "^5.13.2", + "react-jss": "^10.5.1", + "react-redux": "^7.2.2", + "react-virtualized-auto-sizer": "^1.0.5", + "react-window": "^1.8.6", + "redux-watch": "^1.2.0", + "shortid": "^2.2.16", + "styled-components": "^5.3.0", + "tsdef": "^0.0.14" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/chonky-icon-fontawesome": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chonky-icon-fontawesome/-/chonky-icon-fontawesome-2.3.2.tgz", + "integrity": "sha512-19Duy25JxteIlQJfZKLH7ZSujU1zYBMLKovWDOLlw1EdPlXb9exsfYUUkwfNS+31KpwttfaqnGuN8Gyed/R6UQ==", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.32", + "@fortawesome/free-brands-svg-icons": "5.13.1", + "@fortawesome/free-solid-svg-icons": "^5.13.1", + "@fortawesome/react-fontawesome": "^0.1.12", + "chonky": "^2.3.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/chonky/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/chonky/node_modules/@material-ui/core": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.3.tgz", + "integrity": "sha512-Adt40rGW6Uds+cAyk3pVgcErpzU/qxc7KBR94jFHBYretU4AtWZltYcNsbeMn9tXL86jjVL1kuGcIHsgLgFGRw==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.3", + "@material-ui/system": "^4.11.3", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.11.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/chonky/node_modules/@material-ui/core/node_modules/@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/chonky/node_modules/@material-ui/core/node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/chonky/node_modules/@material-ui/core/node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/chonky/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chonky/node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/chonky/node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/chonky/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/chonky/node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -3767,6 +4262,11 @@ "node": ">=10" } }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4028,11 +4528,47 @@ "node": ">=10" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/css-jss/-/css-jss-10.10.0.tgz", + "integrity": "sha512-YyMIS/LsSKEGXEaVJdjonWe18p4vXLo8CMA4FrW/kcaEyqdIGKCFXao31gbJddXEdIxSXFFURWrenBJPlKTgAA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "^10.10.0", + "jss-preset-default": "^10.10.0" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/dashdash": { "version": "1.14.1", @@ -4077,6 +4613,14 @@ } } }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4115,11 +4659,20 @@ "node": ">=8" } }, + "node_modules/dnd-core": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-11.1.3.tgz", + "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", + "dependencies": { + "@react-dnd/asap": "^4.0.0", + "@react-dnd/invariant": "^2.0.0", + "redux": "^4.0.4" + } + }, "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" @@ -4142,8 +4695,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.608", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", - "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==", - "dev": true + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -4257,7 +4809,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -4295,6 +4846,11 @@ "node": ">=0.4.x" } }, + "node_modules/exact-trie": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/exact-trie/-/exact-trie-1.0.13.tgz", + "integrity": "sha512-2N0sx9jMlzZxRmSOpFKmcuaPcLXYLGRp69DohigW5E7R/uo9i6S1zJ/PuAckf70099am1ts7YBRMLO8Nr8AJLg==" + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -4372,6 +4928,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "node_modules/fast-sort": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fast-sort/-/fast-sort-2.2.0.tgz", + "integrity": "sha512-W7zqnn2zsYoQA87FKmYtgOsbJohOrh7XrtZrCVHN5XZKqTBTv5UG+rSS3+iWbg/nepRQUOu+wnas8BwtK8kiCg==" + }, "node_modules/fast-xml-parser": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", @@ -4413,6 +4974,14 @@ "node": ">=0.10.0" } }, + "node_modules/filesize": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", + "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", + "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", @@ -4557,6 +5126,11 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/fuzzy-search": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/fuzzy-search/-/fuzzy-search-3.2.1.tgz", + "integrity": "sha512-vAcPiyomt1ioKAsAL2uxSABHJ4Ju/e4UeDM+g1OlR0vV4YhLGMNsdLNvZTpEDY4JCSt0E4hASCNM5t2ETtsbyg==" + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -4580,7 +5154,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -4650,7 +5223,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -4702,7 +5274,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -4741,7 +5312,6 @@ "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" } @@ -4749,8 +5319,15 @@ "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 + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/hotkeys-js": { + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.13.2.tgz", + "integrity": "sha512-SXd+x90nhOdo5s+DZNPtrvXs0ZahQLXT0tWQ68bzjxCNUZ7eV4ZlNqjHLi3Kt2URpR8EBJOB2dBLdNfwIeql1A==", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } }, "node_modules/html-comment-regex": { "version": "1.1.2", @@ -4798,6 +5375,11 @@ "node": ">= 6" } }, + "node_modules/hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -4820,6 +5402,15 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4850,6 +5441,17 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/intl-messageformat": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", + "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "tslib": "^2.1.0" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4957,6 +5559,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5023,8 +5630,7 @@ "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 + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -5046,7 +5652,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -5079,7 +5684,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -5109,6 +5713,158 @@ "node": ">=0.6.0" } }, + "node_modules/jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-compose": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.10.0.tgz", + "integrity": "sha512-F5kgtWpI2XfZ3Z8eP78tZEYFdgTIbpA/TMuX3a8vwrNolYtN1N4qJR/Ob0LAsqIwCMLojtxN7c7Oo/+Vz6THow==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-expand": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.10.0.tgz", + "integrity": "sha512-ymT62W2OyDxBxr7A6JR87vVX9vTq2ep5jZLIdUSusfBIEENLdkkc0lL/Xaq8W9s3opUq7R0sZQpzRWELrfVYzA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-extend": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.10.0.tgz", + "integrity": "sha512-sKYrcMfr4xxigmIwqTjxNcHwXJIfvhvjTNxF+Tbc1NmNdyspGW47Ey6sGH8BcQ4FFQhLXctpWCQSpDwdNmXSwg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-rule-value-observable": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.10.0.tgz", + "integrity": "sha512-ZLMaYrR3QE+vD7nl3oNXuj79VZl9Kp8/u6A1IbTPDcuOu8b56cFdWRZNZ0vNr8jHewooEeq2doy8Oxtymr2ZPA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "symbol-observable": "^1.2.0" + } + }, + "node_modules/jss-plugin-template": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.10.0.tgz", + "integrity": "sha512-ocXZBIOJOA+jISPdsgkTs8wwpK6UbsvtZK5JI7VUggTD6LWKbtoxUzadd2TpfF+lEtlhUmMsCkTRNkITdPKa6w==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, + "node_modules/jss-preset-default": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.10.0.tgz", + "integrity": "sha512-GL175Wt2FGhjE+f+Y3aWh+JioL06/QWFgZp53CbNNq6ZkVU0TDplD8Bxm9KnkotAYn3FlplNqoW5CjyLXcoJ7Q==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "jss-plugin-camel-case": "10.10.0", + "jss-plugin-compose": "10.10.0", + "jss-plugin-default-unit": "10.10.0", + "jss-plugin-expand": "10.10.0", + "jss-plugin-extend": "10.10.0", + "jss-plugin-global": "10.10.0", + "jss-plugin-nested": "10.10.0", + "jss-plugin-props-sort": "10.10.0", + "jss-plugin-rule-value-function": "10.10.0", + "jss-plugin-rule-value-observable": "10.10.0", + "jss-plugin-template": "10.10.0", + "jss-plugin-vendor-prefixer": "10.10.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", @@ -5118,14 +5874,12 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -5137,7 +5891,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "dependencies": { "yallist": "^3.0.2" } @@ -5164,6 +5917,11 @@ "node": ">= 0.6" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -5384,8 +6142,7 @@ "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/nodemon": { "version": "3.0.2", @@ -5516,6 +6273,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "engines": { + "node": ">= 10.12.0" + } + }, "node_modules/oidc-token-hash": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", @@ -5761,14 +6526,12 @@ "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 + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "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" }, @@ -5776,6 +6539,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "node_modules/postcss": { "version": "8.4.32", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", @@ -5804,6 +6572,11 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -5878,7 +6651,6 @@ "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", @@ -5888,8 +6660,7 @@ "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 + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -5998,7 +6769,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -6006,11 +6776,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-display-name": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", + "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" + }, + "node_modules/react-dnd": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", + "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", + "dependencies": { + "@react-dnd/shallowequal": "^2.0.0", + "@types/hoist-non-react-statics": "^3.3.1", + "dnd-core": "^11.1.3", + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "react": ">= 16.9.0", + "react-dom": ">= 16.9.0" + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz", + "integrity": "sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==", + "dependencies": { + "dnd-core": "^11.1.3" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -6019,11 +6816,99 @@ "react": "^18.2.0" } }, + "node_modules/react-intl": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-5.25.1.tgz", + "integrity": "sha512-pkjdQDvpJROoXLMltkP/5mZb0/XqrqLoPGKUCfbdkP8m6U9xbK40K51Wu+a4aQqTEvEK5lHBk0fWzUV72SJ3Hg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-messageformat-parser": "2.1.0", + "@formatjs/intl": "2.2.1", + "@formatjs/intl-displaynames": "5.4.3", + "@formatjs/intl-listformat": "6.5.3", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "16 || 17 || 18", + "hoist-non-react-statics": "^3.3.2", + "intl-messageformat": "9.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": "^16.3.0 || 17 || 18", + "typescript": "^4.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "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 + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.10.0.tgz", + "integrity": "sha512-WLiq84UYWqNBF6579/uprcIUnM1TSywYq6AIjKTTTG5ziJl9Uy+pwuvpN3apuyVwflMbD60PraeTKT7uWH9XEQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@emotion/is-prop-valid": "^0.7.3", + "css-jss": "10.10.0", + "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", + "jss": "10.10.0", + "jss-preset-default": "10.10.0", + "prop-types": "^15.6.0", + "shallow-equal": "^1.2.0", + "theming": "^3.3.0", + "tiny-warning": "^1.0.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/react-jss/node_modules/@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "dependencies": { + "@emotion/memoize": "0.7.1" + } + }, + "node_modules/react-jss/node_modules/@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" + }, + "node_modules/react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-refresh": { "version": "0.14.0", @@ -6070,7 +6955,6 @@ "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", @@ -6082,6 +6966,31 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-virtualized-auto-sizer": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.20.tgz", + "integrity": "sha512-OdIyHwj4S4wyhbKHOKM1wLSj/UDXm839Z3Cvfg2a9j+He6yDa6i5p0qQvEiCnyQlGO/HyfSnigQwuxvYalaAXA==", + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc" + } + }, + "node_modules/react-window": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz", + "integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -6107,11 +7016,34 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, + "node_modules/redux-watch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redux-watch/-/redux-watch-1.2.0.tgz", + "integrity": "sha512-Ws4Q+e5zFGMyy1H709c1Ws8apSd6MqoJRIzBDHbI4nikome/IZWVTYXdQNz+VJxPjyX/h2E+lYEo41fXgjCF8g==", + "dependencies": { + "object-path": "^0.11.5" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/request": { "version": "2.88.2", @@ -6183,6 +7115,11 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -6321,7 +7258,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -6399,6 +7335,16 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shell-quote": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", @@ -6408,6 +7354,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shortid": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", + "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "nanoid": "^2.1.0" + } + }, + "node_modules/shortid/node_modules/nanoid": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6666,6 +7626,40 @@ "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", "peer": true }, + "node_modules/styled-components": { + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", + "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^1.1.0", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -6676,7 +7670,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -6696,6 +7689,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tar": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", @@ -6717,11 +7718,32 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/theming": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz", + "integrity": "sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.3" + } + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -6784,6 +7806,11 @@ "tree-kill": "cli.js" } }, + "node_modules/tsdef": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/tsdef/-/tsdef-0.0.14.tgz", + "integrity": "sha512-UjMD4XKRWWFlFBfwKVQmGFT5YzW/ZaF8x6KpCDf92u9wgKeha/go3FU0e5WqDjXsCOdfiavCkfwfVHNDxRDGMA==" + }, "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", @@ -6845,7 +7872,6 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7137,8 +8163,7 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index 6d78841..62e7f28 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,8 @@ "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", + "chonky": "^2.3.2", + "chonky-icon-fontawesome": "^2.3.2", "express": "^4.18.2", "figlet": "^1.7.0", "js-yaml": "^4.1.0", diff --git a/src/components/edit/MineclusterFiles.jsx b/src/components/edit/MineclusterFiles.jsx new file mode 100644 index 0000000..b7f3067 --- /dev/null +++ b/src/components/edit/MineclusterFiles.jsx @@ -0,0 +1,55 @@ +import { useState, useEffect } from "react"; +import Box from "@mui/material/Box"; +import { + FileBrowser, + FileContextMenu, + FileList, + FileNavbar, + FileToolbar, + setChonkyDefaults, +} from "chonky"; +import { ChonkyIconFA } from "chonky-icon-fontawesome"; + +import { getServerFiles } from "@mcl/queries"; + +export default function MineclusterFiles(props) { + setChonkyDefaults({ iconComponent: ChonkyIconFA }); + const { server: serverName } = props; + const [dirStack, setDirStack] = useState(["."]); + const [files, setFiles] = useState([]); + useEffect(() => { + getServerFiles(serverName, dirStack.join("/")).then((f) => + setFiles(f ?? []), + ); + }, [dirStack]); + + const getFolderChain = () => { + if (dirStack.length === 1) return [{ id: "home", name: "/", isDir: true }]; + return dirStack.map((d, i) => ({ id: `${d}-${i}`, name: d, isDir: true })); + }; + + function fileClick(chonkyEvent) { + const { id: clickEvent, payload } = chonkyEvent; + console.log(chonkyEvent); + if (clickEvent === `open_parent_folder`) + return setDirStack(dirStack.slice(0, -1)); + if (clickEvent !== `open_files`) return console.log(clickEvent); + const { targetFile: file } = payload; + if (!file || !file.isDir) return; + setDirStack([...dirStack, file.name]); + } + return ( + + + + + + + + + ); +} diff --git a/src/components/servers/ServerCard.jsx b/src/components/servers/ServerCard.jsx index ac61a5c..4eec631 100644 --- a/src/components/servers/ServerCard.jsx +++ b/src/components/servers/ServerCard.jsx @@ -14,6 +14,8 @@ 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"; +import FolderIcon from "@mui/icons-material/Folder"; +import { Link } from "react-router-dom"; export default function ServerCard(props) { const { server, openRcon } = props; @@ -94,9 +96,24 @@ export default function ServerCard(props) { > - + + + + , component: , }, + { + name: "Edit", + path: "/mcl/files", + icon: , + component: , + }, ]; diff --git a/src/pages/Files.jsx b/src/pages/Files.jsx new file mode 100644 index 0000000..8c4780e --- /dev/null +++ b/src/pages/Files.jsx @@ -0,0 +1,20 @@ +import { useEffect } from "react"; +import { useSearchParams, useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import Toolbar from "@mui/material/Toolbar"; +import MineclusterFiles from "@mcl/components/edit/MineclusterFiles.jsx"; + +export default function Files() { + const [searchParams] = useSearchParams(); + const currentServer = searchParams.get("server"); + const nav = useNavigate(); + useEffect(() => { + if (!currentServer) nav("/"); + }, [currentServer]); + return ( + + + + ); +} diff --git a/src/util/queries.js b/src/util/queries.js index 4c0dc5a..e2a7047 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -30,6 +30,15 @@ export const useDeleteServer = (server) => postJsonApi("/server/delete", { name: server }, "server-instances", "DELETE"); export const useCreateServer = (spec) => postJsonApi("/server/create", spec, "server-list"); + +export const getServerFiles = async (server, dir) => + fetchApiPost("/files/list", { name: server, dir })(); + +export const useInvalidator = () => { + const qc = useQueryClient(); + return (q) => qc.invalidateQueries([q]); +}; + export const useServerList = () => useQuery({ queryKey: ["server-list"], queryFn: fetchApi("/server/list") }); export const useServerInstances = () => @@ -63,5 +72,6 @@ const postJsonApi = (subPath, body, invalidate, method = "POST") => { body: JSON.stringify(body), }); qc.invalidateQueries([invalidate]); + return res.json(); }; }; diff --git a/vite.config.js b/vite.config.js index fc924d1..3ed35cf 100644 --- a/vite.config.js +++ b/vite.config.js @@ -31,7 +31,7 @@ export default () => { "@mcl/settings": path.resolve("./src/ctx/SettingsContext.jsx"), "@mcl/pages": path.resolve("./src/pages"), "@mcl/queries": path.resolve("./src/util/queries.js"), - "@mcl/components": path.resolve("./src/components"), + "@mcl/components": path.resolve("./src/components"), "@mcl": path.resolve("./src"), }, }, From 22bf905415d1745cd065ff12209bb3e3e2891431 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Mon, 18 Dec 2023 22:58:56 -0700 Subject: [PATCH 15/56] [FEATURE] Initial File Manager --- lib/controllers/file-controller.js | 52 ++++++- lib/k8s/server-files.js | 86 ++++++++--- lib/routes/files-route.js | 16 +- src/components/edit/MineclusterFiles.jsx | 55 ------- .../files/ChonkyStyledFileBrowser.jsx | 42 +++++ src/components/files/MineclusterFiles.jsx | 144 ++++++++++++++++++ src/nav/MCLMenu.jsx | 2 +- src/pages/Files.jsx | 2 +- src/util/queries.js | 40 ++++- vite.config.js | 2 +- 10 files changed, 356 insertions(+), 85 deletions(-) delete mode 100644 src/components/edit/MineclusterFiles.jsx create mode 100644 src/components/files/ChonkyStyledFileBrowser.jsx create mode 100644 src/components/files/MineclusterFiles.jsx diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js index 88501d2..36aa0b0 100644 --- a/lib/controllers/file-controller.js +++ b/lib/controllers/file-controller.js @@ -1,4 +1,10 @@ -import { listServerFiles } from "../k8s/server-files.js"; +import { + createServerFolder, + getServerItem, + listServerFiles, + removeServerItem, + uploadServerItem, +} from "../k8s/server-files.js"; import { sendError } from "../util/ExpressClientError.js"; export async function listFiles(req, res) { @@ -15,10 +21,50 @@ export async function listFiles(req, res) { isSymLink: !!fi.link, size: fi.size, })); - console.log(fileData); res.json(fileData); }) .catch(sendError(res)); } -export async function uploadFile(req, res) {} +export async function createFolder(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + createServerFolder(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function deleteItem(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + if (serverSpec.isDir === undefined || serverSpec.isDir === null) + return res.status(400).send("IsDIr required!"); + removeServerItem(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function uploadItem(req, res) { + const serverSpec = req.body; + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + uploadServerItem(serverSpec, req.file) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function getItem(req, res) { + const serverSpec = req.body; + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + getServerItem(serverSpec, res) + .then(({ ds, ftpTransfer }) => { + ds.pipe(res).on("error", sendError(res)); + return ftpTransfer; + }) + .catch(sendError(res)); +} diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js index 516701d..ec1f7cc 100644 --- a/lib/k8s/server-files.js +++ b/lib/k8s/server-files.js @@ -2,10 +2,27 @@ import ftp from "basic-ftp"; import { ERR } from "../util/logging.js"; import { getServerAssets } from "./k8s-server-control.js"; import ExpressClientError from "../util/ExpressClientError.js"; +import { Readable, Writable, Transform } from "node:stream"; const namespace = process.env.MCL_SERVER_NAMESPACE; -export async function useFtp(serverService) { +const pathSecurityCheck = (path) => { + if (!path.startsWith(".")) + throw new ExpressClientError({ + m: "Only relative directories can be created", + c: 409, + }); +}; + +const handleError = (e) => { + ERR("SERVER FILES", "Error occurred while preforming FTP operation!", e); + throw new ExpressClientError({ + c: 500, + m: "Error occurred while performing FTP operation!", + }); +}; + +export async function getFtpClient(serverService) { const { name } = serverService.metadata; const client = new ftp.Client(); await client.access({ @@ -16,16 +33,8 @@ export async function useFtp(serverService) { return client; } -const handleError = (e) => { - ERR("SERVER FILES", "Error occurred while preforming FTP operation!", e); - throw new ExpressClientError({ - c: 500, - m: "Error occurred while performing FTP operation!", - }); -}; - -export async function listServerFiles(serverSpec) { - const { name, dir } = serverSpec; +export async function useServerFtp(serverSpec, fn) { + const { name } = serverSpec; const server = await getServerAssets(name); if (!server) throw new ExpressClientError({ @@ -37,15 +46,52 @@ export async function listServerFiles(serverSpec) { c: 409, m: "Service doesn't exist, please contact your hosting provider!", }); + const client = await getFtpClient(server.service); + const result = await fn(client); + client.close(); + return result; +} - // FTP Operations; - const client = await useFtp(server.service).catch(handleError); - const files = client - .list(dir) - .then((f) => { - client.close(); - return f; - }) - .catch(handleError); +export async function listServerFiles(serverSpec) { + const { path } = serverSpec; + const files = useServerFtp(serverSpec, async (c) => await c.list(path)).catch( + handleError, + ); return files; } + +export async function createServerFolder(serverSpec) { + const { path } = serverSpec; + pathSecurityCheck(path); + await useServerFtp(serverSpec, async (c) => c.ensureDir(path)).catch( + handleError, + ); +} + +export async function removeServerItem(serverSpec) { + const { path, isDir } = serverSpec; + pathSecurityCheck(path); + await useServerFtp(serverSpec, async (c) => { + if (isDir) await c.removeDir(path); + else await c.remove(path); + }).catch(handleError); +} + +export async function uploadServerItem(serverSpec, file) { + const fileStream = Readable.from(file.buffer); + const { path } = serverSpec; + pathSecurityCheck(path); + await useServerFtp(serverSpec, async (c) => { + await c.uploadFrom(fileStream, `${path}/${file.originalname}`); + }).catch(handleError); +} + +export async function getServerItem(serverSpec, writableStream) { + const { path } = serverSpec; + const ds = new Transform({ transform: (c, e, cb) => cb(null, c) }); + pathSecurityCheck(path); + const ftpTransfer = useServerFtp(serverSpec, async (c) => { + await c.downloadTo(ds, path); + }).catch(handleError); + return { ds, ftpTransfer }; +} diff --git a/lib/routes/files-route.js b/lib/routes/files-route.js index cab537e..c27c175 100644 --- a/lib/routes/files-route.js +++ b/lib/routes/files-route.js @@ -1,7 +1,21 @@ import { Router, json as jsonMiddleware } from "express"; -import { listFiles } from "../controllers/file-controller.js"; +import multer from "multer"; +import { + createFolder, + deleteItem, + listFiles, + uploadItem, + getItem, +} from "../controllers/file-controller.js"; + const router = Router(); router.use(jsonMiddleware()); +const multerMiddleware = multer(); + router.post("/list", listFiles); +router.post("/folder", createFolder); +router.delete("/item", deleteItem); +router.post("/item", getItem); +router.post("/upload", multerMiddleware.single("file"), uploadItem); export default router; diff --git a/src/components/edit/MineclusterFiles.jsx b/src/components/edit/MineclusterFiles.jsx deleted file mode 100644 index b7f3067..0000000 --- a/src/components/edit/MineclusterFiles.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import { useState, useEffect } from "react"; -import Box from "@mui/material/Box"; -import { - FileBrowser, - FileContextMenu, - FileList, - FileNavbar, - FileToolbar, - setChonkyDefaults, -} from "chonky"; -import { ChonkyIconFA } from "chonky-icon-fontawesome"; - -import { getServerFiles } from "@mcl/queries"; - -export default function MineclusterFiles(props) { - setChonkyDefaults({ iconComponent: ChonkyIconFA }); - const { server: serverName } = props; - const [dirStack, setDirStack] = useState(["."]); - const [files, setFiles] = useState([]); - useEffect(() => { - getServerFiles(serverName, dirStack.join("/")).then((f) => - setFiles(f ?? []), - ); - }, [dirStack]); - - const getFolderChain = () => { - if (dirStack.length === 1) return [{ id: "home", name: "/", isDir: true }]; - return dirStack.map((d, i) => ({ id: `${d}-${i}`, name: d, isDir: true })); - }; - - function fileClick(chonkyEvent) { - const { id: clickEvent, payload } = chonkyEvent; - console.log(chonkyEvent); - if (clickEvent === `open_parent_folder`) - return setDirStack(dirStack.slice(0, -1)); - if (clickEvent !== `open_files`) return console.log(clickEvent); - const { targetFile: file } = payload; - if (!file || !file.isDir) return; - setDirStack([...dirStack, file.name]); - } - return ( - - - - - - - - - ); -} diff --git a/src/components/files/ChonkyStyledFileBrowser.jsx b/src/components/files/ChonkyStyledFileBrowser.jsx new file mode 100644 index 0000000..3273684 --- /dev/null +++ b/src/components/files/ChonkyStyledFileBrowser.jsx @@ -0,0 +1,42 @@ +// ChonkyFullFileBrowser.tsx +import { forwardRef, memo } from "react"; +import { + StylesProvider, + createGenerateClassName, +} from "@material-ui/core/styles"; + +import { + FileBrowser, + FileList, + FileContextMenu, + FileNavbar, + FileToolbar, + setChonkyDefaults, + FileBrowserHandle, + FileBrowserProps, +} from "chonky"; + +import { ChonkyIconFA } from "chonky-icon-fontawesome"; + +setChonkyDefaults({ iconComponent: ChonkyIconFA }); + +const muiJSSClassNameGenerator = createGenerateClassName({ + // Seed property is used to add a prefix classes generated by material ui. + seed: "chonky", +}); + +export default memo( + forwardRef((props, ref) => { + const { onScroll } = props; + return ( + + + + + + + + + ); + }), +); diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx new file mode 100644 index 0000000..7b04e9a --- /dev/null +++ b/src/components/files/MineclusterFiles.jsx @@ -0,0 +1,144 @@ +import { useState, useEffect, useMemo, useRef } from "react"; +import Box from "@mui/material/Box"; +import { + FileBrowser, + FileContextMenu, + FileList, + FileNavbar, + FileToolbar, + setChonkyDefaults, + ChonkyActions, +} from "chonky"; +import { ChonkyIconFA } from "chonky-icon-fontawesome"; + +import { + getServerFiles, + createServerFolder, + deleteServerItem, + getServerItem, +} from "@mcl/queries"; + +export default function MineclusterFiles(props) { + // Chonky configuration + setChonkyDefaults({ iconComponent: ChonkyIconFA }); + const fileActions = useMemo( + () => [ + ChonkyActions.CreateFolder, + ChonkyActions.UploadFiles, + ChonkyActions.DownloadFiles, + ChonkyActions.CopyFiles, + ChonkyActions.DeleteFiles, + ], + [], + ); + const { server: serverName } = props; + const inputRef = useRef(null); + const [dirStack, setDirStack] = useState(["."]); + const [files, setFiles] = useState([]); + + const updateFiles = () => + getServerFiles(serverName, dirStack.join("/")).then((f) => + setFiles(f ?? []), + ); + + useEffect(() => { + updateFiles(); + }, [dirStack]); + + const getFolderChain = () => { + if (dirStack.length === 1) return [{ id: "home", name: "/", isDir: true }]; + return dirStack.map((d, i) => ({ id: `${d}-${i}`, name: d, isDir: true })); + }; + + const openParentFolder = () => setDirStack(dirStack.slice(0, -1)); + + function openFolder(payload) { + const { targetFile: file } = payload; + if (!file || !file.isDir) return; + setDirStack([...dirStack, file.name]); + } + + function createFolder() { + const name = prompt("What is the name of the new folder?"); + const path = [...dirStack, name].join("/"); + createServerFolder(serverName, path).then(updateFiles); + } + + function deleteItems(files) { + Promise.all( + files.map((f) => + deleteServerItem(serverName, [...dirStack, f.name].join("/"), f.isDir), + ), + ) + .catch((e) => console.error("Error deleting some files!", e)) + .then(updateFiles); + } + + function uploadFileSelection(e) { + if (!e.target.files || e.target.files.length === 0) return; + const { files } = e.target; + Promise.all([...files].map((f) => uploadFile(f))) + .catch((e) => console.log("Error uploading a file", e)) + .then(updateFiles); + } + + async function uploadFile(file) { + const formData = new FormData(); + formData.append("file", file); + formData.append("name", serverName); + formData.append("path", [...dirStack, name].join("/")); + await fetch("/api/files/upload", { + method: "POST", + body: formData, + }); + } + + async function downloadFiles(files) { + Promise.all( + files.map((f) => + getServerItem(serverName, f.name, [...dirStack, f.name].join("/")), + ), + ) + .then(() => console.log("Done")) + .catch((e) => console.error("Error Downloading files!", e)); + } + + function fileClick(chonkyEvent) { + const { id: clickEvent, payload } = chonkyEvent; + console.log(chonkyEvent); + if (clickEvent === "open_parent_folder") return openParentFolder(); + if (clickEvent === "create_folder") return createFolder(); + if (clickEvent === "upload_files") return inputRef.current.click(); + if (clickEvent === "download_files") + return downloadFiles(chonkyEvent.state.selectedFilesForAction); + if (clickEvent === "delete_files") + return deleteItems(chonkyEvent.state.selectedFilesForAction); + if (clickEvent !== "open_files") return console.log(clickEvent); + openFolder(payload); + } + return ( + + + + + + + + + + + ); +} diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index 2c58fbf..fc36cf6 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -40,7 +40,7 @@ export default function MCLMenu() { position="fixed" color="primary" sx={{ zIndex: drawerIndex(), bgcolor: "black" }} - enableColorOnDark={false} + enableColorOnDark={true} > diff --git a/src/pages/Files.jsx b/src/pages/Files.jsx index 8c4780e..2794530 100644 --- a/src/pages/Files.jsx +++ b/src/pages/Files.jsx @@ -3,7 +3,7 @@ import { useSearchParams, useNavigate } from "react-router-dom"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import Toolbar from "@mui/material/Toolbar"; -import MineclusterFiles from "@mcl/components/edit/MineclusterFiles.jsx"; +import MineclusterFiles from "@mcl/components/files/MineclusterFiles.jsx"; export default function Files() { const [searchParams] = useSearchParams(); diff --git a/src/util/queries.js b/src/util/queries.js index e2a7047..fa06c61 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -2,6 +2,15 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; const fetchApi = (subPath) => async () => fetch(`/api${subPath}`).then((res) => res.json()); +const fetchApiCore = async (subPath, json, method = "POST", jsonify = false) => + fetch(`/api${subPath}`, { + method, + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(json), + }).then((res) => (jsonify ? res.json() : res)); + const fetchApiPost = (subPath, json) => async () => fetch(`/api${subPath}`, { method: "POST", @@ -31,8 +40,33 @@ export const useDeleteServer = (server) => export const useCreateServer = (spec) => postJsonApi("/server/create", spec, "server-list"); -export const getServerFiles = async (server, dir) => - fetchApiPost("/files/list", { name: server, dir })(); +export const getServerFiles = async (server, path) => + fetchApiCore("/files/list", { name: server, path }, "POST", true); +export const createServerFolder = async (server, path) => + fetchApiCore("/files/folder", { + name: server, + path, + }); /*postJsonApi("/files/folder", {name: server, path});*/ +export const deleteServerItem = async (server, path, isDir) => + fetchApiCore("/files/item", { name: server, path, isDir }, "DELETE"); + +export const getServerItem = async (server, name, path) => + fetchApiCore("/files/item", { name: server, path }) + .then((resp) => + resp.status === 200 + ? resp.blob() + : Promise.reject("something went wrong"), + ) + .then((blob) => { + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.style.display = "none"; + a.href = url; + a.download = name; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + }); export const useInvalidator = () => { const qc = useQueryClient(); @@ -71,7 +105,7 @@ const postJsonApi = (subPath, body, invalidate, method = "POST") => { }, body: JSON.stringify(body), }); - qc.invalidateQueries([invalidate]); + if (invalidate) qc.invalidateQueries([invalidate]); return res.json(); }; }; diff --git a/vite.config.js b/vite.config.js index 3ed35cf..5d25a00 100644 --- a/vite.config.js +++ b/vite.config.js @@ -31,7 +31,7 @@ export default () => { "@mcl/settings": path.resolve("./src/ctx/SettingsContext.jsx"), "@mcl/pages": path.resolve("./src/pages"), "@mcl/queries": path.resolve("./src/util/queries.js"), - "@mcl/components": path.resolve("./src/components"), + "@mcl/components": path.resolve("./src/components"), "@mcl": path.resolve("./src"), }, }, From 12d198456cdb92a6e6ec9cd7f267510476eb8f49 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Tue, 19 Dec 2023 11:39:01 -0700 Subject: [PATCH 16/56] [FEATURE] Server service containerization --- lib/controllers/lifecycle-controller.js | 14 ++-- .../migrations/1_create_servers_table.sql | 8 ++- lib/database/queries/server-queries.js | 34 +++++++++ lib/k8s/configs/containers/ftp-server.yml | 4 +- .../configs/containers/minecraft-server.yml | 20 +++--- lib/k8s/k8s-server-control.js | 32 +++++++-- lib/k8s/server-containers.js | 67 +++++++++++++++++ lib/k8s/server-control.js | 6 +- lib/k8s/server-create.js | 71 ++----------------- 9 files changed, 165 insertions(+), 91 deletions(-) create mode 100644 lib/database/queries/server-queries.js create mode 100644 lib/k8s/server-containers.js diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 6984fc0..9931555 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -1,10 +1,12 @@ import createServerResources from "../k8s/server-create.js"; import deleteServerResources from "../k8s/server-delete.js"; +import { createServerEntry } from "../database/queries/server-queries.js"; import { sendError } from "../util/ExpressClientError.js"; import { startServerContainer, stopServerContainer, } from "../k8s/server-control.js"; +import { toggleServer } from "../k8s/k8s-server-control.js"; function payloadFilter(req, res) { const serverSpec = req.body; @@ -32,8 +34,10 @@ function checkServerName(serverSpec) { export function createServer(req, res) { if (payloadFilter(req, res) !== "filtered") return; const serverSpec = req.body; - createServerResources(serverSpec) - .then(() => res.sendStatus(200)) + createServerEntry(serverSpec) + .then(() => + createServerResources(serverSpec).then(() => res.sendStatus(200)), + ) .catch(sendError(res)); } @@ -59,7 +63,8 @@ export async function startServer(req, res) { } catch (e) { return sendError(res)(e); } - startServerContainer(serverSpec) + const { name } = serverSpec; + toggleServer(name, true) .then(() => res.sendStatus(200)) .catch(sendError(res)); } @@ -72,7 +77,8 @@ export async function stopServer(req, res) { } catch (e) { return sendError(res)(e); } - stopServerContainer(serverSpec) + const { name } = serverSpec; + toggleServer(name, false) .then(() => res.sendStatus(200)) .catch(sendError(res)); } diff --git a/lib/database/migrations/1_create_servers_table.sql b/lib/database/migrations/1_create_servers_table.sql index 375eafd..5306630 100644 --- a/lib/database/migrations/1_create_servers_table.sql +++ b/lib/database/migrations/1_create_servers_table.sql @@ -1,8 +1,12 @@ -/*CREATE SEQUENCE servers_id_seq; +CREATE SEQUENCE servers_id_seq; CREATE TABLE servers ( id bigint NOT NULL DEFAULT nextval('servers_id_seq') PRIMARY KEY, name varchar(255) DEFAULT NULL, host varchar(255) DEFAULT NULL, + version varchar(63) DEFAULT 'latest', + server_type varchar(63) DEFAULT 'VANILLA', + memory varchar(63) DEFAULT '512', + CONSTRAINT unique_name UNIQUE(name), CONSTRAINT unique_host UNIQUE(host) ); -ALTER SEQUENCE servers_id_seq OWNED BY servers.id;*/ \ No newline at end of file +ALTER SEQUENCE servers_id_seq OWNED BY servers.id; \ No newline at end of file diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js new file mode 100644 index 0000000..239b8a8 --- /dev/null +++ b/lib/database/queries/server-queries.js @@ -0,0 +1,34 @@ +import pg from "../postgres.js"; +import { insertQuery, selectWhereQuery } from "../pg-query.js"; +import ExpressClientError from "../../util/ExpressClientError.js"; +const table = "servers"; + +const asExpressClientError = (e) => { + throw new ExpressClientError({ m: e.message, c: 409 }); +}; + +export async function createServerEntry(serverSpec) { + const { name, host, version, serverType: server_type, memory } = serverSpec; + const q = insertQuery(table, { name, host, version, server_type, memory }); + return pg.query(q).catch(asExpressClientError); +} + +export async function getServerEntry(serverName) { + if (!serverName) asExpressClientError({ message: "Server Name Required!" }); + const q = selectWhereQuery(table, { name: serverName }); + try { + const serverSpecs = await pg.query(q); + if (!serverSpecs.length === 1) + throw Error("Multiple servers found with the same name!"); + const { + name, + host, + version, + server_type: serverType, + memory, + } = serverSpecs[0]; + return { name, host, version, serverType, memory }; + } catch (e) { + asExpressClientError(e); + } +} diff --git a/lib/k8s/configs/containers/ftp-server.yml b/lib/k8s/configs/containers/ftp-server.yml index de6f49e..759bc20 100644 --- a/lib/k8s/configs/containers/ftp-server.yml +++ b/lib/k8s/configs/containers/ftp-server.yml @@ -25,8 +25,8 @@ readinessProbe: timeoutSeconds: 1 resources: requests: - cpu: 500m - memory: 512Mi + cpu: 50m + memory: 64Mi stdin: true terminationMessagePath: /dev/termination-log terminationMessagePolicy: File diff --git a/lib/k8s/configs/containers/minecraft-server.yml b/lib/k8s/configs/containers/minecraft-server.yml index 09bcb90..4034e36 100644 --- a/lib/k8s/configs/containers/minecraft-server.yml +++ b/lib/k8s/configs/containers/minecraft-server.yml @@ -1,15 +1,23 @@ env: + # System Values + - name: JVM_OPTS + - name: JVM_XX_OPTS + - name: OVERRIDE_SERVER_PROPERTIES + value: "false" - name: EULA value: "TRUE" + # Updated at recreation + - name: MEMORY + value: 1024M - name: TYPE value: VANILLA - name: VERSION value: "latest" + # Set at creation but not updated on recreation - name: DIFFICULTY value: easy - name: WHITELIST - name: OPS - - name: ICON - name: MAX_PLAYERS value: "20" - name: MAX_WORLD_SIZE @@ -52,16 +60,8 @@ env: - name: GENERATOR_SETTINGS - name: LEVEL value: world - # - name: MODPACK - # value: https://somemodpack.com - 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 @@ -80,7 +80,7 @@ livenessProbe: periodSeconds: 5 successThreshold: 1 timeoutSeconds: 1 -name: changeme-name +name: changeme-name-server ports: - containerPort: 25565 name: minecraft diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js index fc45560..4e5233d 100644 --- a/lib/k8s/k8s-server-control.js +++ b/lib/k8s/k8s-server-control.js @@ -1,5 +1,12 @@ import k8s from "@kubernetes/client-node"; +import yaml from "js-yaml"; import { VERB, ERR } from "../util/logging.js"; +import { getServerEntry } from "../database/queries/server-queries.js"; +import { + getFtpContainer, + getCoreServerContainer, + getBackupContainer, +} from "./server-containers.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -8,6 +15,8 @@ const k8sCore = kc.makeApiClient(k8s.CoreV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; +const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); + const mineclusterManaged = (o) => o.metadata && o.metadata.annotations && @@ -93,13 +102,26 @@ export async function getContainers(serverName) { return deployment.spec.template.spec.containers; } +async function containerControl(serverName, deployment, scaleUp) { + const { containers } = deployment.spec.template.spec; + const depFtp = containers.find((c) => c.name.endsWith("-ftp")); + const depServer = containers.find((c) => c.name.endsWith("-server")); + const depBackup = containers.find((c) => c.name.endsWith("-backup")); + const serverSpec = await getServerEntry(serverName); + const ftpContainer = depFtp ?? getFtpContainer(serverSpec); + const serverContainer = depServer ?? getCoreServerContainer(serverSpec); + const backupContainer = depBackup ?? getBackupContainer(serverSpec); + if (scaleUp) return [ftpContainer, serverContainer]; + return [ftpContainer]; +} + export async function toggleServer(serverName, scaleUp = false) { const deployment = await getDeployment(serverName); - const { containers } = deployment.spec.template.spec; - const ftpContainer = containers.find((c) => c.name.endsWith("-ftp")); - - res.sendStatus(200); - deployment.spec.template.spec.containers = containers; + deployment.spec.template.spec.containers = await containerControl( + serverName, + deployment, + scaleUp, + ); return k8sDeps.replaceNamespacedDeployment( deployment.metadata.name, namespace, diff --git a/lib/k8s/server-containers.js b/lib/k8s/server-containers.js new file mode 100644 index 0000000..4694828 --- /dev/null +++ b/lib/k8s/server-containers.js @@ -0,0 +1,67 @@ +import fs from "node:fs"; +import path from "node:path"; +import yaml from "js-yaml"; +const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); + +export function getFtpContainer(serverSpec) { + const { name } = serverSpec; + const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); + ftpContainer.name = `mcl-${name}-ftp`; + const ftpPortList = [ + { p: 20, n: "ftp-data" }, + { p: 21, n: "ftp-commands" }, + ]; + for (var p = 40000; p <= 40009; p++) + ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); + ftpContainer.ports = ftpPortList.map(({ p: containerPort, n: name }) => ({ + containerPort, + name, + protocol: "TCP", + })); + return ftpContainer; +} + +export function getCoreServerContainer(serverSpec) { + const { name, version, serverType, memory } = serverSpec; + const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml"); + // Container Updates + container.name = `mcl-${name}-server`; + container.resources.requests.memory = `${memory}Mi`; + + const findEnv = (k) => container.env.find(({ name: n }) => n === k); + const updateEnv = (k, v) => (findEnv(k).value = v); + + // Enviornment variables + updateEnv("TYPE", serverType); + updateEnv("VERSION", version); + updateEnv("MEMORY", `${memory}M`); + // RCON + const rs = `mcl-${name}-rcon-secret`; + findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + return container; +} + +export function getServerContainer(serverSpec) { + const { difficulty, gamemode, motd, maxPlayers, seed, ops, whitelist } = + serverSpec; + const container = getCoreServerContainer(serverSpec); + + const findEnv = (k) => container.env.find(({ name: n }) => n === k); + const updateEnv = (k, v) => (findEnv(k).value = v); + + // Enviornment variables + updateEnv("DIFFICULTY", difficulty); + updateEnv("MODE", gamemode); + updateEnv("MOTD", motd); + updateEnv("MAX_PLAYERS", maxPlayers); + updateEnv("SEED", seed); + updateEnv("OPS", ops); + updateEnv("WHITELIST", whitelist); + + return container; +} + +export function getBackupContainer(serverSpec) { + const container = loadYaml("lib/k8s/configs/containers/minecraft-backup.yml"); + return container; +} diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js index f1d868e..63097e6 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -47,11 +47,13 @@ export async function getInstances() { const serverInstances = serverDeployments.map((s) => { name = s.metadata.annotations["minecluster.dunemask.net/server-name"]; metrics = null; - started = !!s.spec.replicas; + started = !!s.spec.template.spec.containers.find((c) => + c.name.includes(`mcl-${name}-server`), + ); const pod = podMetricsResponse.items.find(({ metadata: md }) => { return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`; }); - if (pod) { + if (started && pod) { const podCpus = pod.containers.map( ({ usage }) => parseInt(usage.cpu) / 1_000_000, ); diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 159811b..d929f1c 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -5,6 +5,11 @@ import yaml from "js-yaml"; import fs from "node:fs"; import path from "node:path"; import ExpressClientError from "../util/ExpressClientError.js"; +import { + getFtpContainer, + getServerContainer, + getBackupContainer, +} from "./server-containers.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -39,72 +44,6 @@ function createServerVolume(serverSpec) { return volumeYaml; } -function getFtpContainer(serverSpec) { - const { name } = serverSpec; - const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); - ftpContainer.name = `mcl-${name}-ftp`; - const ftpPortList = [ - { p: 20, n: "ftp-data" }, - { p: 21, n: "ftp-commands" }, - ]; - for (var p = 40000; p <= 40009; p++) - ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); - ftpContainer.ports = ftpPortList.map(({ p: containerPort, n: name }) => ({ - containerPort, - name, - protocol: "TCP", - })); - return ftpContainer; -} - -function getServerContainer(serverSpec) { - const { - name, - version, - serverType, - difficulty, - gamemode, - memory, - motd, - maxPlayers, - seed, - ops, - whitelist, - } = serverSpec; - const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml"); - - // Container Updates - container.name = `mcl-${name}-server`; - container.resources.requests.memory = `${memory}Mi`; - // container.resources.limits.memory = `${memory}Mi`; // TODO Allow for limits beyond initial startup - - const findEnv = (k) => container.env.find(({ name: n }) => n === k); - const updateEnv = (k, v) => (findEnv(k).value = v); - - // Enviornment variables - updateEnv("TYPE", serverType); - updateEnv("VERSION", version); - updateEnv("DIFFICULTY", difficulty); - updateEnv("MODE", gamemode); - updateEnv("MOTD", motd); - updateEnv("MAX_PLAYERS", maxPlayers); - updateEnv("SEED", seed); - updateEnv("OPS", ops); - updateEnv("WHITELIST", whitelist); - updateEnv("MEMORY", `${memory}M`); - - // RCON - const rs = `mcl-${name}-rcon-secret`; - findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; - - return container; -} - -function getBackupContainer(serverSpec) { - const container = loadYaml("lib/k8s/configs/containers/minecraft-backup.yml"); - return container; -} - function createServerDeploy(serverSpec) { const { name } = serverSpec; const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); From 5a1a89342ecf7bd1e0151473299453a50902b333 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Tue, 19 Dec 2023 14:05:59 -0700 Subject: [PATCH 17/56] [CHORE] Fix styling inconsistencies --- lib/controllers/lifecycle-controller.js | 4 +-- lib/k8s/server-create.js | 19 +++++++++----- src/components/files/MineclusterFiles.jsx | 2 ++ src/css/header.css | 31 +++++++++++++++++++++++ src/nav/MCLMenu.jsx | 25 ++++++++---------- src/pages/CreateOptions.jsx | 4 +-- 6 files changed, 59 insertions(+), 26 deletions(-) create mode 100644 src/css/header.css diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 9931555..3298abf 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -11,10 +11,10 @@ import { toggleServer } from "../k8s/k8s-server-control.js"; function payloadFilter(req, res) { const serverSpec = req.body; if (!serverSpec) return res.sendStatus(400); - const { name, url, version, serverType, difficulty, gamemode, memory } = + const { name, host, 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 (!host) return res.status(400).send("Server host is required!"); if (!version) return res.status(400).send("Server version is required!"); if (!difficulty) return res.status(400).send("Server difficulty is required!"); diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index d929f1c..8ef2fe3 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -45,7 +45,7 @@ function createServerVolume(serverSpec) { } function createServerDeploy(serverSpec) { - const { name } = serverSpec; + const { name, host } = serverSpec; const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); const { metadata } = deployYaml; const serverContainer = getServerContainer(serverSpec); @@ -67,24 +67,27 @@ function createServerDeploy(serverSpec) { ({ name }) => name === "datadir", ).persistentVolumeClaim.claimName = `mcl-${name}-volume`; - // Apply Containers + // Apply Containers TODO: User control for autostart deployYaml.spec.template.spec.containers.push(serverContainer); deployYaml.spec.template.spec.containers.push(ftpContainer); - // TODO: User control for autostart - deployYaml.spec.replicas = 0; + deployYaml.spec.replicas = 1; return deployYaml; } function createServerService(serverSpec) { - const { name, url } = serverSpec; + const { name, host } = serverSpec; const serviceYaml = loadYaml("lib/k8s/configs/server-svc.yml"); - serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = url; + serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = host; + serviceYaml.metadata.annotations["mc-router.itzg.me/externalServerName"] = + host; serviceYaml.metadata.labels.app = `mcl-${name}-app`; serviceYaml.metadata.name = `mcl-${name}-server`; serviceYaml.metadata.namespace = namespace; serviceYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = name; serviceYaml.spec.selector.app = `mcl-${name}-app`; + // Port List: + const serverPortList = [{ p: 25565, n: "minecraft" }]; // Apply FTP Port List const ftpPortList = [ @@ -93,7 +96,9 @@ function createServerService(serverSpec) { ]; for (var p = 40000; p <= 40009; p++) ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); - serviceYaml.spec.ports = ftpPortList.map(({ p: port, n: name }) => ({ + + const portList = [...serverPortList, ...ftpPortList]; + serviceYaml.spec.ports = portList.map(({ p: port, n: name }) => ({ port, name, protocol: "TCP", diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx index 7b04e9a..6c0079d 100644 --- a/src/components/files/MineclusterFiles.jsx +++ b/src/components/files/MineclusterFiles.jsx @@ -18,6 +18,8 @@ import { getServerItem, } from "@mcl/queries"; +import "@mcl/css/header.css"; + export default function MineclusterFiles(props) { // Chonky configuration setChonkyDefaults({ iconComponent: ChonkyIconFA }); diff --git a/src/css/header.css b/src/css/header.css new file mode 100644 index 0000000..15d51e4 --- /dev/null +++ b/src/css/header.css @@ -0,0 +1,31 @@ +.appbar-items { + font-size: 1.25rem; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-weight: 500; + line-height: 1.6; + letter-spacing: 0.0075em; +} + +.view > header { + transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + box-shadow: + 0px 2px 4px -1px rgba(0, 0, 0, 0.2), + 0px 4px 5px 0px rgba(0, 0, 0, 0.14), + 0px 1px 10px 0px rgba(0, 0, 0, 0.12); + display: flex; + flex-direction: column; + width: 100%; + box-sizing: border-box; + flex-shrink: 0; + position: fixed; + top: 0; + left: auto; + right: 0; + color: rgba(0, 0, 0, 0.87); + z-index: 1302; + background-color: black; +} +.view > header > div > div > a { + height: 40px; + width: 40px; +} diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index fc36cf6..3d6e7c2 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -42,22 +42,17 @@ export default function MCLMenu() { sx={{ zIndex: drawerIndex(), bgcolor: "black" }} enableColorOnDark={true} > - + - - - - - - {navHeader()}{" "} - - + + + + + {navHeader()} + diff --git a/src/pages/CreateOptions.jsx b/src/pages/CreateOptions.jsx index b5993cf..bb38323 100644 --- a/src/pages/CreateOptions.jsx +++ b/src/pages/CreateOptions.jsx @@ -97,7 +97,7 @@ export default function Create() { 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"); + if (!spec.host) return alertValidationError("Host cannot be blank"); return "validated"; } @@ -121,7 +121,7 @@ export default function Create() { /> Date: Tue, 19 Dec 2023 20:10:57 -0700 Subject: [PATCH 18/56] [FEATURE] Allow deleting of servers from the DB --- lib/controllers/lifecycle-controller.js | 27 ++++++++++++++++--------- lib/database/queries/server-queries.js | 9 ++++++++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 3298abf..5b0105e 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -1,6 +1,10 @@ import createServerResources from "../k8s/server-create.js"; import deleteServerResources from "../k8s/server-delete.js"; -import { createServerEntry } from "../database/queries/server-queries.js"; +import { + createServerEntry, + deleteServerEntry, + getServerEntry, +} from "../database/queries/server-queries.js"; import { sendError } from "../util/ExpressClientError.js"; import { startServerContainer, @@ -31,14 +35,18 @@ function checkServerName(serverSpec) { throw new ExpressClientError({ c: 400, m: "Server name required!" }); } -export function createServer(req, res) { +export async function createServer(req, res) { if (payloadFilter(req, res) !== "filtered") return; const serverSpec = req.body; - createServerEntry(serverSpec) - .then(() => - createServerResources(serverSpec).then(() => res.sendStatus(200)), - ) - .catch(sendError(res)); + try { + const serverSpecs = await getServerEntry(serverSpec.name); + if (serverSpecs.length !== 0) throw Error("Server already exists in DB!"); + await createServerResources(serverSpec); + await createServerEntry(serverSpec); + res.sendStatus(200); + } catch (e) { + sendError(res)(e); + } } export async function deleteServer(req, res) { @@ -49,8 +57,9 @@ export async function deleteServer(req, res) { } catch (e) { return sendError(res)(e); } - - deleteServerResources(serverSpec) + const deleteEntry = deleteServerEntry(serverSpec.name); + const deleteResources = deleteServerResources(serverSpec); + Promise.all([deleteEntry, deleteResources]) .then(() => res.sendStatus(200)) .catch(sendError(res)); } diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index 239b8a8..d8baa8f 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -1,5 +1,5 @@ import pg from "../postgres.js"; -import { insertQuery, selectWhereQuery } from "../pg-query.js"; +import { deleteQuery, insertQuery, selectWhereQuery } from "../pg-query.js"; import ExpressClientError from "../../util/ExpressClientError.js"; const table = "servers"; @@ -13,11 +13,18 @@ export async function createServerEntry(serverSpec) { return pg.query(q).catch(asExpressClientError); } +export async function deleteServerEntry(serverName) { + if (!serverName) asExpressClientError({ message: "Server Name Required!" }); + const q = deleteQuery(table, { name: serverName }); + return pg.query(q).catch(asExpressClientError); +} + export async function getServerEntry(serverName) { if (!serverName) asExpressClientError({ message: "Server Name Required!" }); const q = selectWhereQuery(table, { name: serverName }); try { const serverSpecs = await pg.query(q); + if (serverSpecs.length === 0) return []; if (!serverSpecs.length === 1) throw Error("Multiple servers found with the same name!"); const { From 4f19cf19d9662209079d7517cd6777de9ae5b280 Mon Sep 17 00:00:00 2001 From: dunemask Date: Wed, 20 Dec 2023 03:20:04 +0000 Subject: [PATCH 19/56] [FEATURE] Basic System with file manager (#4) Co-authored-by: dunemask Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/4 --- dist/app.js | 8 +- lib/Minecluster.js | 5 +- lib/controllers/file-controller.js | 70 + lib/controllers/lifecycle-controller.js | 93 + lib/controllers/status-controller.js | 18 + .../sub-controllers/console-controller.js | 65 + .../migrations/1_create_servers_table.sql | 12 + lib/database/pg-query.js | 121 + lib/database/postgres.js | 63 + lib/database/queries/server-queries.js | 41 + lib/index.js | 0 lib/k8s.js | 8 - lib/k8s/configs/containers/ftp-server.yml | 36 + .../configs/containers/minecraft-backup.yml | 63 + .../configs/containers/minecraft-server.yml | 113 + lib/k8s/configs/rcon-secret.yml | 2 + lib/k8s/configs/rcon-svc.yml | 1 + lib/k8s/configs/server-deployment.yml | 187 +- lib/k8s/configs/server-pvc.yml | 2 + lib/k8s/configs/server-svc.yml | 7 +- lib/k8s/k8s-server-control.js | 146 + lib/k8s/live-logging.js | 30 - lib/k8s/server-containers.js | 67 + lib/k8s/server-control.js | 101 +- lib/k8s/server-create.js | 160 +- lib/k8s/server-delete.js | 65 +- lib/k8s/server-files.js | 97 + lib/routes/error-route.js | 17 + lib/routes/files-route.js | 21 + lib/routes/react-route.js | 2 +- lib/routes/server-route.js | 12 +- lib/routes/system-route.js | 2 + lib/server/rcon.js | 31 - lib/server/router.js | 12 +- lib/server/sockets.js | 12 +- lib/storage/s3-integration.js | 34 + lib/util/ExpressClientError.js | 28 + package-lock.json | 4445 +++++++++++++++-- package.json | 35 +- src/MCL.jsx | 10 +- .../files/ChonkyStyledFileBrowser.jsx | 42 + src/components/files/MineclusterFiles.jsx | 146 + src/{ => components}/overview/Overview.jsx | 0 .../overview/OverviewVisual.jsx | 0 src/{ => components}/servers/RconDialog.jsx | 0 src/{ => components}/servers/RconSocket.js | 0 src/{ => components}/servers/RconView.jsx | 0 src/{ => components}/servers/ServerCard.jsx | 19 +- src/css/header.css | 31 + {public => src}/css/overview.css | 0 {public => src}/css/rcon.css | 0 {public => src}/css/server-card.css | 0 src/nav/MCLMenu.jsx | 55 +- src/nav/MCLPages.jsx | 7 + src/nav/Viewport.jsx | 2 + src/pages/Create.jsx | 150 +- src/pages/CreateOptions.jsx | 248 + src/pages/Files.jsx | 20 + src/pages/Home.jsx | 31 +- src/util/queries.js | 87 +- src/util/theme.js | 16 + vite.config.js | 4 +- 62 files changed, 5910 insertions(+), 1190 deletions(-) create mode 100644 lib/controllers/file-controller.js create mode 100644 lib/controllers/lifecycle-controller.js create mode 100644 lib/controllers/status-controller.js create mode 100644 lib/controllers/sub-controllers/console-controller.js create mode 100644 lib/database/migrations/1_create_servers_table.sql create mode 100644 lib/database/pg-query.js create mode 100644 lib/database/postgres.js create mode 100644 lib/database/queries/server-queries.js delete mode 100644 lib/index.js delete mode 100644 lib/k8s.js create mode 100644 lib/k8s/configs/containers/ftp-server.yml create mode 100644 lib/k8s/configs/containers/minecraft-backup.yml create mode 100644 lib/k8s/configs/containers/minecraft-server.yml create mode 100644 lib/k8s/k8s-server-control.js delete mode 100644 lib/k8s/live-logging.js create mode 100644 lib/k8s/server-containers.js create mode 100644 lib/k8s/server-files.js create mode 100644 lib/routes/error-route.js create mode 100644 lib/routes/files-route.js delete mode 100644 lib/server/rcon.js create mode 100644 lib/storage/s3-integration.js create mode 100644 lib/util/ExpressClientError.js create mode 100644 src/components/files/ChonkyStyledFileBrowser.jsx create mode 100644 src/components/files/MineclusterFiles.jsx rename src/{ => components}/overview/Overview.jsx (100%) rename src/{ => components}/overview/OverviewVisual.jsx (100%) rename src/{ => components}/servers/RconDialog.jsx (100%) rename src/{ => components}/servers/RconSocket.js (100%) rename src/{ => components}/servers/RconView.jsx (100%) rename src/{ => components}/servers/ServerCard.jsx (86%) create mode 100644 src/css/header.css rename {public => src}/css/overview.css (100%) rename {public => src}/css/rcon.css (100%) rename {public => src}/css/server-card.css (100%) create mode 100644 src/pages/CreateOptions.jsx create mode 100644 src/pages/Files.jsx create mode 100644 src/util/theme.js diff --git a/dist/app.js b/dist/app.js index 74122c5..2f46e88 100644 --- a/dist/app.js +++ b/dist/app.js @@ -1,4 +1,3 @@ -import stream from "stream"; import k8s from "@kubernetes/client-node"; import Minecluster from "../lib/Minecluster.js"; const mcl = new Minecluster(); @@ -7,11 +6,6 @@ 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)}); diff --git a/lib/Minecluster.js b/lib/Minecluster.js index 0fa918b..983371e 100644 --- a/lib/Minecluster.js +++ b/lib/Minecluster.js @@ -7,6 +7,7 @@ import { INFO, OK, logInfo } from "./util/logging.js"; // Import Core Modules import buildRoutes from "./server/router.js"; import injectSockets from "./server/sockets.js"; +import pg from "./database/postgres.js"; // Constants const title = "MCL"; @@ -23,6 +24,7 @@ export default class Minecluster { logInfo(fig.textSync(title, "Larry 3D")); INFO("INIT", "Initializing..."); this.app = express(); + this.pg = pg; this.server = http.createServer(this.app); this.sockets = injectSockets(this.server, this.jobs); this.routes = buildRoutes(this.sockets); @@ -31,11 +33,12 @@ export default class Minecluster { } async _connect() { - // await this.pg.connect(); + await this.pg.connect(); } start() { const mcl = this; + return new Promise(async function init(res) { mcl._preinitialize(); await mcl._connect(); diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js new file mode 100644 index 0000000..36aa0b0 --- /dev/null +++ b/lib/controllers/file-controller.js @@ -0,0 +1,70 @@ +import { + createServerFolder, + getServerItem, + listServerFiles, + removeServerItem, + uploadServerItem, +} from "../k8s/server-files.js"; +import { sendError } from "../util/ExpressClientError.js"; + +export async function listFiles(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + listServerFiles(serverSpec) + .then((f) => { + const fileData = f.map((fi, i) => ({ + name: fi.name, + isDir: fi.type === 2, + id: `${fi.name}-${i}`, + isHidden: fi.name.startsWith("."), + isSymLink: !!fi.link, + size: fi.size, + })); + res.json(fileData); + }) + .catch(sendError(res)); +} + +export async function createFolder(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + createServerFolder(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function deleteItem(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + if (serverSpec.isDir === undefined || serverSpec.isDir === null) + return res.status(400).send("IsDIr required!"); + removeServerItem(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function uploadItem(req, res) { + const serverSpec = req.body; + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + uploadServerItem(serverSpec, req.file) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function getItem(req, res) { + const serverSpec = req.body; + if (!serverSpec.name) return res.status(400).send("Server name required!"); + if (!serverSpec.path) return res.status(400).send("Path required!"); + getServerItem(serverSpec, res) + .then(({ ds, ftpTransfer }) => { + ds.pipe(res).on("error", sendError(res)); + return ftpTransfer; + }) + .catch(sendError(res)); +} diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js new file mode 100644 index 0000000..5b0105e --- /dev/null +++ b/lib/controllers/lifecycle-controller.js @@ -0,0 +1,93 @@ +import createServerResources from "../k8s/server-create.js"; +import deleteServerResources from "../k8s/server-delete.js"; +import { + createServerEntry, + deleteServerEntry, + getServerEntry, +} from "../database/queries/server-queries.js"; +import { sendError } from "../util/ExpressClientError.js"; +import { + startServerContainer, + stopServerContainer, +} from "../k8s/server-control.js"; +import { toggleServer } from "../k8s/k8s-server-control.js"; + +function payloadFilter(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + const { name, host, version, serverType, difficulty, gamemode, memory } = + serverSpec; + if (!name) return res.status(400).send("Server name is required!"); + if (!host) return res.status(400).send("Server host 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 checkServerName(serverSpec) { + if (!serverSpec) throw new ExpressClientError({ c: 400 }); + if (!serverSpec.name) + throw new ExpressClientError({ c: 400, m: "Server name required!" }); +} + +export async function createServer(req, res) { + if (payloadFilter(req, res) !== "filtered") return; + const serverSpec = req.body; + try { + const serverSpecs = await getServerEntry(serverSpec.name); + if (serverSpecs.length !== 0) throw Error("Server already exists in DB!"); + await createServerResources(serverSpec); + await createServerEntry(serverSpec); + res.sendStatus(200); + } catch (e) { + sendError(res)(e); + } +} + +export async function deleteServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerName(serverSpec); + } catch (e) { + return sendError(res)(e); + } + const deleteEntry = deleteServerEntry(serverSpec.name); + const deleteResources = deleteServerResources(serverSpec); + Promise.all([deleteEntry, deleteResources]) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function startServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerName(serverSpec); + } catch (e) { + return sendError(res)(e); + } + const { name } = serverSpec; + toggleServer(name, true) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} + +export async function stopServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerName(serverSpec); + } catch (e) { + return sendError(res)(e); + } + const { name } = serverSpec; + toggleServer(name, false) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} diff --git a/lib/controllers/status-controller.js b/lib/controllers/status-controller.js new file mode 100644 index 0000000..b2fa8b7 --- /dev/null +++ b/lib/controllers/status-controller.js @@ -0,0 +1,18 @@ +import { getDeployments } from "../k8s/k8s-server-control.js"; +import { getInstances } from "../k8s/server-control.js"; +import { sendError } from "../util/ExpressClientError.js"; + +export function serverList(req, res) { + getDeployments() + .then((sd) => res.json(sd.map((s) => s.metadata.name.substring(4)))) + .catch((e) => { + ERR("SERVER CONTROL", e); + res.status(500).send("Couldn't get server list"); + }); +} + +export function serverInstances(req, res) { + getInstances() + .then((i) => res.json(i)) + .catch(sendError(res)); +} diff --git a/lib/controllers/sub-controllers/console-controller.js b/lib/controllers/sub-controllers/console-controller.js new file mode 100644 index 0000000..40cf777 --- /dev/null +++ b/lib/controllers/sub-controllers/console-controller.js @@ -0,0 +1,65 @@ +// Imports +import k8s from "@kubernetes/client-node"; +import { Rcon as RconClient } from "rcon-client"; +import stream from "stream"; +import { ERR, WARN } from "../../util/logging.js"; + +// Kubernetes Configuration +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +// Retrieves logs from the minecraft server container +export async function webConsoleLogs(socket) { + const { serverName } = socket.mcs; + const podName = `mcl-${serverName}`; + const containerName = `${podName}-server`; + const podResponse = await k8sCore.listNamespacedPod(namespace); + const pods = podResponse.body.items.map((vp1) => vp1.metadata.name); + const mcsPods = pods.filter((p) => p.startsWith(podName)); + if (mcsPods.length === 0) + throw Error(`Could not find a pod that starts with ${podName}`); + if (mcsPods.length > 1) + throw Error(`Multiple pods match the name ${podName}`); + + const log = new k8s.Log(kc); + const logStream = new stream.PassThrough(); + logStream.on("data", (chunk) => + socket.emit("push", Buffer.from(chunk).toString()), + ); + log + .log(namespace, mcsPods[0], containerName, logStream, { + follow: true, + pretty: false, + timestamps: false, + }) + .catch((e) => ERR("CONSOLE CONTROLLER", "Error streaming logs", e)); +} + +// Creates an RCON connection to the minecraft container +export async function webConsoleRcon(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 { serverName } = socket.mcs; + const rconHost = `mcl-${serverName}-rcon.${namespace}.svc.cluster.local`; + const rcon = new RconClient({ + host: rconHost, + port: 25575, + password: rconPassword, + }); + rcon.on("error", (error) => socket.emit("push", error)); + try { + await rcon.connect(); + } catch (error) { + socket.emit("push", "Could not connect RCON Input to server!"); + WARN("RCON", `Could not connect to '${rconHost}'`); + } + socket.rconClient = rcon; +} diff --git a/lib/database/migrations/1_create_servers_table.sql b/lib/database/migrations/1_create_servers_table.sql new file mode 100644 index 0000000..5306630 --- /dev/null +++ b/lib/database/migrations/1_create_servers_table.sql @@ -0,0 +1,12 @@ +CREATE SEQUENCE servers_id_seq; +CREATE TABLE servers ( + id bigint NOT NULL DEFAULT nextval('servers_id_seq') PRIMARY KEY, + name varchar(255) DEFAULT NULL, + host varchar(255) DEFAULT NULL, + version varchar(63) DEFAULT 'latest', + server_type varchar(63) DEFAULT 'VANILLA', + memory varchar(63) DEFAULT '512', + CONSTRAINT unique_name UNIQUE(name), + CONSTRAINT unique_host UNIQUE(host) +); +ALTER SEQUENCE servers_id_seq OWNED BY servers.id; \ No newline at end of file diff --git a/lib/database/pg-query.js b/lib/database/pg-query.js new file mode 100644 index 0000000..ce21af6 --- /dev/null +++ b/lib/database/pg-query.js @@ -0,0 +1,121 @@ +const buildPostgresEntry = (entry) => { + const pgEntry = { ...entry }; + Object.keys(pgEntry).forEach((col) => { + if (pgEntry[col] === undefined) delete pgEntry[col]; + }); + return pgEntry; +}; + +export const buildPostgresValue = (jsVar) => { + if (jsVar === null) return "null"; + if (typeof jsVar === "string") return buildPostgresString(jsVar); + if (Array.isArray(jsVar) && jsVar.length === 0) return "null"; + if (Array.isArray(jsVar) && isTypeArray(jsVar, "string")) + return buildPostgresStringArray(jsVar); + return jsVar; +}; + +const buildPostgresStringArray = (jsonArray) => { + if (jsonArray.length === 0) return null; + var pgArray = [...jsonArray]; + var arrayString = "ARRAY ["; + pgArray.forEach((e, i) => (pgArray[i] = `'${e}'`)); + arrayString += pgArray.join(","); + arrayString += "]"; + return arrayString; +}; + +const isTypeArray = (jsonArray, type) => + jsonArray.every((e) => typeof e === type); + +const buildPostgresString = (jsonString) => + (jsonString && `'${jsonString.replaceAll("'", "''")}'`) || null; + +export const insertQuery = (table, jsEntry) => { + if (typeof jsEntry !== "object") throw Error("PG Inserts must be objects!"); + const entry = buildPostgresEntry(jsEntry); + const cols = Object.keys(entry); + cols.forEach((col, i) => { + entry[col] = buildPostgresValue(entry[col]); + cols[i] = `"${col}"`; + }); + var query = `INSERT INTO ${table}(${cols.join(",")})\n`; + query += `VALUES(${Object.values(entry).join(",")})`; + return query; +}; + +export const deleteQuery = (table, jsEntry) => { + if (typeof jsEntry !== "object") + throw Error("PG Delete conditionals must be an object!"); + const entry = buildPostgresEntry(jsEntry); + const cols = Object.keys(entry); + const conditionals = []; + for (var col of cols) { + entry[col] = buildPostgresValue(entry[col]); + if (entry[col] === "null") conditionals.push(`x.${col} IS NULL`); + else conditionals.push(`x.${col}=${entry[col]}`); + } + return `DELETE FROM ${table} x WHERE ${conditionals.join(" AND ")}`; +}; +export const onConflictUpdate = (conflicts, updates) => { + if (!Array.isArray(conflicts)) throw Error("PG Conflicts must be an array!"); + if (typeof updates !== "object") throw Error("PG Updates must be objects!"); + const entry = buildPostgresEntry(updates); + var query = `ON CONFLICT (${conflicts.join(",")}) DO UPDATE SET\n`; + const cols = Object.keys(entry); + for (var col of cols) { + entry[col] = buildPostgresValue(entry[col]); + } + query += cols.map((c) => `${c}=${entry[c]}`).join(","); + return query; +}; +export const clearTableQuery = (table) => { + return `TRUNCATE ${table}`; +}; + +export const selectWhereQuery = (table, jsEntry, joinWith) => { + if (typeof jsEntry !== "object") throw Error("PG Where must be an object!"); + const where = buildPostgresEntry(jsEntry); + const cols = Object.keys(where); + var query = `SELECT * FROM ${table} AS x WHERE\n`; + for (var col of cols) { + where[col] = buildPostgresValue(where[col]); + } + return (query += cols.map((c) => `x.${c}=${where[c]}`).join(joinWith)); +}; +export const updateWhereQuery = (table, updates, wheres, joinWith) => { + if (typeof updates !== "object") throw Error("PG Updates must be an object!"); + if (typeof wheres !== "object") throw Error("PG Wheres must be an object!"); + const update = buildPostgresEntry(updates); + const where = buildPostgresEntry(wheres); + const updateCols = Object.keys(update); + const whereCols = Object.keys(where); + var query = `UPDATE ${table}\n`; + var updateQuery = updateCols + .map((c) => `${c} = ${buildPostgresValue(update[c])}`) + .join(","); + var whereQuery = whereCols + .map((c) => `${c} = ${buildPostgresValue(where[c])}`) + .join(joinWith); + return (query += `SET ${updateQuery} WHERE ${whereQuery}`); +}; +export const updateWhereAnyQuery = (table, updates, wheres) => + updateWhereQuery(table, updates, wheres, " OR "); +export const updateWhereAllQuery = (table, updates, wheres) => + updateWhereQuery(table, updates, wheres, " AND "); +export const selectWhereAnyQuery = (table, where) => + selectWhereQuery(table, where, " OR "); +export const selectWhereAllQuery = (table, where) => + selectWhereQuery(table, where, " AND "); + +export default { + selectWhereAnyQuery, + selectWhereAllQuery, + updateWhereAnyQuery, + updateWhereAllQuery, + insertQuery, + deleteQuery, + buildPostgresValue, + onConflictUpdate, + clearTableQuery, +}; diff --git a/lib/database/postgres.js b/lib/database/postgres.js new file mode 100644 index 0000000..eb2a037 --- /dev/null +++ b/lib/database/postgres.js @@ -0,0 +1,63 @@ +// Imports +import path from "node:path"; +import { URL } from "node:url"; +import { migrate } from "postgres-migrations"; +import createPgp from "pg-promise"; +import moment from "moment"; +import { INFO, WARN, OK, VERB } from "../util/logging.js"; + +// Environment Variables +const { + MCL_POSTGRES_DATABASE: database, + MCL_POSTGRES_ENABLED: pgEnabled, + MCL_POSTGRES_HOST: host, + MCL_POSTGRES_PASSWORD: password, + MCL_POSTGRES_PORT: port, + MCL_POSTGRES_USER: user, +} = process.env; + +// Postgres-promise Configuration +// Ensure dates get saved as UTC date strings +// This prevents the parser from doing strange datetime operations +const pgp = createPgp(); +pgp.pg.types.setTypeParser(1114, (str) => moment.utc(str).format()); + +// Database Config +const dbConfig = { + database: database ?? "minecluster", + user: user ?? "postgres", + password: password ?? "postgres", + host: host ?? "localhost", + port: port ?? 5432, + ensureDatabaseExists: true, +}; + +const databaseDir = new URL(".", import.meta.url).pathname; +const migrationsDir = path.resolve(databaseDir, "migrations/"); + +const queryMock = (str) => INFO("POSTGRES MOCK", str); + +const connect = (pg) => async () => { + if (pgEnabled === "false") { + WARN("POSTGRES", "Postgres Disabled!"); + return { query: queryMock }; + } + VERB("POSTGRES", "Migrating..."); + await migrate(dbConfig, migrationsDir); + // Override fake methods + const pgInstance = pgp(dbConfig); + for (var k in pgInstance) pg[k] = pgInstance[k]; + VERB("POSTGRES", "Migrated Successfully!"); + await pg.connect(); + VERB("POSTGRES", "Postgres connected Successfully!"); + + OK("POSTGRES", `Connected to database ${dbConfig.database}!`); +}; + +const buildPostgres = () => { + var pg = { query: queryMock }; + pg.connect = connect(pg); + return pg; +}; + +export default buildPostgres(); diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js new file mode 100644 index 0000000..d8baa8f --- /dev/null +++ b/lib/database/queries/server-queries.js @@ -0,0 +1,41 @@ +import pg from "../postgres.js"; +import { deleteQuery, insertQuery, selectWhereQuery } from "../pg-query.js"; +import ExpressClientError from "../../util/ExpressClientError.js"; +const table = "servers"; + +const asExpressClientError = (e) => { + throw new ExpressClientError({ m: e.message, c: 409 }); +}; + +export async function createServerEntry(serverSpec) { + const { name, host, version, serverType: server_type, memory } = serverSpec; + const q = insertQuery(table, { name, host, version, server_type, memory }); + return pg.query(q).catch(asExpressClientError); +} + +export async function deleteServerEntry(serverName) { + if (!serverName) asExpressClientError({ message: "Server Name Required!" }); + const q = deleteQuery(table, { name: serverName }); + return pg.query(q).catch(asExpressClientError); +} + +export async function getServerEntry(serverName) { + if (!serverName) asExpressClientError({ message: "Server Name Required!" }); + const q = selectWhereQuery(table, { name: serverName }); + try { + const serverSpecs = await pg.query(q); + if (serverSpecs.length === 0) return []; + if (!serverSpecs.length === 1) + throw Error("Multiple servers found with the same name!"); + const { + name, + host, + version, + server_type: serverType, + memory, + } = serverSpecs[0]; + return { name, host, version, serverType, memory }; + } catch (e) { + asExpressClientError(e); + } +} diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/lib/k8s.js b/lib/k8s.js deleted file mode 100644 index b842159..0000000 --- a/lib/k8s.js +++ /dev/null @@ -1,8 +0,0 @@ -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/containers/ftp-server.yml b/lib/k8s/configs/containers/ftp-server.yml new file mode 100644 index 0000000..759bc20 --- /dev/null +++ b/lib/k8s/configs/containers/ftp-server.yml @@ -0,0 +1,36 @@ +env: + - name: FTP_USER + value: "minecluster" + - name: FTP_PASS + value: "minecluster" +image: garethflowers/ftp-server +imagePullPolicy: IfNotPresent +livenessProbe: +exec: + command: ["echo"] +failureThreshold: 20 +initialDelaySeconds: 30 +periodSeconds: 5 +successThreshold: 1 +timeoutSeconds: 1 +name: changeme-name-ftp +ports: [] # Programatically add all the ports for easier readability, Ports include: 20,21,40000-400009 +readinessProbe: + exec: + command: ["echo"] + failureThreshold: 20 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 1 +resources: + requests: + cpu: 50m + memory: 64Mi +stdin: true +terminationMessagePath: /dev/termination-log +terminationMessagePolicy: File +tty: true +volumeMounts: + - mountPath: /home/minecluster + name: datadir diff --git a/lib/k8s/configs/containers/minecraft-backup.yml b/lib/k8s/configs/containers/minecraft-backup.yml new file mode 100644 index 0000000..074025a --- /dev/null +++ b/lib/k8s/configs/containers/minecraft-backup.yml @@ -0,0 +1,63 @@ +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 diff --git a/lib/k8s/configs/containers/minecraft-server.yml b/lib/k8s/configs/containers/minecraft-server.yml new file mode 100644 index 0000000..4034e36 --- /dev/null +++ b/lib/k8s/configs/containers/minecraft-server.yml @@ -0,0 +1,113 @@ +env: + # System Values + - name: JVM_OPTS + - name: JVM_XX_OPTS + - name: OVERRIDE_SERVER_PROPERTIES + value: "false" + - name: EULA + value: "TRUE" + # Updated at recreation + - name: MEMORY + value: 1024M + - name: TYPE + value: VANILLA + - name: VERSION + value: "latest" + # Set at creation but not updated on recreation + - name: DIFFICULTY + value: easy + - name: WHITELIST + - name: OPS + - 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: ONLINE_MODE + 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-server +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 diff --git a/lib/k8s/configs/rcon-secret.yml b/lib/k8s/configs/rcon-secret.yml index 6b7bd80..ff52e1a 100644 --- a/lib/k8s/configs/rcon-secret.yml +++ b/lib/k8s/configs/rcon-secret.yml @@ -3,6 +3,8 @@ data: rcon-password: UEphT3V2aGJlQjNvc3M0dElwQU5YTUZrSkltR1RsRVl0ZGx3elFqZjJLdVZrZXNtV0hja1VhUUd3bmZDcElpbA== kind: Secret metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app-label name: changeme-rcon-secret diff --git a/lib/k8s/configs/rcon-svc.yml b/lib/k8s/configs/rcon-svc.yml index bcb34a7..9a68813 100644 --- a/lib/k8s/configs/rcon-svc.yml +++ b/lib/k8s/configs/rcon-svc.yml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app name: changeme-rcon diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml index bb6611a..0d5d335 100644 --- a/lib/k8s/configs/server-deployment.yml +++ b/lib/k8s/configs/server-deployment.yml @@ -1,6 +1,8 @@ apiVersion: apps/v1 kind: Deployment metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name name: changeme-name namespace: changeme-namespace spec: @@ -14,191 +16,18 @@ spec: type: Recreate template: metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name 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 + containers: [] dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler - securityContext: - fsGroup: 2000 - runAsUser: 1000 + # securityContext: + # fsGroup: 2000 + # runAsUser: 1000 terminationGracePeriodSeconds: 30 volumes: - name: datadir diff --git a/lib/k8s/configs/server-pvc.yml b/lib/k8s/configs/server-pvc.yml index caeaa2b..f502e8a 100644 --- a/lib/k8s/configs/server-pvc.yml +++ b/lib/k8s/configs/server-pvc.yml @@ -1,6 +1,8 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: + annotations: + minecluster.dunemask.net/server-name: changeme-server-name labels: service: changeme-service-name name: changeme-pvc-name diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml index c6678e6..c7e7fa2 100644 --- a/lib/k8s/configs/server-svc.yml +++ b/lib/k8s/configs/server-svc.yml @@ -4,6 +4,7 @@ metadata: annotations: ingress.qumine.io/hostname: changeme-url ingress.qumine.io/portname: minecraft + minecluster.dunemask.net/server-name: changeme-server-name labels: app: changeme-app name: changeme-name @@ -13,11 +14,15 @@ spec: ipFamilies: - IPv4 ipFamilyPolicy: SingleStack - ports: + ports: # Programatically add all FTP ports. Port range includes 20, 21, 40000-40001 - name: minecraft port: 25565 protocol: TCP targetPort: minecraft + # - name: ftp-data + # port: 20 + # protocol: TCP + # targetPort: ftp-data selector: app: changeme-app sessionAffinity: None diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js new file mode 100644 index 0000000..4e5233d --- /dev/null +++ b/lib/k8s/k8s-server-control.js @@ -0,0 +1,146 @@ +import k8s from "@kubernetes/client-node"; +import yaml from "js-yaml"; +import { VERB, ERR } from "../util/logging.js"; +import { getServerEntry } from "../database/queries/server-queries.js"; +import { + getFtpContainer, + getCoreServerContainer, + getBackupContainer, +} from "./server-containers.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 loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); + +const mineclusterManaged = (o) => + o.metadata && + o.metadata.annotations && + o.metadata.annotations["minecluster.dunemask.net/server-name"] !== undefined; + +export const serverMatch = (serverName) => (o) => + o.metadata.annotations["minecluster.dunemask.net/server-name"] === serverName; + +export async function getDeployments() { + const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); + const serverDeployments = deploymentRes.body.items.filter(mineclusterManaged); + return serverDeployments; +} + +export async function getServices() { + const serviceRes = await k8sCore.listNamespacedService(namespace); + const serverServices = serviceRes.body.items.filter(mineclusterManaged); + return serverServices; +} + +export async function getSecrets() { + const secretRes = await k8sCore.listNamespacedSecret(namespace); + const serverSecrets = secretRes.body.items.filter(mineclusterManaged); + return serverSecrets; +} + +export async function getVolumes() { + const volumeRes = + await k8sCore.listNamespacedPersistentVolumeClaim(namespace); + const serverVolumes = volumeRes.body.items.filter(mineclusterManaged); + return serverVolumes; +} + +export function getServerAssets(serverName) { + const serverFilter = serverMatch(serverName); + return Promise.all([ + getDeployments(), + getServices(), + getSecrets(), + getVolumes(), + ]) + .then(([deps, svcs, scrts, vols]) => { + const deployments = deps.filter(serverFilter); + const services = svcs.filter(serverFilter); + const secrets = scrts.filter(serverFilter); + const volumes = vols.filter(serverFilter); + + if (deployments.length > 1) throw Error("Deployment filter broken!"); + if (volumes.length > 1) throw Error("Volume filter broken!"); + if (secrets.length > 1) throw Error("Secrets broken!"); + const serverAssets = { + deployment: deployments[0], + service: services.find( + (s) => s.metadata.name === `mcl-${serverName}-server`, + ), + volume: volumes[0], + rconService: services.find( + (s) => s.metadata.name === `mcl-${serverName}-rcon`, + ), + rconSecret: secrets[0], + }; + for (var k in serverAssets) if (serverAssets[k]) return serverAssets; + // If no assets exist, return nothing + }) + .catch((e) => ERR("SERVER ASSETS", e)); +} + +export async function getDeployment(serverName) { + const servers = await getDeployments(); + const serverDeployment = servers.find( + (s) => + s.metadata.annotations["minecluster.dunemask.net/server-name"] === + serverName, + ); + if (!serverDeployment) + throw Error(`MCL Deployment '${serverName}' could not be found!`); + + return serverDeployment; +} + +export async function getContainers(serverName) { + const deployment = await getDeployment(serverName); + return deployment.spec.template.spec.containers; +} + +async function containerControl(serverName, deployment, scaleUp) { + const { containers } = deployment.spec.template.spec; + const depFtp = containers.find((c) => c.name.endsWith("-ftp")); + const depServer = containers.find((c) => c.name.endsWith("-server")); + const depBackup = containers.find((c) => c.name.endsWith("-backup")); + const serverSpec = await getServerEntry(serverName); + const ftpContainer = depFtp ?? getFtpContainer(serverSpec); + const serverContainer = depServer ?? getCoreServerContainer(serverSpec); + const backupContainer = depBackup ?? getBackupContainer(serverSpec); + if (scaleUp) return [ftpContainer, serverContainer]; + return [ftpContainer]; +} + +export async function toggleServer(serverName, scaleUp = false) { + const deployment = await getDeployment(serverName); + deployment.spec.template.spec.containers = await containerControl( + serverName, + deployment, + scaleUp, + ); + return k8sDeps.replaceNamespacedDeployment( + deployment.metadata.name, + namespace, + deployment, + ); +} + +export async function scaleDeployment(serverName, scaleUp = false) { + const deployment = await getDeployment(serverName); + if (deployment.spec.replicas === 1 && scaleUp) + return VERB( + "KSC", + `MCL Deployment '${serverName}' is already scaled! Ignoring scale adjustment.`, + ); + deployment.spec.replicas = scaleUp ? 1 : 0; + + return k8sDeps.replaceNamespacedDeployment( + deployment.metadata.name, + namespace, + deployment, + ); +} diff --git a/lib/k8s/live-logging.js b/lib/k8s/live-logging.js deleted file mode 100644 index c65b34b..0000000 --- a/lib/k8s/live-logging.js +++ /dev/null @@ -1,30 +0,0 @@ -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-containers.js b/lib/k8s/server-containers.js new file mode 100644 index 0000000..4694828 --- /dev/null +++ b/lib/k8s/server-containers.js @@ -0,0 +1,67 @@ +import fs from "node:fs"; +import path from "node:path"; +import yaml from "js-yaml"; +const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); + +export function getFtpContainer(serverSpec) { + const { name } = serverSpec; + const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); + ftpContainer.name = `mcl-${name}-ftp`; + const ftpPortList = [ + { p: 20, n: "ftp-data" }, + { p: 21, n: "ftp-commands" }, + ]; + for (var p = 40000; p <= 40009; p++) + ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); + ftpContainer.ports = ftpPortList.map(({ p: containerPort, n: name }) => ({ + containerPort, + name, + protocol: "TCP", + })); + return ftpContainer; +} + +export function getCoreServerContainer(serverSpec) { + const { name, version, serverType, memory } = serverSpec; + const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml"); + // Container Updates + container.name = `mcl-${name}-server`; + container.resources.requests.memory = `${memory}Mi`; + + const findEnv = (k) => container.env.find(({ name: n }) => n === k); + const updateEnv = (k, v) => (findEnv(k).value = v); + + // Enviornment variables + updateEnv("TYPE", serverType); + updateEnv("VERSION", version); + updateEnv("MEMORY", `${memory}M`); + // RCON + const rs = `mcl-${name}-rcon-secret`; + findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + return container; +} + +export function getServerContainer(serverSpec) { + const { difficulty, gamemode, motd, maxPlayers, seed, ops, whitelist } = + serverSpec; + const container = getCoreServerContainer(serverSpec); + + const findEnv = (k) => container.env.find(({ name: n }) => n === k); + const updateEnv = (k, v) => (findEnv(k).value = v); + + // Enviornment variables + updateEnv("DIFFICULTY", difficulty); + updateEnv("MODE", gamemode); + updateEnv("MOTD", motd); + updateEnv("MAX_PLAYERS", maxPlayers); + updateEnv("SEED", seed); + updateEnv("OPS", ops); + updateEnv("WHITELIST", whitelist); + + return container; +} + +export function getBackupContainer(serverSpec) { + const container = loadYaml("lib/k8s/configs/containers/minecraft-backup.yml"); + return container; +} diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js index 4bda593..63097e6 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -1,95 +1,86 @@ import k8s from "@kubernetes/client-node"; +import { + getDeployment, + getDeployments, + getServerAssets, + scaleDeployment, +} from "./k8s-server-control.js"; import { ERR } from "../util/logging.js"; +import ExpressClientError from "../util/ExpressClientError.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 k8sDeps = kc.makeApiClient(k8s.AppsV1Api); 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!"); +export async function startServerContainer(serverSpec) { 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); + try { + await scaleDeployment(name, true); + } catch (e) { + ERR("SERVER CONTROL", e); + throw new ExpressClientError({ + c: 500, + m: `Error updating server '${name}'!\n`, + }); + } } -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!"); +export async function stopServerContainer(serverSpec) { 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); + try { + await scaleDeployment(name, false); + } catch (e) { + ERR("SERVER CONTROL", e); + throw new ExpressClientError({ + c: 500, + m: `Error updating server '${name}'!`, + }); + } } -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; +export async function getInstances() { + const serverDeployments = await getDeployments(); 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); + const serverInstances = serverDeployments.map((s) => { + name = s.metadata.annotations["minecluster.dunemask.net/server-name"]; metrics = null; - started = !!s.spec.replicas; + started = !!s.spec.template.spec.containers.find((c) => + c.name.includes(`mcl-${name}-server`), + ); const pod = podMetricsResponse.items.find(({ metadata: md }) => { return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`; }); - if (pod) { + if (started && pod) { const podCpus = pod.containers.map( - ({ usage }) => parseInt(usage.cpu) / 1_000_000 + ({ usage }) => parseInt(usage.cpu) / 1_000_000, ); const podMems = pod.containers.map( - ({ usage }) => parseInt(usage.memory) / 1024 + ({ 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 }; }); + return serverInstances; +} + +export async function getNamespaceMetrics() { + const serverInstances = await getInstances(); var clusterMetrics = { cpu: 0, memory: 0 }; if (servers.length > 1) { - const clusterCpu = servers + const clusterCpu = serverInstances .map(({ metrics }) => (metrics ? metrics.cpu : 0)) .reduce((a, b) => a + b); - const clusterMem = servers + const clusterMem = serverInstances .map(({ metrics }) => (metrics ? metrics.memory : 0)) .reduce((a, b) => a + b); clusterMetrics = { cpu: clusterCpu, memory: clusterMem }; } - res.json({ servers, clusterMetrics }); + return clusterMetrics; } diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 0cf0e2e..8ef2fe3 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -4,158 +4,130 @@ import k8s from "@kubernetes/client-node"; import yaml from "js-yaml"; import fs from "node:fs"; import path from "node:path"; +import ExpressClientError from "../util/ExpressClientError.js"; +import { + getFtpContainer, + getServerContainer, + getBackupContainer, +} from "./server-containers.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; -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"; -} +const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); function createRconSecret(serverSpec) { const { name } = serverSpec; - const rconYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/rcon-secret.yml"), "utf8") - ); - + const rconYaml = loadYaml("lib/k8s/configs/rcon-secret.yml"); // 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; + rconYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = name; return rconYaml; } function createServerVolume(serverSpec) { const { name } = serverSpec; - const volumeYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/server-pvc.yml"), "utf8") - ); + const volumeYaml = loadYaml("lib/k8s/configs/server-pvc.yml"); volumeYaml.metadata.labels.service = `mcl-${name}-server`; volumeYaml.metadata.name = `mcl-${name}-volume`; volumeYaml.metadata.namespace = namespace; + volumeYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; 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 + const { name, host } = serverSpec; + const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); + const { metadata } = deployYaml; + const serverContainer = getServerContainer(serverSpec); + const backupContainer = getBackupContainer(serverSpec); + const ftpContainer = getFtpContainer(serverSpec); + + // Configure Metadata; + metadata.name = `mcl-${name}`; + metadata.namespace = namespace; + metadata.annotations["minecluster.dunemask.net/server-name"] = name; + deployYaml.metadata = metadata; + + // Configure Lables & Selectors 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" + ({ name }) => name === "datadir", ).persistentVolumeClaim.claimName = `mcl-${name}-volume`; - deployYaml.spec.template.spec.containers[0] = serverContainer; + + // Apply Containers TODO: User control for autostart + deployYaml.spec.template.spec.containers.push(serverContainer); + deployYaml.spec.template.spec.containers.push(ftpContainer); + deployYaml.spec.replicas = 1; 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; + const { name, host } = serverSpec; + const serviceYaml = loadYaml("lib/k8s/configs/server-svc.yml"); + serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = host; + serviceYaml.metadata.annotations["mc-router.itzg.me/externalServerName"] = + host; serviceYaml.metadata.labels.app = `mcl-${name}-app`; serviceYaml.metadata.name = `mcl-${name}-server`; serviceYaml.metadata.namespace = namespace; + serviceYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; serviceYaml.spec.selector.app = `mcl-${name}-app`; + // Port List: + const serverPortList = [{ p: 25565, n: "minecraft" }]; + + // Apply FTP Port List + const ftpPortList = [ + { p: 20, n: "ftp-data" }, + { p: 21, n: "ftp-commands" }, + ]; + for (var p = 40000; p <= 40009; p++) + ftpPortList.push({ p, n: `ftp-passive-${p - 40000}` }); + + const portList = [...serverPortList, ...ftpPortList]; + serviceYaml.spec.ports = portList.map(({ p: port, n: name }) => ({ + port, + name, + protocol: "TCP", + targetPort: port, + })); return serviceYaml; } function createRconService(serverSpec) { - const { name, url } = serverSpec; - const rconSvcYaml = yaml.load( - fs.readFileSync(path.resolve("lib/k8s/configs/rcon-svc.yml"), "utf8") - ); + const { name } = serverSpec; + const rconSvcYaml = loadYaml("lib/k8s/configs/rcon-svc.yml"); rconSvcYaml.metadata.labels.app = `mcl-${name}-app`; rconSvcYaml.metadata.name = `mcl-${name}-rcon`; rconSvcYaml.metadata.namespace = namespace; + rconSvcYaml.metadata.annotations["minecluster.dunemask.net/server-name"] = + name; 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; +export default async function createServerResources(serverSpec) { 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!"); + throw new ExpressClientError({ m: "Server already exists!", c: 409 }); 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!"); + throw new ExpressClientError({ m: "Server PVC already exists!", c: 409 }); const rconSecret = createRconSecret(serverSpec); const serverVolume = createServerVolume(serverSpec); const serverDeploy = createServerDeploy(serverSpec); @@ -166,6 +138,4 @@ export default async function createServer(req, res) { 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 index 76b540c..e226fbf 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -1,5 +1,7 @@ import k8s from "@kubernetes/client-node"; import { ERR } from "../util/logging.js"; +import { getServerAssets } from "./k8s-server-control.js"; +import ExpressClientError from "../util/ExpressClientError.js"; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); @@ -7,49 +9,52 @@ 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!"); +const deleteError = (err) => { ERR("K8S", "An error occurred while deleting a resource", err); + throw new ExpressClientError({ + c: 500, + m: "Error deleting a resource!\n" + 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!"); +function deleteOnExist(o, fn) { + if (o) return fn(o.metadata.name); +} + +export default async function deleteServerResources(serverSpec) { 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!"); + const server = await getServerAssets(name); + if (!server) + throw new ExpressClientError({ + c: 404, + m: "No Resources for that server were found!", + }); + // Delete in reverse order - const deleteDeploy = k8sDeps.deleteNamespacedDeployment( - `mcl-${serverSpec.name}`, - namespace + const deleteDeploy = deleteOnExist(server.deployment, (name) => + k8sDeps.deleteNamespacedDeployment(name, namespace), ); - const deleteService = k8sCore.deleteNamespacedService( - `mcl-${name}-server`, - namespace + + const deleteService = deleteOnExist(server.service, (name) => + k8sCore.deleteNamespacedService(name, namespace), ); - const deleteRconService = k8sCore.deleteNamespacedService( - `mcl-${name}-rcon`, - namespace + const deleteRconService = deleteOnExist(server.rconService, (name) => + k8sCore.deleteNamespacedService(name, namespace), ); - await deleteDeploy.catch(deleteError(res)); - const deleteRconSecret = k8sCore.deleteNamespacedSecret( - `mcl-${name}-rcon-secret`, - namespace + if (deleteDeploy) await deleteDeploy.catch(deleteError); + + const deleteRconSecret = deleteOnExist(server.rconSecret, (name) => + k8sCore.deleteNamespacedSecret(name, namespace), ); - const deleteVolume = k8sCore.deleteNamespacedPersistentVolumeClaim( - `mcl-${name}-volume`, - namespace + const deleteVolume = deleteOnExist(server.volume, (name) => + k8sCore.deleteNamespacedPersistentVolumeClaim(name, namespace), ); - Promise.all([ + + return Promise.all([ deleteService, deleteRconService, deleteRconSecret, deleteVolume, - ]) - .then(() => res.sendStatus(200)) - .catch(deleteError(res)); + ]).catch(deleteError); } diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js new file mode 100644 index 0000000..ec1f7cc --- /dev/null +++ b/lib/k8s/server-files.js @@ -0,0 +1,97 @@ +import ftp from "basic-ftp"; +import { ERR } from "../util/logging.js"; +import { getServerAssets } from "./k8s-server-control.js"; +import ExpressClientError from "../util/ExpressClientError.js"; +import { Readable, Writable, Transform } from "node:stream"; + +const namespace = process.env.MCL_SERVER_NAMESPACE; + +const pathSecurityCheck = (path) => { + if (!path.startsWith(".")) + throw new ExpressClientError({ + m: "Only relative directories can be created", + c: 409, + }); +}; + +const handleError = (e) => { + ERR("SERVER FILES", "Error occurred while preforming FTP operation!", e); + throw new ExpressClientError({ + c: 500, + m: "Error occurred while performing FTP operation!", + }); +}; + +export async function getFtpClient(serverService) { + const { name } = serverService.metadata; + const client = new ftp.Client(); + await client.access({ + host: `${name}.${namespace}.svc.cluster.local`, + user: "minecluster", + password: "minecluster", + }); + return client; +} + +export async function useServerFtp(serverSpec, fn) { + const { name } = serverSpec; + const server = await getServerAssets(name); + if (!server) + throw new ExpressClientError({ + c: 404, + m: "No resources for that server were found!", + }); + if (!server.service) + throw new ExpressClientError({ + c: 409, + m: "Service doesn't exist, please contact your hosting provider!", + }); + const client = await getFtpClient(server.service); + const result = await fn(client); + client.close(); + return result; +} + +export async function listServerFiles(serverSpec) { + const { path } = serverSpec; + const files = useServerFtp(serverSpec, async (c) => await c.list(path)).catch( + handleError, + ); + return files; +} + +export async function createServerFolder(serverSpec) { + const { path } = serverSpec; + pathSecurityCheck(path); + await useServerFtp(serverSpec, async (c) => c.ensureDir(path)).catch( + handleError, + ); +} + +export async function removeServerItem(serverSpec) { + const { path, isDir } = serverSpec; + pathSecurityCheck(path); + await useServerFtp(serverSpec, async (c) => { + if (isDir) await c.removeDir(path); + else await c.remove(path); + }).catch(handleError); +} + +export async function uploadServerItem(serverSpec, file) { + const fileStream = Readable.from(file.buffer); + const { path } = serverSpec; + pathSecurityCheck(path); + await useServerFtp(serverSpec, async (c) => { + await c.uploadFrom(fileStream, `${path}/${file.originalname}`); + }).catch(handleError); +} + +export async function getServerItem(serverSpec, writableStream) { + const { path } = serverSpec; + const ds = new Transform({ transform: (c, e, cb) => cb(null, c) }); + pathSecurityCheck(path); + const ftpTransfer = useServerFtp(serverSpec, async (c) => { + await c.downloadTo(ds, path); + }).catch(handleError); + return { ds, ftpTransfer }; +} diff --git a/lib/routes/error-route.js b/lib/routes/error-route.js new file mode 100644 index 0000000..7b4e2ce --- /dev/null +++ b/lib/routes/error-route.js @@ -0,0 +1,17 @@ +export function logErrors(err, req, res, next) { + console.error(err.stack); + next(err); +} + +export function clientErrorHandler(err, req, res, next) { + if (req.xhr) { + res.status(500).send({ error: "Something failed!" }); + } else { + next(err); + } +} + +export function errorHandler(err, req, res, next) { + res.status(500); + res.render("error", { error: err }); +} diff --git a/lib/routes/files-route.js b/lib/routes/files-route.js new file mode 100644 index 0000000..c27c175 --- /dev/null +++ b/lib/routes/files-route.js @@ -0,0 +1,21 @@ +import { Router, json as jsonMiddleware } from "express"; +import multer from "multer"; +import { + createFolder, + deleteItem, + listFiles, + uploadItem, + getItem, +} from "../controllers/file-controller.js"; + +const router = Router(); +router.use(jsonMiddleware()); +const multerMiddleware = multer(); + +router.post("/list", listFiles); +router.post("/folder", createFolder); +router.delete("/item", deleteItem); +router.post("/item", getItem); +router.post("/upload", multerMiddleware.single("file"), uploadItem); + +export default router; diff --git a/lib/routes/react-route.js b/lib/routes/react-route.js index 9438566..e581fe3 100644 --- a/lib/routes/react-route.js +++ b/lib/routes/react-route.js @@ -3,6 +3,6 @@ import path from "path"; const router = Router(); router.use("/", express.static(path.resolve("./build"))); router.get("/*", (req, res) => - res.sendFile(path.resolve("./build/index.html")) + res.sendFile(path.resolve("./build/index.html")), ); export default router; diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js index 4c7eb35..7361abd 100644 --- a/lib/routes/server-route.js +++ b/lib/routes/server-route.js @@ -1,12 +1,14 @@ import { Router, json as jsonMiddleware } from "express"; import { + createServer, + deleteServer, startServer, stopServer, +} from "../controllers/lifecycle-controller.js"; +import { + serverInstances, serverList, - getServers, -} from "../k8s/server-control.js"; -import createServer from "../k8s/server-create.js"; -import deleteServer from "../k8s/server-delete.js"; +} from "../controllers/status-controller.js"; const router = Router(); router.use(jsonMiddleware()); // Routes @@ -15,5 +17,5 @@ router.delete("/delete", deleteServer); router.post("/start", startServer); router.post("/stop", stopServer); router.get("/list", serverList); -router.get("/instances", getServers); +router.get("/instances", serverInstances); export default router; diff --git a/lib/routes/system-route.js b/lib/routes/system-route.js index ddc5638..66e1022 100644 --- a/lib/routes/system-route.js +++ b/lib/routes/system-route.js @@ -7,6 +7,8 @@ kc.loadFromDefault(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); // Get Routes router.get("/available", (req, res) => { + return res.json({ cpu: 8000, memory: 16000 }); + // TODO Workaround to detect available k8sApi.listNode().then((nodeRes) => { const nodeAllocatable = nodeRes.body.items.map((i) => i.status.allocatable); const nodeResources = nodeAllocatable.map(({ cpu, memory }) => ({ diff --git a/lib/server/rcon.js b/lib/server/rcon.js deleted file mode 100644 index d2535b1..0000000 --- a/lib/server/rcon.js +++ /dev/null @@ -1,31 +0,0 @@ -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 index 58326bc..ccedebb 100644 --- a/lib/server/router.js +++ b/lib/server/router.js @@ -5,7 +5,13 @@ import express from "express"; import vitals from "../routes/vitals-route.js"; import systemRoute from "../routes/system-route.js"; import serverRoute from "../routes/server-route.js"; +import filesRoute from "../routes/files-route.js"; import reactRoute from "../routes/react-route.js"; +import { + logErrors, + clientErrorHandler, + errorHandler, +} from "../routes/error-route.js"; export default function buildRoutes(pg, skio) { const router = express.Router(); @@ -18,7 +24,11 @@ export default function buildRoutes(pg, skio) { // Routes router.use("/api/system", systemRoute); router.use("/api/server", serverRoute); - router.use(["/mcl","/mcl/*"], reactRoute); // Static Build Route + router.use("/api/files", filesRoute); + router.use(["/mcl", "/mcl/*"], reactRoute); // Static Build Route + /*router.use(logErrors); + router.use(clientErrorHandler); + router.use(errorHandler);*/ return router; } diff --git a/lib/server/sockets.js b/lib/server/sockets.js index 2b63ede..370e3d4 100644 --- a/lib/server/sockets.js +++ b/lib/server/sockets.js @@ -1,9 +1,9 @@ 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; +import { + webConsoleLogs, + webConsoleRcon, +} from "../controllers/sub-controllers/console-controller.js"; async function rconSend(socket, m) { if (!socket.rconClient) @@ -20,8 +20,8 @@ const socketConnect = async (io, socket) => { VERB("WS", "Websocket connecting"); socket.mcs = { serverName: socket.handshake.query.serverName }; try { - await liveLogging(socket, namespace); - await rconInterface(socket); + await webConsoleLogs(socket); + await webConsoleRcon(socket); socket.on("msg", (m) => rconSend(socket, m)); } catch (err) { ERR("SOCKETS", err); diff --git a/lib/storage/s3-integration.js b/lib/storage/s3-integration.js new file mode 100644 index 0000000..34ed5d5 --- /dev/null +++ b/lib/storage/s3-integration.js @@ -0,0 +1,34 @@ +import multer from "multer"; +import multerS3 from "multer-s3"; +import AWS from "aws-sdk"; + +// Environment Variables +const { + MCL_S3_ENDPOINT: s3Endpoint, + MCL_S3_ACCESS_KEY_ID: s3KeyId, + MCL_S3_ACCESS_KEY: s3Key, +} = process.env; + +export const mcl = "mcl"; + +export const s3 = new AWS.S3({ + endpoint: s3Endpoint, + accessKeyId: s3KeyId, + secretAccessKey: s3Key, + sslEnabled: true, + s3ForcePathStyle: true, +}); + +const storage = multerS3({ + s3, + bucket, + contentType: multerS3.AUTO_CONTENT_TYPE, + metadata: (req, file, cb) => { + cb(null, { fieldName: file.fieldname }); + }, + key: (req, file, cb) => { + cb(null, Date.now().toString()); + }, +}); + +export const upload = multer({ storage }); diff --git a/lib/util/ExpressClientError.js b/lib/util/ExpressClientError.js new file mode 100644 index 0000000..d079c30 --- /dev/null +++ b/lib/util/ExpressClientError.js @@ -0,0 +1,28 @@ +import { VERB } from "./logging.js"; + +export default class ExpressClientError extends Error { + constructor(message, clientOptions = {}) { + var msg; + if (typeof message === "object" && message.m !== undefined) msg = message.m; + else if (typeof message === "object") msg = "Unknown Express Client Error!"; + super(msg); + if (typeof message === "object") this.clientOptions = message; + else this.clientOptions = { message: msg, ...clientOptions }; + } + + sendError(res) { + if (!this.clientOptions.m && this.clientOptions.c) + res.sendStatus(this.clientOptions.c); + else res.status(this.clientOptions.c ?? 500).send(this.toString()); + } + + toString() { + return this.message; + } +} + +export const sendError = (res) => (e) => { + VERB("V", e); + if (e instanceof ExpressClientError) e.sendError(res); + else res.status(500).send(e); +}; diff --git a/package-lock.json b/package-lock.json index d8e509a..d111705 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,38 +9,46 @@ "version": "0.0.1-alpha.0", "license": "LGPL-2.1", "dependencies": { - "@kubernetes/client-node": "^0.18.1", + "@kubernetes/client-node": "^0.20.0", + "aws-sdk": "^2.1514.0", + "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", + "chonky": "^2.3.2", + "chonky-icon-fontawesome": "^2.3.2", "express": "^4.18.2", - "figlet": "^1.6.0", + "figlet": "^1.7.0", "js-yaml": "^4.1.0", - "rcon-client": "^4.2.3", + "moment": "^2.29.4", + "multer": "^1.4.5-lts.1", + "multer-s3": "^3.0.1", + "pg-promise": "^11.5.4", + "postgres-migrations": "^5.3.0", + "rcon-client": "^4.2.4", "socket.io": "^4.7.2", - "uuid": "^9.0.0" + "uuid": "^9.0.1" }, "devDependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/material": "^5.14.5", - "@tanstack/react-query": "^4.33.0", - "@vitejs/plugin-react": "^4.0.4", - "concurrently": "^8.2.0", - "nodemon": "^3.0.1", - "prettier": "^3.0.2", + "@mui/icons-material": "^5.14.19", + "@mui/material": "^5.14.20", + "@tanstack/react-query": "^5.12.2", + "@vitejs/plugin-react": "^4.2.1", + "concurrently": "^8.2.2", + "nodemon": "^3.0.2", + "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.15.0", + "react-router-dom": "^6.20.1", "socket.io-client": "^4.7.2", - "vite": "^4.4.9" + "vite": "^5.0.7" } }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -49,13 +57,832 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", - "dev": true, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "peer": true, "dependencies": { - "@babel/highlight": "^7.22.10", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/crc32c": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", + "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", + "peer": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32c/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "peer": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", + "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", + "peer": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "peer": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "peer": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "peer": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.427.0.tgz", + "integrity": "sha512-YKjJ9zgn0oE393HURKgvjNoX6lxUjb+dkTBE1GymFnGCPl6VxQbKXajXWNqUyN+oPPlZ2osEiljPaN0RserUjA==", + "peer": true, + "dependencies": { + "@aws-crypto/sha1-browser": "3.0.0", + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.427.0", + "@aws-sdk/credential-provider-node": "3.427.0", + "@aws-sdk/middleware-bucket-endpoint": "3.425.0", + "@aws-sdk/middleware-expect-continue": "3.425.0", + "@aws-sdk/middleware-flexible-checksums": "3.425.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-location-constraint": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-sdk-s3": "3.427.0", + "@aws-sdk/middleware-signing": "3.425.0", + "@aws-sdk/middleware-ssec": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/region-config-resolver": "3.425.0", + "@aws-sdk/signature-v4-multi-region": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@aws-sdk/xml-builder": "3.310.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/eventstream-serde-browser": "^2.0.10", + "@smithy/eventstream-serde-config-resolver": "^2.0.10", + "@smithy/eventstream-serde-node": "^2.0.10", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-blob-browser": "^2.0.10", + "@smithy/hash-node": "^2.0.10", + "@smithy/hash-stream-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/md5-js": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-stream": "^2.0.14", + "@smithy/util-utf8": "^2.0.0", + "@smithy/util-waiter": "^2.0.10", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.427.0.tgz", + "integrity": "sha512-sFVFEmsQ1rmgYO1SgrOTxE/MTKpeE4hpOkm1WqhLQK7Ij136vXpjCxjH1JYZiHiUzO1wr9t4ex4dlB5J3VS/Xg==", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/region-config-resolver": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.427.0.tgz", + "integrity": "sha512-le2wLJKILyWuRfPz2HbyaNtu5kEki+ojUkTqCU6FPDRrqUvEkaaCBH9Awo/2AtrCfRkiobop8RuTTj6cAnpiJg==", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.427.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-sdk-sts": "3.425.0", + "@aws-sdk/middleware-signing": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/region-config-resolver": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.425.0.tgz", + "integrity": "sha512-J20etnLvMKXRVi5FK4F8yOCNm2RTaQn5psQTGdDEPWJNGxohcSpzzls8U2KcMyUJ+vItlrThr4qwgpHG3i/N0w==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.427.0.tgz", + "integrity": "sha512-NmH1cO/w98CKMltYec3IrJIIco19wRjATFNiw83c+FGXZ+InJwReqBnruxIOmKTx2KDzd6fwU1HOewS7UjaaaQ==", + "peer": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.425.0", + "@aws-sdk/credential-provider-process": "3.425.0", + "@aws-sdk/credential-provider-sso": "3.427.0", + "@aws-sdk/credential-provider-web-identity": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.427.0.tgz", + "integrity": "sha512-wYYbQ57nKL8OfgRbl8k6uXcdnYml+p3LSSfDUAuUEp1HKlQ8lOXFJ3BdLr5qrk7LhpyppSRnWBmh2c3kWa7ANQ==", + "peer": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.425.0", + "@aws-sdk/credential-provider-ini": "3.427.0", + "@aws-sdk/credential-provider-process": "3.425.0", + "@aws-sdk/credential-provider-sso": "3.427.0", + "@aws-sdk/credential-provider-web-identity": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.425.0.tgz", + "integrity": "sha512-YY6tkLdvtb1Fgofp3b1UWO+5vwS14LJ/smGmuGpSba0V7gFJRdcrJ9bcb9vVgAGuMdjzRJ+bUKlLLtqXkaykEw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.427.0.tgz", + "integrity": "sha512-c+tXyS/i49erHs4bAp6vKNYeYlyQ0VNMBgoco0LCn1rL0REtHbfhWMnqDLF6c2n3yIWDOTrQu0D73Idnpy16eA==", + "peer": true, + "dependencies": { + "@aws-sdk/client-sso": "3.427.0", + "@aws-sdk/token-providers": "3.427.0", + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.425.0.tgz", + "integrity": "sha512-/0R65TgRzL01JU3SzloivWNwdkbIhr06uY/F5pBHf/DynQqaspKNfdHn6AiozgSVDfwRHFjKBTUy6wvf3QFkuA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.427.0.tgz", + "integrity": "sha512-JE26Zo4SMMY2SGlD/FilF5MpLuP8D2IrW+ye/J77dwh91gyGnNa/lubJ7WbVjIAxgeaDHsAkcpNO4VR5k6JCKg==", + "dependencies": { + "@smithy/abort-controller": "^2.0.1", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/smithy-client": "^2.1.9", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.425.0.tgz", + "integrity": "sha512-7UTfA10fmDw9cgHLApxRUNPywZTG4S/1TNZgTxndO/1OM9ZHtIatw1iLbqJD35gHrpEYI8Vo14YvcnD2ITuiMw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.425.0.tgz", + "integrity": "sha512-CqAmnDST2o7+sKKw2/ffHKiYKE+jZb/Ce9U0P//ZYzqp9R1Wb016ID+W6DoxufyPJAS9dpRMcUDnAssmMIC/EA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.425.0.tgz", + "integrity": "sha512-BDwn2vVVsC/AzmHXQlaZhEpKXL7GfKFpH7ZFccZuwEQBcyn8lVCcwtfaRe5P1mEe2wklVzOXd1dw8bt0+BOUPA==", + "peer": true, + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@aws-crypto/crc32c": "3.0.0", + "@aws-sdk/types": "3.425.0", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.425.0.tgz", + "integrity": "sha512-E5Gt41LObQ+cr8QnLthwsH3MtVSNXy1AKJMowDr85h0vzqA/FHUkgHyOGntgozzjXT5M0MaSRYxS0xwTR5D4Ew==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.425.0.tgz", + "integrity": "sha512-3rt0LpGmL1LCRFuEObS1yERd9OEV+AEIAvhY7b53M7u7SyrjWQtpntWkI365L/QljhgMXQBfps2qO4JtrhQnsA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.425.0.tgz", + "integrity": "sha512-INE9XWRXx2f4a/r2vOU0tAmgctVp7nEaEasemNtVBYhqbKLZvr9ndLBSgKGgJ8LIcXAoISipaMuFiqIGkFsm7A==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.425.0.tgz", + "integrity": "sha512-77gnzJ5b91bgD75L/ugpOyerx6lR3oyS4080X1YI58EzdyBMkDrHM4FbMcY2RynETi3lwXCFzLRyZjWXY1mRlw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.427.0.tgz", + "integrity": "sha512-virGCf9vsqYCLpmngLOZOVSYgVr2cCOCvTuRoT9vf5tD/63JwaC173jnbdoJO6CWI7ID5Iz0eNdgITXVQ2mpew==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.425.0.tgz", + "integrity": "sha512-JFojrg76oKAoBknnr9EL5N2aJ1mRCtBqXoZYST58GSx8uYdFQ89qS65VNQ8JviBXzsrCNAn4vDhZ5Ch5E6TxGQ==", + "peer": true, + "dependencies": { + "@aws-sdk/middleware-signing": "3.425.0", + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.425.0.tgz", + "integrity": "sha512-ZpOfgJHk7ovQ0sSwg3tU4NxFOnz53lJlkJRf7S+wxQALHM0P2MJ6LYBrZaFMVsKiJxNIdZBXD6jclgHg72ZW6Q==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.425.0.tgz", + "integrity": "sha512-9HTuXnHYAZWkwPC8x9tElsQjFPxDT//orbIFauS7VF5HkLCKn9J6O6lW1wKMxrEnDwfN/Vi3nw479MoPj5Ss0Q==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.427.0.tgz", + "integrity": "sha512-y9HxYsNvnA3KqDl8w1jHeCwz4P9CuBEtu/G+KYffLeAMBsMZmh4SIkFFCO9wE/dyYg6+yo07rYcnnIfy7WA0bw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.425.0.tgz", + "integrity": "sha512-u7uv/iUOapIJdRgRkO3wnpYsUgV6ponsZJQgVg/8L+n+Vo5PQL5gAcIuAOwcYSKQPFaeK+KbmByI4SyOK203Vw==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.425.0.tgz", + "integrity": "sha512-7n2FRPE9rLaVa26xXQJ8TExrt53dWN824axQd1a0r5va0SmMQYG/iV5LBmwUlAntUSq46Lse4Q5YnbOVedGOmw==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.427.0.tgz", + "integrity": "sha512-4E5E+4p8lJ69PBY400dJXF06LUHYx5lkKzBEsYqWWhoZcoftrvi24ltIhUDoGVLkrLcTHZIWSdFAWSos4hXqeg==", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.425.0", + "@aws-sdk/middleware-logger": "3.425.0", + "@aws-sdk/middleware-recursion-detection": "3.425.0", + "@aws-sdk/middleware-user-agent": "3.427.0", + "@aws-sdk/types": "3.425.0", + "@aws-sdk/util-endpoints": "3.427.0", + "@aws-sdk/util-user-agent-browser": "3.425.0", + "@aws-sdk/util-user-agent-node": "3.425.0", + "@smithy/config-resolver": "^2.0.11", + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/hash-node": "^2.0.10", + "@smithy/invalid-dependency": "^2.0.10", + "@smithy/middleware-content-length": "^2.0.12", + "@smithy/middleware-endpoint": "^2.0.10", + "@smithy/middleware-retry": "^2.0.13", + "@smithy/middleware-serde": "^2.0.10", + "@smithy/middleware-stack": "^2.0.4", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.6", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.13", + "@smithy/util-defaults-mode-node": "^2.0.15", + "@smithy/util-retry": "^2.0.3", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.425.0.tgz", + "integrity": "sha512-6lqbmorwerN4v+J5dqbHPAsjynI0mkEF+blf+69QTaKKGaxBBVaXgqoqul9RXYcK5MMrrYRbQIMd0zYOoy90kA==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz", + "integrity": "sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.427.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.427.0.tgz", + "integrity": "sha512-rSyiAIFF/EVvity/+LWUqoTMJ0a25RAc9iqx0WZ4tf1UjuEXRRXxZEb+jEZg1bk+pY84gdLdx9z5E+MSJCZxNQ==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/node-config-provider": "^2.0.13", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.425.0.tgz", + "integrity": "sha512-22Y9iMtjGcFjGILR6/xdp1qRezlHVLyXtnpEsbuPTiernRCPk6zfAnK/ATH77r02MUjU057tdxVkd5umUBTn9Q==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/types": "^2.3.4", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.425.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.425.0.tgz", + "integrity": "sha512-SIR4F5uQeeVAi8lv4OgRirtdtNi5zeyogTuQgGi9su8F/WP1N6JqxofcwpUY5f8/oJ2UlXr/tx1f09UHfJJzvA==", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.425.0", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "peer": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz", + "integrity": "sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -66,7 +893,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -78,7 +904,6 @@ "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", @@ -92,7 +917,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -100,47 +924,43 @@ "node_modules/@babel/code-frame/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", - "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.10", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -151,13 +971,17 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", "dependencies": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.23.5", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -166,14 +990,24 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", - "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", - "dev": true, + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dependencies": { "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -183,22 +1017,20 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", - "dev": true, + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dev": true, + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -208,7 +1040,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -217,28 +1048,26 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", - "dev": true, + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", - "dev": true, + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -251,7 +1080,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -260,7 +1088,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -272,7 +1099,6 @@ "version": "7.22.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -281,53 +1107,48 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "dev": true, + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", - "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", - "dev": true, + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -339,7 +1160,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -351,7 +1171,6 @@ "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", @@ -365,7 +1184,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -373,23 +1191,20 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -397,10 +1212,24 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", - "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -413,9 +1242,9 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", - "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -428,10 +1257,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", - "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", + "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -440,33 +1268,31 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", - "dev": true, + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -475,13 +1301,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", - "dev": true, + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -530,7 +1355,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", - "dev": true, "dependencies": { "@emotion/memoize": "^0.8.1" } @@ -538,8 +1362,7 @@ "node_modules/@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", - "dev": true + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "node_modules/@emotion/react": { "version": "11.11.1", @@ -607,6 +1430,11 @@ } } }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, "node_modules/@emotion/unitless": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", @@ -635,9 +1463,9 @@ "dev": true }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz", + "integrity": "sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==", "cpu": [ "arm" ], @@ -651,9 +1479,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz", + "integrity": "sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==", "cpu": [ "arm64" ], @@ -667,9 +1495,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.8.tgz", + "integrity": "sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==", "cpu": [ "x64" ], @@ -683,9 +1511,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz", + "integrity": "sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==", "cpu": [ "arm64" ], @@ -699,9 +1527,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz", + "integrity": "sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==", "cpu": [ "x64" ], @@ -715,9 +1543,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz", + "integrity": "sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==", "cpu": [ "arm64" ], @@ -731,9 +1559,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz", + "integrity": "sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==", "cpu": [ "x64" ], @@ -747,9 +1575,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz", + "integrity": "sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==", "cpu": [ "arm" ], @@ -763,9 +1591,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz", + "integrity": "sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==", "cpu": [ "arm64" ], @@ -779,9 +1607,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz", + "integrity": "sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==", "cpu": [ "ia32" ], @@ -795,9 +1623,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz", + "integrity": "sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==", "cpu": [ "loong64" ], @@ -811,9 +1639,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz", + "integrity": "sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==", "cpu": [ "mips64el" ], @@ -827,9 +1655,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz", + "integrity": "sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==", "cpu": [ "ppc64" ], @@ -843,9 +1671,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz", + "integrity": "sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==", "cpu": [ "riscv64" ], @@ -859,9 +1687,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz", + "integrity": "sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==", "cpu": [ "s390x" ], @@ -875,9 +1703,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz", + "integrity": "sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==", "cpu": [ "x64" ], @@ -891,9 +1719,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz", + "integrity": "sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==", "cpu": [ "x64" ], @@ -907,9 +1735,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz", + "integrity": "sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==", "cpu": [ "x64" ], @@ -923,9 +1751,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz", + "integrity": "sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==", "cpu": [ "x64" ], @@ -939,9 +1767,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz", + "integrity": "sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==", "cpu": [ "arm64" ], @@ -955,9 +1783,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz", + "integrity": "sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==", "cpu": [ "ia32" ], @@ -971,9 +1799,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz", + "integrity": "sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==", "cpu": [ "x64" ], @@ -986,11 +1814,190 @@ "node": ">=12" } }, + "node_modules/@floating-ui/core": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz", + "integrity": "sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==", + "dev": true, + "dependencies": { + "@floating-ui/utils": "^0.1.3" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", + "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "dev": true, + "dependencies": { + "@floating-ui/core": "^1.4.2", + "@floating-ui/utils": "^0.1.3" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", + "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "dev": true, + "dependencies": { + "@floating-ui/dom": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", + "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==", + "dev": true + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", + "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", + "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-skeleton-parser": "1.3.6", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", + "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.2.1.tgz", + "integrity": "sha512-vgvyUOOrzqVaOFYzTf2d3+ToSkH2JpR7x/4U1RyoHQLmvEaTQvXJ7A2qm1Iy3brGNXC/+/7bUlc3lpH+h/LOJA==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "@formatjs/intl-displaynames": "5.4.3", + "@formatjs/intl-listformat": "6.5.3", + "intl-messageformat": "9.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "typescript": "^4.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@formatjs/intl-displaynames": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-5.4.3.tgz", + "integrity": "sha512-4r12A3mS5dp5hnSaQCWBuBNfi9Amgx2dzhU4lTFfhSxgb5DOAiAbMpg6+7gpWZgl4ahsj3l2r/iHIjdmdXOE2Q==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl-listformat": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-6.5.3.tgz", + "integrity": "sha512-ozpz515F/+3CU+HnLi5DYPsLa6JoCfBggBSSg/8nOB5LYSFW9+ZgNQJxJ8tdhKYeODT+4qVHX27EeJLoxLGLNg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.13.1.tgz", + "integrity": "sha512-dKwF+NpIV2LVCNBA7hibH53k+ChF4Wu59P2z35gu3zwRBZpmpLVhS9k1/RiSqUqkyXUQvA2rSv48GY6wp5axZQ==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.29" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", + "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.x" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1004,7 +2011,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1013,7 +2019,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1021,26 +2026,24 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "dev": true, + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@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==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.20.0.tgz", + "integrity": "sha512-xxlv5GLX4FVR/dDKEsmi4SPeuB49aRc35stndyxcC73XnUEEwF39vXbROpHOirmDse8WE9vxOjABnSVS+jb7EA==", "dependencies": { "@types/js-yaml": "^4.0.1", - "@types/node": "^18.11.17", + "@types/node": "^20.1.1", "@types/request": "^2.47.1", "@types/ws": "^8.5.3", "byline": "^5.0.0", @@ -1051,9 +2054,7 @@ "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": { @@ -1123,27 +2124,39 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/base": { - "version": "5.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.11.tgz", - "integrity": "sha512-FdKZGPd8qmC3ZNke7CNhzcEgToc02M6WYZc9hcBsNQ17bgAd3s9F//1bDDYgMVBYxDM71V0sv/hBHlOY4I1ZVA==", + "version": "5.0.0-beta.26", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", + "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@emotion/is-prop-valid": "^1.2.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.4", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", "@popperjs/core": "^2.11.8", "clsx": "^2.0.0", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -1157,29 +2170,29 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.5.tgz", - "integrity": "sha512-+wpGH1USwPcKMFPMvXqYPC6fEvhxM3FzxC8lyDiNK/imLyyJ6y2DPb1Oue7OGIKJWBmYBqrWWtfovrxd1aJHTA==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", + "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==", "dev": true, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.14.3", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.3.tgz", - "integrity": "sha512-XkxWPhageu1OPUm2LWjo5XqeQ0t2xfGe8EiLkRW9oz2LHMMZmijvCxulhgquUVTF1DnoSh+3KoDLSsoAFtVNVw==", + "version": "5.14.19", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.19.tgz", + "integrity": "sha512-yjP8nluXxZGe3Y7pS+yxBV+hWZSsSBampCxkZwaw+1l+feL+rfP74vbEFbMrX/Kil9I/Y1tWfy5bs/eNvwNpWw==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6" + "@babel/runtime": "^7.23.4" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@mui/material": "^5.0.0", @@ -1193,18 +2206,18 @@ } }, "node_modules/@mui/material": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.5.tgz", - "integrity": "sha512-4qa4GMfuZH0Ai3mttk5ccXP8a3sf7aPlAJwyMrUSz6h9hPri6BPou94zeu3rENhhmKLby9S/W1y+pmficy8JKA==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", + "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@mui/base": "5.0.0-beta.11", - "@mui/core-downloads-tracker": "^5.14.5", - "@mui/system": "^5.14.5", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.5", - "@types/react-transition-group": "^4.4.6", + "@babel/runtime": "^7.23.4", + "@mui/base": "5.0.0-beta.26", + "@mui/core-downloads-tracker": "^5.14.20", + "@mui/system": "^5.14.20", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@types/react-transition-group": "^4.4.9", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", @@ -1216,7 +2229,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -1238,13 +2251,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.5.tgz", - "integrity": "sha512-cC4C5RrpXpDaaZyH9QwmPhRLgz+f2SYbOty3cPkk4qPSOSfif2ZEcDD9HTENKDDd9deB+xkPKzzZhi8cxIx8Ig==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", + "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.4", + "@mui/utils": "^5.14.20", "prop-types": "^15.8.1" }, "engines": { @@ -1252,7 +2265,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -1265,12 +2278,12 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz", - "integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", + "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", "dev": true, "dependencies": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.23.4", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1280,7 +2293,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -1297,16 +2310,16 @@ } }, "node_modules/@mui/system": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.5.tgz", - "integrity": "sha512-mextXZHDeGcR7E1kx43TRARrVXy+gI4wzpUgNv7MqZs1dvTVXQGVeAT6ydj9d6FUqHBPMNLGV/21vJOrpqsL+w==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", + "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@mui/private-theming": "^5.14.5", - "@mui/styled-engine": "^5.13.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.5", + "@babel/runtime": "^7.23.4", + "@mui/private-theming": "^5.14.20", + "@mui/styled-engine": "^5.14.19", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1316,7 +2329,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -1337,12 +2350,12 @@ } }, "node_modules/@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", + "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", "dev": true, "peerDependencies": { - "@types/react": "*" + "@types/react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1351,14 +2364,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.5.tgz", - "integrity": "sha512-6Hzw63VR9C5xYv+CbjndoRLU6Gntal8rJ5W+GUzkyHrGWIyYPWZPa6AevnyGioySNETATe1H9oXS8f/7qgIHJA==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", + "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.22.6", - "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.1", + "@babel/runtime": "^7.23.4", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1367,10 +2379,16 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@popperjs/core": { @@ -1383,24 +2401,869 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-dnd/asap": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", + "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==" + }, + "node_modules/@react-dnd/invariant": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", + "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz", - "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz", + "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==", "dev": true, "engines": { "node": ">=14.0.0" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.7.0.tgz", + "integrity": "sha512-rGku10pL1StFlFvXX5pEv88KdGW6DHUghsxyP/aRYb9eH+74jTGJ3U0S/rtlsQ4yYq1Hcc7AMkoJOb1xu29Fxw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.7.0.tgz", + "integrity": "sha512-/EBw0cuJ/KVHiU2qyVYUhogXz7W2vXxBzeE9xtVIMC+RyitlY2vvaoysMUqASpkUtoNIHlnKTu/l7mXOPgnKOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.7.0.tgz", + "integrity": "sha512-4VXG1bgvClJdbEYYjQ85RkOtwN8sqI3uCxH0HC5w9fKdqzRzgG39K7GAehATGS8jghA7zNoS5CjSKkDEqWmNZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.7.0.tgz", + "integrity": "sha512-/ImhO+T/RWJ96hUbxiCn2yWI0/MeQZV/aeukQQfhxiSXuZJfyqtdHPUPrc84jxCfXTxbJLmg4q+GBETeb61aNw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.7.0.tgz", + "integrity": "sha512-zhye8POvTyUXlKbfPBVqoHy3t43gIgffY+7qBFqFxNqVtltQLtWeHNAbrMnXiLIfYmxcoL/feuLDote2tx+Qbg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.7.0.tgz", + "integrity": "sha512-RAdr3OJnUum6Vs83cQmKjxdTg31zJnLLTkjhcFt0auxM6jw00GD6IPFF42uasYPr/wGC6TRm7FsQiJyk0qIEfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.7.0.tgz", + "integrity": "sha512-nhWwYsiJwZGq7SyR3afS3EekEOsEAlrNMpPC4ZDKn5ooYSEjDLe9W/xGvoIV8/F/+HNIY6jY8lIdXjjxfxopXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.7.0.tgz", + "integrity": "sha512-rlfy5RnQG1aop1BL/gjdH42M2geMUyVQqd52GJVirqYc787A/XVvl3kQ5NG/43KXgOgE9HXgCaEH05kzQ+hLoA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.7.0.tgz", + "integrity": "sha512-cCkoGlGWfBobdDtiiypxf79q6k3/iRVGu1HVLbD92gWV5WZbmuWJCgRM4x2N6i7ljGn1cGytPn9ZAfS8UwF6vg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.7.0.tgz", + "integrity": "sha512-R2oBf2p/Arc1m+tWmiWbpHBjEcJnHVnv6bsypu4tcKdrYTpDfl1UT9qTyfkIL1iiii5D4WHxUHCg5X0pzqmxFg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.7.0.tgz", + "integrity": "sha512-CPtgaQL1aaPc80m8SCVEoxFGHxKYIt3zQYC3AccL/SqqiWXblo3pgToHuBwR8eCP2Toa+X1WmTR/QKFMykws7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.7.0.tgz", + "integrity": "sha512-pmioUlttNh9GXF5x2CzNa7Z8kmRTyhEzzAC+2WOOapjewMbl+3tGuAnxbwc5JyG8Jsz2+hf/QD/n5VjimOZ63g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.7.0.tgz", + "integrity": "sha512-SeZzC2QhhdBQUm3U0c8+c/P6UlRyBcLL2Xp5KX7z46WXZxzR8RJSIWL9wSUeBTgxog5LTPJuPj0WOT9lvrtP7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@smithy/abort-controller": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.11.tgz", + "integrity": "sha512-MSzE1qR2JNyb7ot3blIOT3O3H0Jn06iNDEgHRaqZUwBgx5EG+VIx24Y21tlKofzYryIOcWpIohLrIIyocD6LMA==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz", + "integrity": "sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.0.tgz", + "integrity": "sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==", + "peer": true, + "dependencies": { + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.14.tgz", + "integrity": "sha512-K1K+FuWQoy8j/G7lAmK85o03O89s2Vvh6kMFmzEmiHUoQCRH1rzbDtMnGNiaMHeSeYJ6y79IyTusdRG+LuWwtg==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.1", + "@smithy/types": "^2.3.5", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.16.tgz", + "integrity": "sha512-tKa2xF+69TvGxJT+lnJpGrKxUuAZDLYXFhqnPEgnHz+psTpkpcB4QRjHj63+uj83KaeFJdTfW201eLZeRn6FfA==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.1", + "@smithy/property-provider": "^2.0.12", + "@smithy/types": "^2.3.5", + "@smithy/url-parser": "^2.0.11", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.11.tgz", + "integrity": "sha512-BQCTjxhCYRZIfXapa2LmZSaH8QUBGwMZw7XRN83hrdixbLjIcj+o549zjkedFS07Ve2TlvWUI6BTzP+nv7snBA==", + "peer": true, + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.5", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.11.tgz", + "integrity": "sha512-p9IK4uvwT6B3pT1VGlODvcVBfPVikjBFHAcKpvvNF+7lAEI+YiC6d0SROPkpjnvCgVBYyGXa3ciqrWnFze6mwQ==", + "peer": true, + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.11.tgz", + "integrity": "sha512-vN32E8yExo0Z8L7kXhlU9KRURrhqOpPdLxQMp3MwfMThrjiqbr1Sk5srUXc1ed2Ygl/l0TEN9vwNG0bQHg6AjQ==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.11.tgz", + "integrity": "sha512-Gjqbpg7UmD+YzkpgNShNcDNZcUpBWIkvX2XCGptz5PoxJU/UQbuF9eSc93ZlIb7j4aGjtFfqk23HUMW8Hopg2Q==", + "peer": true, + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.11.tgz", + "integrity": "sha512-F8FsxLTbFN4+Esgpo+nNKcEajrgRZJ+pG9c8+MhLM4Odp5ejLHw2GMCXd81cGsgmfcbnzdDEXazPPVzOwj89MQ==", + "peer": true, + "dependencies": { + "@smithy/eventstream-codec": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.2.tgz", + "integrity": "sha512-K7aRtRuaBjzlk+jWWeyfDTLAmRRvmA4fU8eHUXtjsuEDgi3f356ZE32VD2ssxIH13RCLVZbXMt5h7wHzYiSuVA==", + "dependencies": { + "@smithy/protocol-http": "^3.0.7", + "@smithy/querystring-builder": "^2.0.11", + "@smithy/types": "^2.3.5", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.11.tgz", + "integrity": "sha512-/6vq/NiH2EN3mWdwcLdjVohP+VCng+ZA1GnlUdx959egsfgIlLWQvCyjnB2ze9Hr6VHV5XEFLLpLQH2dHA6Sgw==", + "peer": true, + "dependencies": { + "@smithy/chunked-blob-reader": "^2.0.0", + "@smithy/chunked-blob-reader-native": "^2.0.0", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.11.tgz", + "integrity": "sha512-PbleVugN2tbhl1ZoNWVrZ1oTFFas/Hq+s6zGO8B9bv4w/StTriTKA9W+xZJACOj9X7zwfoTLbscM+avCB1KqOQ==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.0.11.tgz", + "integrity": "sha512-Jn2yl+Dn0kvwKvSavvR1/BFVYa2wIkaJKWeTH48kno89gqHAJxMh1hrtBN6SJ7F8VhodNZTiNOlQVqCSfLheNQ==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.11.tgz", + "integrity": "sha512-zazq99ujxYv/NOf9zh7xXbNgzoVLsqE0wle8P/1zU/XdhPi/0zohTPKWUzIxjGdqb5hkkwfBkNkl5H+LE0mvgw==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.0.11.tgz", + "integrity": "sha512-YBIv+e95qeGvQA05ucwstmTeQ/bUzWgU+nO2Ffmif5awu6IzSR0Jfk3XLYh4mdy7f8DCgsn8qA63u7N9Lu0+5A==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.13.tgz", + "integrity": "sha512-Md2kxWpaec3bXp1oERFPQPBhOXCkGSAF7uc1E+4rkwjgw3/tqAXRtbjbggu67HJdwaif76As8AV6XxbD1HzqTQ==", + "peer": true, + "dependencies": { + "@smithy/protocol-http": "^3.0.7", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.11.tgz", + "integrity": "sha512-mCugsvB15up6fqpzUEpMT4CuJmFkEI+KcozA7QMzYguXCaIilyMKsyxgamwmr+o7lo3QdjN0//XLQ9bWFL129g==", + "dependencies": { + "@smithy/middleware-serde": "^2.0.11", + "@smithy/types": "^2.3.5", + "@smithy/url-parser": "^2.0.11", + "@smithy/util-middleware": "^2.0.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.16.tgz", + "integrity": "sha512-Br5+0yoiMS0ugiOAfJxregzMMGIRCbX4PYo1kDHtLgvkA/d++aHbnHB819m5zOIAMPvPE7AThZgcsoK+WOsUTA==", + "peer": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.1", + "@smithy/protocol-http": "^3.0.7", + "@smithy/service-error-classification": "^2.0.4", + "@smithy/types": "^2.3.5", + "@smithy/util-middleware": "^2.0.4", + "@smithy/util-retry": "^2.0.4", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.11.tgz", + "integrity": "sha512-NuxnjMyf4zQqhwwdh0OTj5RqpnuT6HcH5Xg5GrPijPcKzc2REXVEVK4Yyk8ckj8ez1XSj/bCmJ+oNjmqB02GWA==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.5.tgz", + "integrity": "sha512-bVQU/rZzBY7CbSxIrDTGZYnBWKtIw+PL/cRc9B7etZk1IKSOe0NvKMJyWllfhfhrTeMF6eleCzOihIQympAvPw==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.1.tgz", + "integrity": "sha512-1lF6s1YWBi1LBu2O30tD3jyTgMtuvk/Z1twzXM4GPYe4dmZix4nNREPJIPOcfFikNU2o0eTYP80+izx5F2jIJA==", + "peer": true, + "dependencies": { + "@smithy/property-provider": "^2.0.12", + "@smithy/shared-ini-file-loader": "^2.2.0", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.7.tgz", + "integrity": "sha512-PQIKZXlp3awCDn/xNlCSTFE7aYG/5Tx33M05NfQmWYeB5yV1GZZOSz4dXpwiNJYTXb9jPqjl+ueXXkwtEluFFA==", + "dependencies": { + "@smithy/abort-controller": "^2.0.11", + "@smithy/protocol-http": "^3.0.7", + "@smithy/querystring-builder": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.12.tgz", + "integrity": "sha512-Un/OvvuQ1Kg8WYtoMCicfsFFuHb/TKL3pCA6ZIo/WvNTJTR94RtoRnL7mY4XkkUAoFMyf6KjcQJ76y1FX7S5rw==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.7.tgz", + "integrity": "sha512-HnZW8y+r66ntYueCDbLqKwWcMNWW8o3eVpSrHNluwtBJ/EUWfQHRKSiu6vZZtc6PGfPQWgVfucoCE/C3QufMAA==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.11.tgz", + "integrity": "sha512-b4kEbVMxpmfv2VWUITn2otckTi7GlMteZQxi+jlwedoATOGEyrCJPfRcYQJjbCi3fZ2QTfh3PcORvB27+j38Yg==", + "dependencies": { + "@smithy/types": "^2.3.5", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.11.tgz", + "integrity": "sha512-YXe7jhi7s3dQ0Fu9dLoY/gLu6NCyy8tBWJL/v2c9i7/RLpHgKT+uT96/OqZkHizCJ4kr0ZD46tzMjql/o60KLg==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.4.tgz", + "integrity": "sha512-77506l12I5gxTZqBkx3Wb0RqMG81bMYLaVQ+EqIWFwQDJRs5UFeXogKxSKojCmz1wLUziHZQXm03MBzPQiumQw==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.0.tgz", + "integrity": "sha512-xFXqs4vAb5BdkzHSRrTapFoaqS4/3m/CGZzdw46fBjYZ0paYuLAoMY60ICCn1FfGirG+PiJ3eWcqJNe4/SkfyA==", + "peer": true, + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.11.tgz", + "integrity": "sha512-EFVU1dT+2s8xi227l1A9O27edT/GNKvyAK6lZnIZ0zhIHq/jSLznvkk15aonGAM1kmhmZBVGpI7Tt0odueZK9A==", + "peer": true, + "dependencies": { + "@smithy/eventstream-codec": "^2.0.11", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.5", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.4", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.10.tgz", + "integrity": "sha512-2OEmZDiW1Z196QHuQZ5M6cBE8FCSG0H2HADP1G+DY8P3agsvb0YJyfhyKuJbxIQy15tr3eDAK6FOrlbxgKOOew==", + "dependencies": { + "@smithy/middleware-stack": "^2.0.5", + "@smithy/types": "^2.3.5", + "@smithy/util-stream": "^2.0.15", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.5.tgz", + "integrity": "sha512-ehyDt8M9hehyxrLQGoA1BGPou8Js1Ocoh5M0ngDhJMqbFmNK5N6Xhr9/ZExWkyIW8XcGkiMPq3ZUEE0ScrhbuQ==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.11.tgz", + "integrity": "sha512-h89yXMCCF+S5k9XIoKltMIWTYj+FcEkU/IIFZ6RtE222fskOTL4Iak6ZRG+ehSvZDt8yKEcxqheTDq7JvvtK3g==", + "dependencies": { + "@smithy/querystring-parser": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "peer": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.14.tgz", + "integrity": "sha512-NupG7SWUucm3vJrvlpt9jG1XeoPJphjcivgcUUXhDJbUPy4F04LhlTiAhWSzwlCNcF8OJsMvZ/DWbpYD3pselw==", + "peer": true, + "dependencies": { + "@smithy/property-provider": "^2.0.12", + "@smithy/smithy-client": "^2.1.10", + "@smithy/types": "^2.3.5", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.18.tgz", + "integrity": "sha512-+3jMom/b/Cdp21tDnY4vKu249Al+G/P0HbRbct7/aSZDlROzv1tksaYukon6UUv7uoHn+/McqnsvqZHLlqvQ0g==", + "peer": true, + "dependencies": { + "@smithy/config-resolver": "^2.0.14", + "@smithy/credential-provider-imds": "^2.0.16", + "@smithy/node-config-provider": "^2.1.1", + "@smithy/property-provider": "^2.0.12", + "@smithy/smithy-client": "^2.1.10", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.4.tgz", + "integrity": "sha512-Pbu6P4MBwRcjrLgdTR1O4Y3c0sTZn2JdOiJNcgL7EcIStcQodj+6ZTXtbyU/WTEU3MV2NMA10LxFc3AWHZ3+4A==", + "dependencies": { + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.4.tgz", + "integrity": "sha512-b+n1jBBKc77C1E/zfBe1Zo7S9OXGBiGn55N0apfhZHxPUP/fMH5AhFUUcWaJh7NAnah284M5lGkBKuhnr3yK5w==", + "peer": true, + "dependencies": { + "@smithy/service-error-classification": "^2.0.4", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.15.tgz", + "integrity": "sha512-A/hkYJPH2N5MCWYvky4tTpQihpYAEzqnUfxDyG3L/yMndy/2sLvxnyQal9Opuj1e9FiKSTeMyjnU9xxZGs0mRw==", + "dependencies": { + "@smithy/fetch-http-handler": "^2.2.2", + "@smithy/node-http-handler": "^2.1.7", + "@smithy/types": "^2.3.5", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.11.tgz", + "integrity": "sha512-8SJWUl9O1YhjC77EccgltI3q4XZQp3vp9DGEW6o0OdkUcwqm/H4qOLnMkA2n+NDojuM5Iia2jWoCdbluIiG7TA==", + "peer": true, + "dependencies": { + "@smithy/abort-controller": "^2.0.11", + "@smithy/types": "^2.3.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "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.33.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.33.0.tgz", - "integrity": "sha512-qYu73ptvnzRh6se2nyBIDHGBQvPY1XXl3yR769B7B6mIDD7s+EZhdlWHQ67JI6UOTFRaI7wupnTnwJ3gE0Mr/g==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.12.1.tgz", + "integrity": "sha512-WbZztNmKq0t6QjdNmHzezbi/uifYo9j6e2GLJkodsYaYUlzMbAp91RDyeHkIZrm7EfO4wa6Sm5sxJZm5SPlh6w==", "dev": true, "funding": { "type": "github", @@ -1408,30 +3271,60 @@ } }, "node_modules/@tanstack/react-query": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.33.0.tgz", - "integrity": "sha512-97nGbmDK0/m0B86BdiXzx3EW9RcDYKpnyL2+WwyuLHEgpfThYAnXFaMMmnTDuAO4bQJXEhflumIEUfKmP7ESGA==", + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.12.2.tgz", + "integrity": "sha512-BeWZu8zVFH20oRc+S/K9ADPgWjEzP/XQCGBNz5IbApUwPQAdwkQYbXODVL5AyAlWiSxhx+P2xlARPBApj2Yrog==", "dev": true, "dependencies": { - "@tanstack/query-core": "4.33.0", - "use-sync-external-store": "^1.2.0" + "@tanstack/query-core": "5.12.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } + "react": "^18.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" } }, "node_modules/@types/caseless": { @@ -1439,6 +3332,15 @@ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, + "node_modules/@types/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A==", + "deprecated": "This is a stub types definition. classnames provides its own type definitions, so you do not need this installed.", + "dependencies": { + "classnames": "*" + } + }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -1452,15 +3354,34 @@ "@types/node": "*" } }, + "node_modules/@types/fuzzy-search": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/fuzzy-search/-/fuzzy-search-2.1.5.tgz", + "integrity": "sha512-Yw8OsjhVKbKw83LMDOZ9RXc+N+um48DmZYMrz7QChpHkQuygsc5O40oCL7SfvWgpaaviCx2TbNXYUBwhMtBH5w==" + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "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/memoizee": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@types/memoizee/-/memoizee-0.4.11.tgz", + "integrity": "sha512-2gyorIBZu8GoDr9pYjROkxWWcFtHCquF7TVbN2I+/OvgZhnIGQS0vX5KJz4lXNKb8XOSfxFOSG5OLru1ESqLUg==" + }, "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==" + "version": "20.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", + "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -1469,40 +3390,60 @@ "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 + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "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, + "version": "17.0.73", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.73.tgz", + "integrity": "sha512-6AcjgPIVsXTIsFDgsGW0iQhvg0xb2vt2qAWgXyncnVNRaW9ZXTTwAh7RQoh7PzK1AhjPoGDvUBkdAREih9n5oQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, - "node_modules/@types/react-is": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", - "integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==", - "dev": true, + "node_modules/@types/react-redux": { + "version": "7.1.33", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz", + "integrity": "sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/react-transition-group": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", - "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", - "dev": true, + "node_modules/@types/react-virtualized-auto-sizer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.4.tgz", + "integrity": "sha512-nhYwlFiYa8M3S+O2T9QO/e1FQUYMr/wJENUdf/O0dhRi1RS/93rjrYQFYdbUqtdFySuhrtnEDX29P6eKOttY+A==", "dependencies": { "@types/react": "*" } }, + "node_modules/@types/react-window": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz", + "integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/redux-watch": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/redux-watch/-/redux-watch-1.1.2.tgz", + "integrity": "sha512-pooK4MLNYmTyfOU7jy/ZmS2mpbSHkEVpWIcK4/BRbaegOnCB4PYA2JY88vBXE2LVkhPM+du1Z+lVzRiewMz6wg==" + }, "node_modules/@types/request": { "version": "2.48.8", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz", @@ -1517,8 +3458,12 @@ "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 + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/shortid": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", + "integrity": "sha512-9BCYD9btg2CY4kPcpMQ+vCR8U6V8f/KvixYD5ZbxoWlkhddNF5IeZMVL3p+QFUkg+Hb+kPAG9Jgk4bnnF1v/Fw==" }, "node_modules/@types/tough-cookie": { "version": "4.0.2", @@ -1534,21 +3479,22 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz", - "integrity": "sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", "dev": true, "dependencies": { - "@babel/core": "^7.22.9", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0" + "vite": "^4.2.0 || ^5.0.0" } }, "node_modules/abbrev": { @@ -1630,6 +3576,11 @@ "node": ">= 8" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -1665,6 +3616,14 @@ "safer-buffer": "~2.1.0" } }, + "node_modules/assert-options": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/assert-options/-/assert-options-0.8.1.tgz", + "integrity": "sha512-5lNGRB5g5i2bGIzb+J1QQE1iKU/WEMVBReFIc5pPDWjcPj23otPL0eI6PB2v7QPi0qU6Mhym5D3y0ZiSIOf3GA==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -1678,6 +3637,45 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1514.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1514.0.tgz", + "integrity": "sha512-ZQE5kHhJozwBB+Zaa21Gglm2pSQVU+8fFZNOn4pr+Kc1scYPlmVBPR3a0w19Vc4HNXPzjApAk2G4xMvzZDktAw==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1706,11 +3704,45 @@ "npm": ">=6" } }, + "node_modules/babel-plugin-styled-components": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz", + "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "lodash": "^4.17.21", + "picomatch": "^2.3.1" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, "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/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -1719,6 +3751,14 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/basic-ftp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", + "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", @@ -1785,6 +3825,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "peer": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1807,10 +3853,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "dev": true, + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "funding": [ { "type": "opencollective", @@ -1826,10 +3871,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -1838,6 +3883,40 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/byline": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", @@ -1875,11 +3954,18 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { - "version": "1.0.30001522", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", - "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==", - "dev": true, + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", "funding": [ { "type": "opencollective", @@ -1938,6 +4024,236 @@ "fsevents": "~2.3.2" } }, + "node_modules/chonky": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chonky/-/chonky-2.3.2.tgz", + "integrity": "sha512-ed2u+SEjEPSn8bv/zC0sXfMG/XS6Ydm4J2leLCvRb7a/2BZxKqE1DFETxqfLeJ2OA1IRujvwnuvmJO8ZgyOGyA==", + "dependencies": { + "@material-ui/core": "4.11.3", + "@reduxjs/toolkit": "^1.5.0", + "@types/classnames": "^2.2.11", + "@types/fuzzy-search": "^2.1.0", + "@types/memoizee": "^0.4.5", + "@types/react": "^17.0.3", + "@types/react-redux": "^7.1.16", + "@types/react-virtualized-auto-sizer": "^1.0.0", + "@types/react-window": "^1.8.2", + "@types/redux-watch": "^1.1.0", + "@types/shortid": "^0.0.29", + "classnames": "^2.2.6", + "deepmerge": "^4.2.2", + "exact-trie": "^1.0.13", + "fast-sort": "^2.2.0", + "filesize": "^6.1.0", + "fuzzy-search": "^3.2.1", + "hotkeys-js": "^3.8.3", + "react-dnd": "11", + "react-dnd-html5-backend": "11", + "react-intl": "^5.13.2", + "react-jss": "^10.5.1", + "react-redux": "^7.2.2", + "react-virtualized-auto-sizer": "^1.0.5", + "react-window": "^1.8.6", + "redux-watch": "^1.2.0", + "shortid": "^2.2.16", + "styled-components": "^5.3.0", + "tsdef": "^0.0.14" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/chonky-icon-fontawesome": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chonky-icon-fontawesome/-/chonky-icon-fontawesome-2.3.2.tgz", + "integrity": "sha512-19Duy25JxteIlQJfZKLH7ZSujU1zYBMLKovWDOLlw1EdPlXb9exsfYUUkwfNS+31KpwttfaqnGuN8Gyed/R6UQ==", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.32", + "@fortawesome/free-brands-svg-icons": "5.13.1", + "@fortawesome/free-solid-svg-icons": "^5.13.1", + "@fortawesome/react-fontawesome": "^0.1.12", + "chonky": "^2.3.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/chonky/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/chonky/node_modules/@material-ui/core": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.3.tgz", + "integrity": "sha512-Adt40rGW6Uds+cAyk3pVgcErpzU/qxc7KBR94jFHBYretU4AtWZltYcNsbeMn9tXL86jjVL1kuGcIHsgLgFGRw==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.3", + "@material-ui/system": "^4.11.3", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.11.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/chonky/node_modules/@material-ui/core/node_modules/@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/chonky/node_modules/@material-ui/core/node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/chonky/node_modules/@material-ui/core/node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/chonky/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chonky/node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/chonky/node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/chonky/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/chonky/node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1946,6 +4262,11 @@ "node": ">=10" } }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2011,10 +4332,51 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/concurrently": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.0.tgz", - "integrity": "sha512-nnLMxO2LU492mTUj9qX/az/lESonSZu81UznYDoXtz1IQf996ixVqPAgHXwvHiHCAef/7S8HIK+fTFK7Ifk8YA==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", "dev": true, "dependencies": { "chalk": "^4.1.2", @@ -2166,11 +4528,47 @@ "node": ">=10" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/css-jss/-/css-jss-10.10.0.tgz", + "integrity": "sha512-YyMIS/LsSKEGXEaVJdjonWe18p4vXLo8CMA4FrW/kcaEyqdIGKCFXao31gbJddXEdIxSXFFURWrenBJPlKTgAA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "^10.10.0", + "jss-preset-default": "^10.10.0" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/dashdash": { "version": "1.14.1", @@ -2215,6 +4613,14 @@ } } }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2253,11 +4659,20 @@ "node": ">=8" } }, + "node_modules/dnd-core": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-11.1.3.tgz", + "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", + "dependencies": { + "@react-dnd/asap": "^4.0.0", + "@react-dnd/invariant": "^2.0.0", + "redux": "^4.0.4" + } + }, "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" @@ -2278,10 +4693,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.497", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.497.tgz", - "integrity": "sha512-9cvj6XkrgyxDySKJWYVIyq7p9bOAkH3M3jANgvWNX/F2jIAfbBN4oBNLJg1i68I8wAKVuih2IL4y1n9hqbL3Aw==", - "dev": true + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -2355,9 +4769,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.19.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz", + "integrity": "sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==", "dev": true, "hasInstallScript": true, "bin": { @@ -2367,35 +4781,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/android-arm": "0.19.8", + "@esbuild/android-arm64": "0.19.8", + "@esbuild/android-x64": "0.19.8", + "@esbuild/darwin-arm64": "0.19.8", + "@esbuild/darwin-x64": "0.19.8", + "@esbuild/freebsd-arm64": "0.19.8", + "@esbuild/freebsd-x64": "0.19.8", + "@esbuild/linux-arm": "0.19.8", + "@esbuild/linux-arm64": "0.19.8", + "@esbuild/linux-ia32": "0.19.8", + "@esbuild/linux-loong64": "0.19.8", + "@esbuild/linux-mips64el": "0.19.8", + "@esbuild/linux-ppc64": "0.19.8", + "@esbuild/linux-riscv64": "0.19.8", + "@esbuild/linux-s390x": "0.19.8", + "@esbuild/linux-x64": "0.19.8", + "@esbuild/netbsd-x64": "0.19.8", + "@esbuild/openbsd-x64": "0.19.8", + "@esbuild/sunos-x64": "0.19.8", + "@esbuild/win32-arm64": "0.19.8", + "@esbuild/win32-ia32": "0.19.8", + "@esbuild/win32-x64": "0.19.8" } }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -2425,6 +4838,19 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/exact-trie": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/exact-trie/-/exact-trie-1.0.13.tgz", + "integrity": "sha512-2N0sx9jMlzZxRmSOpFKmcuaPcLXYLGRp69DohigW5E7R/uo9i6S1zJ/PuAckf70099am1ts7YBRMLO8Nr8AJLg==" + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -2502,10 +4928,37 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "node_modules/fast-sort": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fast-sort/-/fast-sort-2.2.0.tgz", + "integrity": "sha512-W7zqnn2zsYoQA87FKmYtgOsbJohOrh7XrtZrCVHN5XZKqTBTv5UG+rSS3+iWbg/nepRQUOu+wnas8BwtK8kiCg==" + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "peer": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/figlet": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.6.0.tgz", - "integrity": "sha512-31EQGhCEITv6+hi2ORRPyn3bulaV9Fl4xOdR169cBzH/n1UqcxsiSB/noo6SJdD7Kfb1Ljit+IgR1USvF/XbdA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.7.0.tgz", + "integrity": "sha512-gO8l3wvqo0V7wEFLXPbkX83b7MVjRrk1oRLfYlZXol8nEpb/ON9pcKLI4qpBv5YtOTfrINtqb7b40iYY2FTWFg==", "bin": { "figlet": "bin/index.js" }, @@ -2513,6 +4966,22 @@ "node": ">= 0.4.0" } }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/filesize": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", + "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", + "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", @@ -2561,6 +5030,14 @@ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2631,9 +5108,9 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -2649,6 +5126,11 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/fuzzy-search": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/fuzzy-search/-/fuzzy-search-3.2.1.tgz", + "integrity": "sha512-vAcPiyomt1ioKAsAL2uxSABHJ4Ju/e4UeDM+g1OlR0vV4YhLGMNsdLNvZTpEDY4JCSt0E4hASCNM5t2ETtsbyg==" + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -2672,7 +5154,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -2742,11 +5223,21 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2783,7 +5274,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -2799,6 +5289,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "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", @@ -2808,7 +5312,6 @@ "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" } @@ -2816,8 +5319,20 @@ "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 + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/hotkeys-js": { + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.13.2.tgz", + "integrity": "sha512-SXd+x90nhOdo5s+DZNPtrvXs0ZahQLXT0tWQ68bzjxCNUZ7eV4ZlNqjHLi3Kt2URpR8EBJOB2dBLdNfwIeql1A==", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" }, "node_modules/http-errors": { "version": "2.0.0", @@ -2860,6 +5375,11 @@ "node": ">= 6" } }, + "node_modules/hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2871,12 +5391,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "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/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2907,6 +5441,17 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/intl-messageformat": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", + "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "tslib": "^2.1.0" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2915,6 +5460,21 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -2933,6 +5493,17 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", @@ -2962,6 +5533,20 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2974,6 +5559,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2983,11 +5573,30 @@ "node": ">=0.12.0" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "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/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/isomorphic-ws": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", @@ -3001,6 +5610,14 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/jose": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", @@ -3013,8 +5630,7 @@ "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 + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -3036,7 +5652,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -3069,7 +5684,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -3099,6 +5713,158 @@ "node": ">=0.6.0" } }, + "node_modules/jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-compose": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.10.0.tgz", + "integrity": "sha512-F5kgtWpI2XfZ3Z8eP78tZEYFdgTIbpA/TMuX3a8vwrNolYtN1N4qJR/Ob0LAsqIwCMLojtxN7c7Oo/+Vz6THow==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-expand": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.10.0.tgz", + "integrity": "sha512-ymT62W2OyDxBxr7A6JR87vVX9vTq2ep5jZLIdUSusfBIEENLdkkc0lL/Xaq8W9s3opUq7R0sZQpzRWELrfVYzA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-extend": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.10.0.tgz", + "integrity": "sha512-sKYrcMfr4xxigmIwqTjxNcHwXJIfvhvjTNxF+Tbc1NmNdyspGW47Ey6sGH8BcQ4FFQhLXctpWCQSpDwdNmXSwg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-rule-value-observable": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.10.0.tgz", + "integrity": "sha512-ZLMaYrR3QE+vD7nl3oNXuj79VZl9Kp8/u6A1IbTPDcuOu8b56cFdWRZNZ0vNr8jHewooEeq2doy8Oxtymr2ZPA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "symbol-observable": "^1.2.0" + } + }, + "node_modules/jss-plugin-template": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.10.0.tgz", + "integrity": "sha512-ocXZBIOJOA+jISPdsgkTs8wwpK6UbsvtZK5JI7VUggTD6LWKbtoxUzadd2TpfF+lEtlhUmMsCkTRNkITdPKa6w==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, + "node_modules/jss-preset-default": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.10.0.tgz", + "integrity": "sha512-GL175Wt2FGhjE+f+Y3aWh+JioL06/QWFgZp53CbNNq6ZkVU0TDplD8Bxm9KnkotAYn3FlplNqoW5CjyLXcoJ7Q==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "jss-plugin-camel-case": "10.10.0", + "jss-plugin-compose": "10.10.0", + "jss-plugin-default-unit": "10.10.0", + "jss-plugin-expand": "10.10.0", + "jss-plugin-extend": "10.10.0", + "jss-plugin-global": "10.10.0", + "jss-plugin-nested": "10.10.0", + "jss-plugin-props-sort": "10.10.0", + "jss-plugin-rule-value-function": "10.10.0", + "jss-plugin-rule-value-observable": "10.10.0", + "jss-plugin-template": "10.10.0", + "jss-plugin-vendor-prefixer": "10.10.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", @@ -3108,14 +5874,12 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -3127,7 +5891,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "dependencies": { "yallist": "^3.0.2" } @@ -3154,6 +5917,11 @@ "node": ">= 0.6" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -3208,6 +5976,14 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", @@ -3255,15 +6031,68 @@ "node": ">=10" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "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==" }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/multer-s3": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/multer-s3/-/multer-s3-3.0.1.tgz", + "integrity": "sha512-BFwSO80a5EW4GJRBdUuSHblz2jhVSAze33ZbnGpcfEicoT0iRolx4kWR+AJV07THFRCQ78g+kelKFdjkCCaXeQ==", + "dependencies": { + "@aws-sdk/lib-storage": "^3.46.0", + "file-type": "^3.3.0", + "html-comment-regex": "^1.1.2", + "run-parallel": "^1.1.6" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/multer/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -3311,19 +6140,18 @@ } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/nodemon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", - "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", "dev": true, "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", @@ -3344,15 +6172,6 @@ "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/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3454,6 +6273,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "engines": { + "node": ">= 10.12.0" + } + }, "node_modules/oidc-token-hash": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", @@ -3515,6 +6342,11 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "optional": true }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3586,17 +6418,120 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-minify": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/pg-minify/-/pg-minify-1.6.3.tgz", + "integrity": "sha512-NoSsPqXxbkD8RIe+peQCqiea4QzXgosdTKY8p7PsbbGsh2F8TifDj/vJxfuR8qJwNYrijdSs7uf0tAe6WOyCsQ==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-promise": { + "version": "11.5.4", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.4.tgz", + "integrity": "sha512-esYSkDt2h6NQOkfotGAm1Ld5OjoITJLpB88Z1PIlcAU/RQ0XQE2PxW0bLJEOMHPGV5iaRnj1Y7ARznXbgN4FNw==", + "dependencies": { + "assert-options": "0.8.1", + "pg": "8.11.3", + "pg-minify": "1.6.3", + "spex": "3.3.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "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 + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "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" }, @@ -3604,10 +6539,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "dev": true, "funding": [ { @@ -3624,7 +6564,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -3632,10 +6572,65 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-migrations": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/postgres-migrations/-/postgres-migrations-5.3.0.tgz", + "integrity": "sha512-gnTHWJZVWbW8T3mXIxJm1JRU853TqBVWkhgfsTJr7zqT3VexjRmJj9kNi96rVhfTezDU4FVW6pf701kLOZiKIA==", + "dependencies": { + "pg": "^8.6.0", + "sql-template-strings": "^2.2.2" + }, + "bin": { + "pg-validate-migrations": "dist/bin/validate.js" + }, + "engines": { + "node": ">10.17.0" + } + }, "node_modules/prettier": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", - "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -3647,11 +6642,15 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/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", @@ -3661,8 +6660,7 @@ "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 + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -3709,6 +6707,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -3732,9 +6758,9 @@ } }, "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==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/rcon-client/-/rcon-client-4.2.4.tgz", + "integrity": "sha512-sTHYLbcu2qrrOX4TOD3rvcLZNs7xiAhTsnZZIvxviSpa0yeV63sPAVI0PeScn5IvhKOCMURGt1NmnQ8h/GxjtA==", "dependencies": { "typed-emitter": "^0.1.0" } @@ -3743,7 +6769,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3751,11 +6776,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-display-name": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", + "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" + }, + "node_modules/react-dnd": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", + "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", + "dependencies": { + "@react-dnd/shallowequal": "^2.0.0", + "@types/hoist-non-react-statics": "^3.3.1", + "dnd-core": "^11.1.3", + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "react": ">= 16.9.0", + "react-dom": ">= 16.9.0" + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz", + "integrity": "sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==", + "dependencies": { + "dnd-core": "^11.1.3" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -3764,11 +6816,99 @@ "react": "^18.2.0" } }, + "node_modules/react-intl": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-5.25.1.tgz", + "integrity": "sha512-pkjdQDvpJROoXLMltkP/5mZb0/XqrqLoPGKUCfbdkP8m6U9xbK40K51Wu+a4aQqTEvEK5lHBk0fWzUV72SJ3Hg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-messageformat-parser": "2.1.0", + "@formatjs/intl": "2.2.1", + "@formatjs/intl-displaynames": "5.4.3", + "@formatjs/intl-listformat": "6.5.3", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "16 || 17 || 18", + "hoist-non-react-statics": "^3.3.2", + "intl-messageformat": "9.13.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": "^16.3.0 || 17 || 18", + "typescript": "^4.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "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 + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.10.0.tgz", + "integrity": "sha512-WLiq84UYWqNBF6579/uprcIUnM1TSywYq6AIjKTTTG5ziJl9Uy+pwuvpN3apuyVwflMbD60PraeTKT7uWH9XEQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@emotion/is-prop-valid": "^0.7.3", + "css-jss": "10.10.0", + "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", + "jss": "10.10.0", + "jss-preset-default": "10.10.0", + "prop-types": "^15.6.0", + "shallow-equal": "^1.2.0", + "theming": "^3.3.0", + "tiny-warning": "^1.0.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/react-jss/node_modules/@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "dependencies": { + "@emotion/memoize": "0.7.1" + } + }, + "node_modules/react-jss/node_modules/@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" + }, + "node_modules/react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-refresh": { "version": "0.14.0", @@ -3780,12 +6920,12 @@ } }, "node_modules/react-router": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz", - "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==", + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.20.1.tgz", + "integrity": "sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==", "dev": true, "dependencies": { - "@remix-run/router": "1.8.0" + "@remix-run/router": "1.13.1" }, "engines": { "node": ">=14.0.0" @@ -3795,13 +6935,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz", - "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==", + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.20.1.tgz", + "integrity": "sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==", "dev": true, "dependencies": { - "@remix-run/router": "1.8.0", - "react-router": "6.15.0" + "@remix-run/router": "1.13.1", + "react-router": "6.20.1" }, "engines": { "node": ">=14.0.0" @@ -3815,7 +6955,6 @@ "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", @@ -3827,6 +6966,31 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-virtualized-auto-sizer": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.20.tgz", + "integrity": "sha512-OdIyHwj4S4wyhbKHOKM1wLSj/UDXm839Z3Cvfg2a9j+He6yDa6i5p0qQvEiCnyQlGO/HyfSnigQwuxvYalaAXA==", + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc" + } + }, + "node_modules/react-window": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz", + "integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -3852,11 +7016,34 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, + "node_modules/redux-watch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redux-watch/-/redux-watch-1.2.0.tgz", + "integrity": "sha512-Ws4Q+e5zFGMyy1H709c1Ws8apSd6MqoJRIzBDHbI4nikome/IZWVTYXdQNz+VJxPjyX/h2E+lYEo41fXgjCF8g==", + "dependencies": { + "object-path": "^0.11.5" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/request": { "version": "2.88.2", @@ -3928,6 +7115,11 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -3974,21 +7166,56 @@ } }, "node_modules/rollup": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.7.0.tgz", + "integrity": "sha512-7Kw0dUP4BWH78zaZCqF1rPyQ8D5DSU6URG45v1dqS/faNsx9WXyess00uTOZxKr7oR/4TOjO1CPudT8L1UsEgw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.7.0", + "@rollup/rollup-android-arm64": "4.7.0", + "@rollup/rollup-darwin-arm64": "4.7.0", + "@rollup/rollup-darwin-x64": "4.7.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.7.0", + "@rollup/rollup-linux-arm64-gnu": "4.7.0", + "@rollup/rollup-linux-arm64-musl": "4.7.0", + "@rollup/rollup-linux-riscv64-gnu": "4.7.0", + "@rollup/rollup-linux-x64-gnu": "4.7.0", + "@rollup/rollup-linux-x64-musl": "4.7.0", + "@rollup/rollup-win32-arm64-msvc": "4.7.0", + "@rollup/rollup-win32-ia32-msvc": "4.7.0", + "@rollup/rollup-win32-x64-msvc": "4.7.0", "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -4022,11 +7249,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -4104,6 +7335,16 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shell-quote": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", @@ -4113,6 +7354,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shortid": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", + "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "nanoid": "^2.1.0" + } + }, + "node_modules/shortid/node_modules/nanoid": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -4252,6 +7507,30 @@ "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, + "node_modules/spex": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/spex/-/spex-3.3.0.tgz", + "integrity": "sha512-VNiXjFp6R4ldPbVRYbpxlD35yRHceecVXlct1J4/X80KuuPnW2AXMq3sGwhnJOhKkUsOxAT6nRGfGE5pocVw5w==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sql-template-strings": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sql-template-strings/-/sql-template-strings-2.2.2.tgz", + "integrity": "sha512-UXhXR2869FQaD+GMly8jAMCRZ94nU5KcrFetZfWEMd+LVVG6y0ExgHAhatEcKZ/wk8YcKPdi+hiD2wm75lq3/Q==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -4284,6 +7563,15 @@ "node": ">= 0.8" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, "node_modules/stream-buffers": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", @@ -4292,6 +7580,14 @@ "node": ">= 0.10.0" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4324,6 +7620,46 @@ "node": ">=8" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "peer": true + }, + "node_modules/styled-components": { + "version": "5.3.11", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", + "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^1.1.0", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -4334,7 +7670,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -4354,6 +7689,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tar": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", @@ -4375,30 +7718,32 @@ "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==", + "node_modules/theming": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz", + "integrity": "sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==", "dependencies": { - "rimraf": "^3.0.0" + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" }, "engines": { - "node": ">=8.17.0" + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.3" } }, - "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/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -4461,6 +7806,11 @@ "tree-kill": "cli.js" } }, + "node_modules/tsdef": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/tsdef/-/tsdef-0.0.14.tgz", + "integrity": "sha512-UjMD4XKRWWFlFBfwKVQmGFT5YzW/ZaF8x6KpCDf92u9wgKeha/go3FU0e5WqDjXsCOdfiavCkfwfVHNDxRDGMA==" + }, "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", @@ -4499,17 +7849,17 @@ "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-0.1.0.tgz", "integrity": "sha512-Tfay0l6gJMP5rkil8CzGbLthukn+9BN/VXWcABVFPjOoelJ+koW8BuPZYk+h/L+lEeIp1fSzVRiWRPIjKVjPdg==" }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, "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", @@ -4519,10 +7869,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -4556,13 +7905,30 @@ "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", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "dev": true, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, "node_modules/util-deprecate": { @@ -4579,9 +7945,13 @@ } }, "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==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -4608,29 +7978,29 @@ } }, "node_modules/vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.7.tgz", + "integrity": "sha512-B4T4rJCDPihrQo2B+h1MbeGL/k/GMAHzhQ8S0LjQ142s6/+l3hHTT095ORvsshj4QCkoWu3Xtmob5mazvakaOw==", "dev": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", @@ -4676,6 +8046,24 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -4726,6 +8114,26 @@ } } }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", @@ -4735,6 +8143,14 @@ "node": ">=0.4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4747,8 +8163,7 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index d51e3a1..62e7f28 100644 --- a/package.json +++ b/package.json @@ -24,28 +24,37 @@ "devDependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/material": "^5.14.5", - "@tanstack/react-query": "^4.33.0", - "@vitejs/plugin-react": "^4.0.4", - "concurrently": "^8.2.0", - "nodemon": "^3.0.1", - "prettier": "^3.0.2", + "@mui/icons-material": "^5.14.19", + "@mui/material": "^5.14.20", + "@tanstack/react-query": "^5.12.2", + "@vitejs/plugin-react": "^4.2.1", + "concurrently": "^8.2.2", + "nodemon": "^3.0.2", + "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.15.0", + "react-router-dom": "^6.20.1", "socket.io-client": "^4.7.2", - "vite": "^4.4.9" + "vite": "^5.0.7" }, "dependencies": { - "@kubernetes/client-node": "^0.18.1", + "@kubernetes/client-node": "^0.20.0", + "aws-sdk": "^2.1514.0", + "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", + "chonky": "^2.3.2", + "chonky-icon-fontawesome": "^2.3.2", "express": "^4.18.2", - "figlet": "^1.6.0", + "figlet": "^1.7.0", "js-yaml": "^4.1.0", - "rcon-client": "^4.2.3", + "moment": "^2.29.4", + "multer": "^1.4.5-lts.1", + "multer-s3": "^3.0.1", + "pg-promise": "^11.5.4", + "postgres-migrations": "^5.3.0", + "rcon-client": "^4.2.4", "socket.io": "^4.7.2", - "uuid": "^9.0.0" + "uuid": "^9.0.1" } } diff --git a/src/MCL.jsx b/src/MCL.jsx index c24ec3e..e15b85e 100644 --- a/src/MCL.jsx +++ b/src/MCL.jsx @@ -1,4 +1,6 @@ // Imports +import { ThemeProvider } from "@mui/material/styles"; +import mclTheme from "./util/theme.js"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { SettingsProvider } from "@mcl/settings"; import Viewport from "./nav/Viewport.jsx"; @@ -11,9 +13,11 @@ export default function MCL() {
- - - + + + + +
diff --git a/src/components/files/ChonkyStyledFileBrowser.jsx b/src/components/files/ChonkyStyledFileBrowser.jsx new file mode 100644 index 0000000..3273684 --- /dev/null +++ b/src/components/files/ChonkyStyledFileBrowser.jsx @@ -0,0 +1,42 @@ +// ChonkyFullFileBrowser.tsx +import { forwardRef, memo } from "react"; +import { + StylesProvider, + createGenerateClassName, +} from "@material-ui/core/styles"; + +import { + FileBrowser, + FileList, + FileContextMenu, + FileNavbar, + FileToolbar, + setChonkyDefaults, + FileBrowserHandle, + FileBrowserProps, +} from "chonky"; + +import { ChonkyIconFA } from "chonky-icon-fontawesome"; + +setChonkyDefaults({ iconComponent: ChonkyIconFA }); + +const muiJSSClassNameGenerator = createGenerateClassName({ + // Seed property is used to add a prefix classes generated by material ui. + seed: "chonky", +}); + +export default memo( + forwardRef((props, ref) => { + const { onScroll } = props; + return ( + + + + + + + + + ); + }), +); diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx new file mode 100644 index 0000000..6c0079d --- /dev/null +++ b/src/components/files/MineclusterFiles.jsx @@ -0,0 +1,146 @@ +import { useState, useEffect, useMemo, useRef } from "react"; +import Box from "@mui/material/Box"; +import { + FileBrowser, + FileContextMenu, + FileList, + FileNavbar, + FileToolbar, + setChonkyDefaults, + ChonkyActions, +} from "chonky"; +import { ChonkyIconFA } from "chonky-icon-fontawesome"; + +import { + getServerFiles, + createServerFolder, + deleteServerItem, + getServerItem, +} from "@mcl/queries"; + +import "@mcl/css/header.css"; + +export default function MineclusterFiles(props) { + // Chonky configuration + setChonkyDefaults({ iconComponent: ChonkyIconFA }); + const fileActions = useMemo( + () => [ + ChonkyActions.CreateFolder, + ChonkyActions.UploadFiles, + ChonkyActions.DownloadFiles, + ChonkyActions.CopyFiles, + ChonkyActions.DeleteFiles, + ], + [], + ); + const { server: serverName } = props; + const inputRef = useRef(null); + const [dirStack, setDirStack] = useState(["."]); + const [files, setFiles] = useState([]); + + const updateFiles = () => + getServerFiles(serverName, dirStack.join("/")).then((f) => + setFiles(f ?? []), + ); + + useEffect(() => { + updateFiles(); + }, [dirStack]); + + const getFolderChain = () => { + if (dirStack.length === 1) return [{ id: "home", name: "/", isDir: true }]; + return dirStack.map((d, i) => ({ id: `${d}-${i}`, name: d, isDir: true })); + }; + + const openParentFolder = () => setDirStack(dirStack.slice(0, -1)); + + function openFolder(payload) { + const { targetFile: file } = payload; + if (!file || !file.isDir) return; + setDirStack([...dirStack, file.name]); + } + + function createFolder() { + const name = prompt("What is the name of the new folder?"); + const path = [...dirStack, name].join("/"); + createServerFolder(serverName, path).then(updateFiles); + } + + function deleteItems(files) { + Promise.all( + files.map((f) => + deleteServerItem(serverName, [...dirStack, f.name].join("/"), f.isDir), + ), + ) + .catch((e) => console.error("Error deleting some files!", e)) + .then(updateFiles); + } + + function uploadFileSelection(e) { + if (!e.target.files || e.target.files.length === 0) return; + const { files } = e.target; + Promise.all([...files].map((f) => uploadFile(f))) + .catch((e) => console.log("Error uploading a file", e)) + .then(updateFiles); + } + + async function uploadFile(file) { + const formData = new FormData(); + formData.append("file", file); + formData.append("name", serverName); + formData.append("path", [...dirStack, name].join("/")); + await fetch("/api/files/upload", { + method: "POST", + body: formData, + }); + } + + async function downloadFiles(files) { + Promise.all( + files.map((f) => + getServerItem(serverName, f.name, [...dirStack, f.name].join("/")), + ), + ) + .then(() => console.log("Done")) + .catch((e) => console.error("Error Downloading files!", e)); + } + + function fileClick(chonkyEvent) { + const { id: clickEvent, payload } = chonkyEvent; + console.log(chonkyEvent); + if (clickEvent === "open_parent_folder") return openParentFolder(); + if (clickEvent === "create_folder") return createFolder(); + if (clickEvent === "upload_files") return inputRef.current.click(); + if (clickEvent === "download_files") + return downloadFiles(chonkyEvent.state.selectedFilesForAction); + if (clickEvent === "delete_files") + return deleteItems(chonkyEvent.state.selectedFilesForAction); + if (clickEvent !== "open_files") return console.log(clickEvent); + openFolder(payload); + } + return ( + + + + + + + + + + + ); +} diff --git a/src/overview/Overview.jsx b/src/components/overview/Overview.jsx similarity index 100% rename from src/overview/Overview.jsx rename to src/components/overview/Overview.jsx diff --git a/src/overview/OverviewVisual.jsx b/src/components/overview/OverviewVisual.jsx similarity index 100% rename from src/overview/OverviewVisual.jsx rename to src/components/overview/OverviewVisual.jsx diff --git a/src/servers/RconDialog.jsx b/src/components/servers/RconDialog.jsx similarity index 100% rename from src/servers/RconDialog.jsx rename to src/components/servers/RconDialog.jsx diff --git a/src/servers/RconSocket.js b/src/components/servers/RconSocket.js similarity index 100% rename from src/servers/RconSocket.js rename to src/components/servers/RconSocket.js diff --git a/src/servers/RconView.jsx b/src/components/servers/RconView.jsx similarity index 100% rename from src/servers/RconView.jsx rename to src/components/servers/RconView.jsx diff --git a/src/servers/ServerCard.jsx b/src/components/servers/ServerCard.jsx similarity index 86% rename from src/servers/ServerCard.jsx rename to src/components/servers/ServerCard.jsx index ac61a5c..4eec631 100644 --- a/src/servers/ServerCard.jsx +++ b/src/components/servers/ServerCard.jsx @@ -14,6 +14,8 @@ 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"; +import FolderIcon from "@mui/icons-material/Folder"; +import { Link } from "react-router-dom"; export default function ServerCard(props) { const { server, openRcon } = props; @@ -94,9 +96,24 @@ export default function ServerCard(props) { > - + + + + header { + transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + box-shadow: + 0px 2px 4px -1px rgba(0, 0, 0, 0.2), + 0px 4px 5px 0px rgba(0, 0, 0, 0.14), + 0px 1px 10px 0px rgba(0, 0, 0, 0.12); + display: flex; + flex-direction: column; + width: 100%; + box-sizing: border-box; + flex-shrink: 0; + position: fixed; + top: 0; + left: auto; + right: 0; + color: rgba(0, 0, 0, 0.87); + z-index: 1302; + background-color: black; +} +.view > header > div > div > a { + height: 40px; + width: 40px; +} diff --git a/public/css/overview.css b/src/css/overview.css similarity index 100% rename from public/css/overview.css rename to src/css/overview.css diff --git a/public/css/rcon.css b/src/css/rcon.css similarity index 100% rename from public/css/rcon.css rename to src/css/rcon.css diff --git a/public/css/server-card.css b/src/css/server-card.css similarity index 100% rename from public/css/server-card.css rename to src/css/server-card.css diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index aa688b3..3d6e7c2 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -13,7 +13,7 @@ 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 HomeIcon from "@mui/icons-material/Home"; import ListItemText from "@mui/material/ListItemText"; import List from "@mui/material/List"; import ListItemButton from "@mui/material/ListItemButton"; @@ -36,48 +36,23 @@ export default function MCLMenu() { 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 index cf7b86c..d13364e 100644 --- a/src/nav/MCLPages.jsx +++ b/src/nav/MCLPages.jsx @@ -1,5 +1,6 @@ import Home from "@mcl/pages/Home.jsx"; import Create from "@mcl/pages/Create.jsx"; +import Files from "@mcl/pages/Files.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"; @@ -17,4 +18,10 @@ export default [ icon: , component: , }, + { + name: "Edit", + path: "/mcl/files", + icon: , + component: , + }, ]; diff --git a/src/nav/Viewport.jsx b/src/nav/Viewport.jsx index af78dff..a6b7622 100644 --- a/src/nav/Viewport.jsx +++ b/src/nav/Viewport.jsx @@ -1,6 +1,8 @@ import Box from "@mui/material/Box"; import Toolbar from "@mui/material/Toolbar"; import MCLPortal from "./MCLPortal.jsx"; +import Button from "@mui/material/Button"; +import SpeedDialIcon from "@mui/material/SpeedDialIcon"; // Import Navbar /*import Navbar from "./Navbar.jsx";*/ import MCLMenu from "./MCLMenu.jsx"; diff --git a/src/pages/Create.jsx b/src/pages/Create.jsx index 7507514..b42e3fe 100644 --- a/src/pages/Create.jsx +++ b/src/pages/Create.jsx @@ -1,152 +1,12 @@ -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", -}; - +import CreateOptions from "./CreateOptions.jsx"; 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/CreateOptions.jsx b/src/pages/CreateOptions.jsx new file mode 100644 index 0000000..bb38323 --- /dev/null +++ b/src/pages/CreateOptions.jsx @@ -0,0 +1,248 @@ +import { useState, useEffect } from "react"; +import Autocomplete from "@mui/material/Autocomplete"; +import TextField from "@mui/material/TextField"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Chip from "@mui/material/Chip"; +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", + serverType: "VANILLA", + difficulty: "easy", + maxPlayers: "5", + gamemode: "survival", + memory: "512", + motd: `\\u00A7e\\u00A7ka\\u00A7l\\u00A7aMine\\u00A76Cluster\\u00A7r\\u00A78\\u00A7b\\u00A7ka`, +}; + +export default function Create() { + const [wl, setWl] = useState([]); + const [ops, setOps] = useState([]); + 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); + console.log(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 opsAdd(e) { + const opEntry = e.target.innerHTML ?? e.target.value; + if (!opEntry) return; + const newOps = [...ops, opEntry]; + setOps(newOps); + updateSpec("ops", newOps.join(",")); + } + + function whitelistAdd(e) { + const wlEntry = e.target.value; + if (!wlEntry) return; + const newWl = [...wl, wlEntry]; + setWl(newWl); + updateSpec("whitelist", newWl.join(",")); + } + + const opsRemove = + (name, { onDelete: updateAutoComplete }) => + (e) => { + updateAutoComplete(e); + const newOps = [...ops]; + const entryIndex = newOps.indexOf(name); + if (entryIndex === -1) return; + newOps.splice(entryIndex, 1); + setOps(newOps); + updateSpec("ops", newOps.join(",")); + }; + + const whitelistRemove = + (name, { onDelete: updateAutocomplete }) => + (e) => { + updateAutocomplete(e); + const newWl = [...wl]; + const entryIndex = newWl.indexOf(name); + if (entryIndex === -1) return; + newWl.splice(entryIndex, 1); + setWl(newWl); + updateSpec("whitelist", newWl.join(",")); + }; + + const opUpdate = (e) => alert("Op not implimented"); + + 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.host) return alertValidationError("Host 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 + + + } + renderTags={(value, getTagProps) => + value.map((option, index) => { + const defaultChipProps = getTagProps({ index }); + return ( + + ); + }) + } + /> + } + renderTags={(value, getTagProps) => + value.map((option, index) => { + const defaultChipProps = getTagProps({ index }); + return ( + + ); + }) + } + /> + {/**/} + {/**/} + + + Survival + Creative + Adventure + Spectator + + + {/**/} + + + + + + ); +} diff --git a/src/pages/Files.jsx b/src/pages/Files.jsx new file mode 100644 index 0000000..2794530 --- /dev/null +++ b/src/pages/Files.jsx @@ -0,0 +1,20 @@ +import { useEffect } from "react"; +import { useSearchParams, useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import Toolbar from "@mui/material/Toolbar"; +import MineclusterFiles from "@mcl/components/files/MineclusterFiles.jsx"; + +export default function Files() { + const [searchParams] = useSearchParams(); + const currentServer = searchParams.get("server"); + const nav = useNavigate(); + useEffect(() => { + if (!currentServer) nav("/"); + }, [currentServer]); + return ( + + + + ); +} diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 1c79043..663a2b7 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,19 +1,25 @@ +import { Link } from "react-router-dom"; 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 ServerCard from "@mcl/components/servers/ServerCard.jsx"; +import RconDialog, { + useRconDialog, +} from "@mcl/components/servers/RconDialog.jsx"; +import Overview from "@mcl/components/overview/Overview.jsx"; +import Button from "@mui/material/Button"; +import SpeedDialIcon from "@mui/material/SpeedDialIcon"; import "@mcl/css/server-card.css"; import "@mcl/css/overview.css"; import { useServerInstances } from "@mcl/queries"; export default function Home() { + const clusterMetrics = { cpu: 0, memory: 0 }; const [server, setServer] = useState(); const [servers, setServers] = useState([]); const [rdOpen, rconToggle] = useRconDialog(); const { isLoading, data: serversData } = useServerInstances(); - const { servers: serverInstances, clusterMetrics } = serversData ?? {}; + const serverInstances = serversData ?? []; useEffect(() => { if (!serverInstances) return; serverInstances.sort((a, b) => a.name.localeCompare(b.name)); @@ -53,6 +59,23 @@ export default function Home() { dialogToggle={rconToggle} serverName={server} /> + ); } diff --git a/src/util/queries.js b/src/util/queries.js index 9636fe4..fa06c61 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -2,6 +2,15 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; const fetchApi = (subPath) => async () => fetch(`/api${subPath}`).then((res) => res.json()); +const fetchApiCore = async (subPath, json, method = "POST", jsonify = false) => + fetch(`/api${subPath}`, { + method, + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(json), + }).then((res) => (jsonify ? res.json() : res)); + const fetchApiPost = (subPath, json) => async () => fetch(`/api${subPath}`, { method: "POST", @@ -12,16 +21,16 @@ const fetchApiPost = (subPath, json) => async () => }).then((res) => res.json()); export const useServerStatus = (server) => - useQuery( - [`server-status-${server}`], - fetchApiPost("/server/status", { name: server }) - ); + useQuery({ + queryKey: [`server-status-${server}`], + queryFn: fetchApiPost("/server/status", { name: server }), + }); export const useServerMetrics = (server) => - useQuery( - [`server-metrics-${server}`], - fetchApiPost("/server/metrics", { name: server }), - { refetchInterval: 10000 } - ); + useQuery({ + queryKey: [`server-metrics-${server}`], + queryFn: fetchApiPost("/server/metrics", { name: server }), + refetchInterval: 10000, + }); export const useStartServer = (server) => postJsonApi("/server/start", { name: server }, "server-instances"); export const useStopServer = (server) => @@ -30,20 +39,61 @@ export const useDeleteServer = (server) => postJsonApi("/server/delete", { name: server }, "server-instances", "DELETE"); export const useCreateServer = (spec) => postJsonApi("/server/create", spec, "server-list"); + +export const getServerFiles = async (server, path) => + fetchApiCore("/files/list", { name: server, path }, "POST", true); +export const createServerFolder = async (server, path) => + fetchApiCore("/files/folder", { + name: server, + path, + }); /*postJsonApi("/files/folder", {name: server, path});*/ +export const deleteServerItem = async (server, path, isDir) => + fetchApiCore("/files/item", { name: server, path, isDir }, "DELETE"); + +export const getServerItem = async (server, name, path) => + fetchApiCore("/files/item", { name: server, path }) + .then((resp) => + resp.status === 200 + ? resp.blob() + : Promise.reject("something went wrong"), + ) + .then((blob) => { + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.style.display = "none"; + a.href = url; + a.download = name; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + }); + +export const useInvalidator = () => { + const qc = useQueryClient(); + return (q) => qc.invalidateQueries([q]); +}; + export const useServerList = () => - useQuery(["server-list"], fetchApi("/server/list")); + useQuery({ queryKey: ["server-list"], queryFn: fetchApi("/server/list") }); export const useServerInstances = () => - useQuery(["server-instances"], fetchApi("/server/instances"), { + useQuery({ + queryKey: ["server-instances"], + queryFn: fetchApi("/server/instances"), refetchInterval: 5000, }); export const useSystemAvailable = () => - useQuery(["system-available"], fetchApi("/system/available")); + useQuery({ + queryKey: ["system-available"], + queryFn: fetchApi("/system/available"), + }); export const useVersionList = () => - useQuery(["minecraft-versions"], () => - fetch("https://piston-meta.mojang.com/mc/game/version_manifest.json").then( - (r) => r.json() - ) - ); + useQuery({ + queryKey: ["minecraft-versions"], + queryFn: () => + 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(); @@ -55,6 +105,7 @@ const postJsonApi = (subPath, body, invalidate, method = "POST") => { }, body: JSON.stringify(body), }); - qc.invalidateQueries([invalidate]); + if (invalidate) qc.invalidateQueries([invalidate]); + return res.json(); }; }; diff --git a/src/util/theme.js b/src/util/theme.js new file mode 100644 index 0000000..26347a4 --- /dev/null +++ b/src/util/theme.js @@ -0,0 +1,16 @@ +// Generated using https://zenoo.github.io/mui-theme-creator/ +import { createTheme } from "@mui/material/styles"; + +const themeOptions = { + palette: { + mode: "light", + primary: { + main: "rgba(109,216,144,255)", + }, + secondary: { + main: "#f50057", + }, + }, +}; + +export default createTheme(themeOptions); diff --git a/vite.config.js b/vite.config.js index c71a2b2..5d25a00 100644 --- a/vite.config.js +++ b/vite.config.js @@ -15,6 +15,7 @@ export default () => { proxy: { "/api": backendUrl, "/socket.io": backendUrl, + "/healthz": backendUrl, }, hmr: { protocol: process.env.MCL_VITE_DEV_PROTOCOL, @@ -26,10 +27,11 @@ export default () => { base: "/mcl/", resolve: { alias: { - "@mcl/css": path.resolve("./public/css"), + "@mcl/css": path.resolve("./src/css"), "@mcl/settings": path.resolve("./src/ctx/SettingsContext.jsx"), "@mcl/pages": path.resolve("./src/pages"), "@mcl/queries": path.resolve("./src/util/queries.js"), + "@mcl/components": path.resolve("./src/components"), "@mcl": path.resolve("./src"), }, }, From fb57c03ba7f6f430ac70232801698045d69e2941 Mon Sep 17 00:00:00 2001 From: dunemask Date: Fri, 22 Dec 2023 18:30:48 +0000 Subject: [PATCH 20/56] [FEATURE] Fixed file manager and adjusted starting display (#5) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/5 --- lib/k8s/server-control.js | 20 +++++++++++----- src/components/files/MineclusterFiles.jsx | 28 +++++++++++++--------- src/components/servers/ServerCard.jsx | 29 ++++++++++++++++------- src/css/header.css | 2 +- src/nav/MCLMenu.jsx | 7 +----- src/pages/CreateOptions.jsx | 10 ++++---- src/pages/Home.jsx | 7 +----- src/util/queries.js | 3 +-- src/util/theme.js | 2 +- 9 files changed, 63 insertions(+), 45 deletions(-) diff --git a/lib/k8s/server-control.js b/lib/k8s/server-control.js index 63097e6..bcb5a35 100644 --- a/lib/k8s/server-control.js +++ b/lib/k8s/server-control.js @@ -11,7 +11,6 @@ const kc = new k8s.KubeConfig(); kc.loadFromDefault(); const k8sMetrics = new k8s.Metrics(kc); -const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; export async function startServerContainer(serverSpec) { @@ -43,17 +42,26 @@ export async function stopServerContainer(serverSpec) { export async function getInstances() { const serverDeployments = await getDeployments(); const podMetricsResponse = await k8sMetrics.getPodMetrics(namespace); - var name, metrics, started; + var name, metrics, services, serverAvailable, ftpAvailable; const serverInstances = serverDeployments.map((s) => { name = s.metadata.annotations["minecluster.dunemask.net/server-name"]; metrics = null; - started = !!s.spec.template.spec.containers.find((c) => - c.name.includes(`mcl-${name}-server`), + const { containers } = s.spec.template.spec; + services = containers.map(({ name }) => name.split("-").pop()); + const serverStatusList = s.status.conditions.map( + ({ type: statusType, status: sts }) => ({ statusType, sts }), ); + const deploymentAvailable = + serverStatusList.find( + (ss) => ss.statusType === "Available" && ss.sts === "True", + ) !== undefined; + serverAvailable = services.includes(`server`) && deploymentAvailable; + ftpAvailable = services.includes("ftp") && deploymentAvailable; + const pod = podMetricsResponse.items.find(({ metadata: md }) => { return md.labels && md.labels.app && md.labels.app === `mcl-${name}-app`; }); - if (started && pod) { + if (serverAvailable && pod) { const podCpus = pod.containers.map( ({ usage }) => parseInt(usage.cpu) / 1_000_000, ); @@ -65,7 +73,7 @@ export async function getInstances() { memory: Math.ceil(podMems.reduce((a, b) => a + b)), }; } - return { name, metrics, started }; + return { name, metrics, services, serverAvailable, ftpAvailable }; }); return serverInstances; } diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx index 6c0079d..45bce13 100644 --- a/src/components/files/MineclusterFiles.jsx +++ b/src/components/files/MineclusterFiles.jsx @@ -38,26 +38,33 @@ export default function MineclusterFiles(props) { const [dirStack, setDirStack] = useState(["."]); const [files, setFiles] = useState([]); - const updateFiles = () => - getServerFiles(serverName, dirStack.join("/")).then((f) => - setFiles(f ?? []), - ); + const updateFiles = () => { + const dir = dirStack.join("/"); + getServerFiles(serverName, dir).then((f) => { + const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` })); + setFiles(files ?? []); + }); + }; useEffect(() => { updateFiles(); }, [dirStack]); const getFolderChain = () => { - if (dirStack.length === 1) return [{ id: "home", name: "/", isDir: true }]; - return dirStack.map((d, i) => ({ id: `${d}-${i}`, name: d, isDir: true })); + if (dirStack.length === 1) return [{ id: "./", name: "Home", isDir: true }]; + return dirStack.map((d, i) => ({ + id: `${dirStack.slice(0, i + 1).join("/")}`, + name: i === 0 ? "Home" : d, + isDir: true, + })); }; const openParentFolder = () => setDirStack(dirStack.slice(0, -1)); function openFolder(payload) { const { targetFile: file } = payload; - if (!file || !file.isDir) return; - setDirStack([...dirStack, file.name]); + if (file && file.isDir) return setDirStack(file.id.split("/")); + if (file && !file.isDir) return downloadFiles([file]); } function createFolder() { @@ -101,13 +108,12 @@ export default function MineclusterFiles(props) { getServerItem(serverName, f.name, [...dirStack, f.name].join("/")), ), ) - .then(() => console.log("Done")) + .then(() => console.log("Done downloading files!")) .catch((e) => console.error("Error Downloading files!", e)); } function fileClick(chonkyEvent) { const { id: clickEvent, payload } = chonkyEvent; - console.log(chonkyEvent); if (clickEvent === "open_parent_folder") return openParentFolder(); if (clickEvent === "create_folder") return createFolder(); if (clickEvent === "upload_files") return inputRef.current.click(); @@ -115,7 +121,7 @@ export default function MineclusterFiles(props) { return downloadFiles(chonkyEvent.state.selectedFilesForAction); if (clickEvent === "delete_files") return deleteItems(chonkyEvent.state.selectedFilesForAction); - if (clickEvent !== "open_files") return console.log(clickEvent); + if (clickEvent !== "open_files") return; // console.log(clickEvent); openFolder(payload); } return ( diff --git a/src/components/servers/ServerCard.jsx b/src/components/servers/ServerCard.jsx index 4eec631..d3a65e0 100644 --- a/src/components/servers/ServerCard.jsx +++ b/src/components/servers/ServerCard.jsx @@ -19,12 +19,12 @@ import { Link } from "react-router-dom"; export default function ServerCard(props) { const { server, openRcon } = props; - const { name, metrics, started } = server; + const { name, metrics, ftpAvailable, serverAvailable, services } = server; const startServer = useStartServer(name); const stopServer = useStopServer(name); const deleteServer = useDeleteServer(name); function toggleRcon() { - if (!started) return; + if (!services.includes("server")) return; openRcon(); } @@ -60,14 +60,26 @@ export default function ServerCard(props) {
)}
- {started && ( + {services.includes("server") && ( )} - {!started && ( + {!services.includes("server") && ( @@ -106,11 +118,12 @@ export default function ServerCard(props) { diff --git a/src/css/header.css b/src/css/header.css index 15d51e4..efa6fa9 100644 --- a/src/css/header.css +++ b/src/css/header.css @@ -23,7 +23,7 @@ right: 0; color: rgba(0, 0, 0, 0.87); z-index: 1302; - background-color: black; + background-color: #29985c; } .view > header > div > div > a { height: 40px; diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index 3d6e7c2..706c971 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -36,12 +36,7 @@ export default function MCLMenu() { theme.zIndex.modal + 2 - (isDrawer ? 1 : 0); return ( - + alert("Op not implimented"); - - function upsertSpec() { + async function upsertSpec() { if (validateSpec() !== "validated") return; - createServer(spec); + createServer(spec) + .then(() => nav("/")) + .catch(alert); } function validateSpec() { diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 663a2b7..2a415cb 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -53,12 +53,7 @@ export default function Home() { ))} - + + + + ); +} diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx index 45bce13..31c1389 100644 --- a/src/components/files/MineclusterFiles.jsx +++ b/src/components/files/MineclusterFiles.jsx @@ -17,8 +17,9 @@ import { deleteServerItem, getServerItem, } from "@mcl/queries"; +import { previewServerItem } from "../../util/queries"; -import "@mcl/css/header.css"; +import { supportedFileTypes } from "./FilePreview.jsx"; export default function MineclusterFiles(props) { // Chonky configuration @@ -33,17 +34,23 @@ export default function MineclusterFiles(props) { ], [], ); - const { server: serverName } = props; + const { server: serverId, changePreview } = props; const inputRef = useRef(null); const [dirStack, setDirStack] = useState(["."]); const [files, setFiles] = useState([]); const updateFiles = () => { const dir = dirStack.join("/"); - getServerFiles(serverName, dir).then((f) => { - const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` })); - setFiles(files ?? []); - }); + getServerFiles(serverId, dir) + .then((f) => { + const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` })); + setFiles(files ?? []); + }) + .catch(() => + console.error( + "Couldn't update files, server likely hasn't started yet", + ), + ); }; useEffect(() => { @@ -61,22 +68,25 @@ export default function MineclusterFiles(props) { const openParentFolder = () => setDirStack(dirStack.slice(0, -1)); - function openFolder(payload) { + function openItem(payload) { const { targetFile: file } = payload; if (file && file.isDir) return setDirStack(file.id.split("/")); - if (file && !file.isDir) return downloadFiles([file]); + if (!file || file.isDir) return; // Ensure file exists or is dir + if (supportedFileTypes.includes(file.name.split(".").pop())) + return previewFile(file); + return downloadFiles([file]); } function createFolder() { const name = prompt("What is the name of the new folder?"); const path = [...dirStack, name].join("/"); - createServerFolder(serverName, path).then(updateFiles); + createServerFolder(serverId, path).then(updateFiles); } function deleteItems(files) { Promise.all( files.map((f) => - deleteServerItem(serverName, [...dirStack, f.name].join("/"), f.isDir), + deleteServerItem(serverId, [...dirStack, f.name].join("/"), f.isDir), ), ) .catch((e) => console.error("Error deleting some files!", e)) @@ -94,7 +104,7 @@ export default function MineclusterFiles(props) { async function uploadFile(file) { const formData = new FormData(); formData.append("file", file); - formData.append("name", serverName); + formData.append("id", serverId); formData.append("path", [...dirStack, name].join("/")); await fetch("/api/files/upload", { method: "POST", @@ -105,13 +115,20 @@ export default function MineclusterFiles(props) { async function downloadFiles(files) { Promise.all( files.map((f) => - getServerItem(serverName, f.name, [...dirStack, f.name].join("/")), + getServerItem(serverId, f.name, [...dirStack, f.name].join("/")), ), ) .then(() => console.log("Done downloading files!")) .catch((e) => console.error("Error Downloading files!", e)); } + function previewFile(file) { + const { name } = file; + previewServerItem(serverId, [...dirStack, name].join("/")).then( + (fileData) => changePreview(name, fileData), + ); + } + function fileClick(chonkyEvent) { const { id: clickEvent, payload } = chonkyEvent; if (clickEvent === "open_parent_folder") return openParentFolder(); @@ -122,7 +139,7 @@ export default function MineclusterFiles(props) { if (clickEvent === "delete_files") return deleteItems(chonkyEvent.state.selectedFilesForAction); if (clickEvent !== "open_files") return; // console.log(clickEvent); - openFolder(payload); + openItem(payload); } return ( @@ -134,7 +151,6 @@ export default function MineclusterFiles(props) { onChange={uploadFileSelection} multiple /> - + diff --git a/src/components/server-options/BackupBucketOption.jsx b/src/components/server-options/BackupBucketOption.jsx new file mode 100644 index 0000000..bc7139d --- /dev/null +++ b/src/components/server-options/BackupBucketOption.jsx @@ -0,0 +1,15 @@ +import TextField from "@mui/material/TextField"; +export default function BackupBucketOption(props) { + const { value, onChange } = props; + + return ( + + ); +} diff --git a/src/components/server-options/BackupHostOption.jsx b/src/components/server-options/BackupHostOption.jsx new file mode 100644 index 0000000..0730893 --- /dev/null +++ b/src/components/server-options/BackupHostOption.jsx @@ -0,0 +1,14 @@ +import TextField from "@mui/material/TextField"; +export default function BackupHostOption(props) { + const { onChange } = props; + + return ( + + ); +} diff --git a/src/components/server-options/BackupIdOption.jsx b/src/components/server-options/BackupIdOption.jsx new file mode 100644 index 0000000..e36ccff --- /dev/null +++ b/src/components/server-options/BackupIdOption.jsx @@ -0,0 +1,14 @@ +import TextField from "@mui/material/TextField"; +export default function BackupIdOption(props) { + const { onChange } = props; + + return ( + + ); +} diff --git a/src/components/server-options/BackupIntervalOption.jsx b/src/components/server-options/BackupIntervalOption.jsx new file mode 100644 index 0000000..610c6fd --- /dev/null +++ b/src/components/server-options/BackupIntervalOption.jsx @@ -0,0 +1,55 @@ +import { useState } from "react"; +import Box from "@mui/material/Box"; +import MenuItem from "@mui/material/MenuItem"; +import TextField from "@mui/material/TextField"; + +const backupIntervalStepDisplay = ["Minutes", "Hours", "Days"]; +export const backupIntervalDefault = "1d"; +export const backupIntervalStepOptions = ["m", "h", "d"]; +export default function BackupIntervalOption(props) { + const { onChange } = props; + const [interval, setInterval] = useState(1); + const [intervalStep, setIntervalStep] = useState( + backupIntervalStepOptions[2], + ); + + const changeStep = (e) => { + setIntervalStep(e.target.value); + onChange({ target: { value: `${interval}${e.target.value}` } }); + }; + + const changeInterval = (e) => { + setInterval(e.target.value); + onChange({ target: { value: `${e.target.value}${intervalStep}` } }); + }; + + return ( + + + + {backupIntervalStepOptions.map((o, i) => ( + + {backupIntervalStepDisplay[i]} + + ))} + + + ); +} diff --git a/src/components/server-options/BackupKeyOption.jsx b/src/components/server-options/BackupKeyOption.jsx new file mode 100644 index 0000000..aa966ff --- /dev/null +++ b/src/components/server-options/BackupKeyOption.jsx @@ -0,0 +1,14 @@ +import TextField from "@mui/material/TextField"; +export default function BackupKeyOption(props) { + const { onChange } = props; + + return ( + + ); +} diff --git a/src/components/server-options/CpuOption.jsx b/src/components/server-options/CpuOption.jsx new file mode 100644 index 0000000..8eb8a83 --- /dev/null +++ b/src/components/server-options/CpuOption.jsx @@ -0,0 +1,26 @@ +import TextField from "@mui/material/TextField"; +import MenuItem from "@mui/material/MenuItem"; + +const maxCpuSupported = 8; +export const cpuOptions = new Array(2 * maxCpuSupported) + .fill(0) + .map((v, i) => (i + 1) * 0.5); + +export default function CpuOption(props) { + const { value, onChange } = props; + return ( + + {cpuOptions.map((o, i) => ( + {`${o} CPU`} + ))} + + ); +} diff --git a/src/components/server-options/HostOption.jsx b/src/components/server-options/HostOption.jsx new file mode 100644 index 0000000..7efe6a9 --- /dev/null +++ b/src/components/server-options/HostOption.jsx @@ -0,0 +1,14 @@ +import TextField from "@mui/material/TextField"; +export default function HostOption(props) { + const { onChange } = props; + + return ( + + ); +} diff --git a/src/components/server-options/MemoryOption.jsx b/src/components/server-options/MemoryOption.jsx new file mode 100644 index 0000000..4b52537 --- /dev/null +++ b/src/components/server-options/MemoryOption.jsx @@ -0,0 +1,24 @@ +import TextField from "@mui/material/TextField"; +import MenuItem from "@mui/material/MenuItem"; +const maxMemSupported = 10; +export const memoryOptions = new Array(2 * maxMemSupported) + .fill(0) + .map((v, i) => (i + 1) * 512); + +export default function Option(props) { + const { value, onChange } = props; + return ( + + {memoryOptions.map((o, i) => ( + {`${o / 1024} Gi`} + ))} + + ); +} diff --git a/src/components/server-options/NameOption.jsx b/src/components/server-options/NameOption.jsx new file mode 100644 index 0000000..3390d9a --- /dev/null +++ b/src/components/server-options/NameOption.jsx @@ -0,0 +1,14 @@ +import TextField from "@mui/material/TextField"; +export default function NameOption(props) { + const { onChange } = props; + + return ( + + ); +} diff --git a/src/components/server-options/ServerTypeOption.jsx b/src/components/server-options/ServerTypeOption.jsx new file mode 100644 index 0000000..d3a885c --- /dev/null +++ b/src/components/server-options/ServerTypeOption.jsx @@ -0,0 +1,25 @@ +import TextField from "@mui/material/TextField"; +import MenuItem from "@mui/material/MenuItem"; + +const displayOption = (o) => o.charAt(0) + o.toLowerCase().slice(1); + +export const serverTypeOptions = ["VANILLA", "FABRIC", "PAPER", "SPIGOT"]; +export default function ServerTypeOption(props) { + const { value, onChange } = props; + return ( + + {serverTypeOptions.map((o, i) => ( + + {displayOption(o)} + + ))} + + ); +} diff --git a/src/components/server-options/VersionOption.jsx b/src/components/server-options/VersionOption.jsx new file mode 100644 index 0000000..8389ddd --- /dev/null +++ b/src/components/server-options/VersionOption.jsx @@ -0,0 +1,37 @@ +import { useState, useEffect } from "react"; +import TextField from "@mui/material/TextField"; +import MenuItem from "@mui/material/MenuItem"; +import { useVersionList } from "@mcl/queries"; + +export default function VersionOption(props) { + const { value, onChange } = props; + const versionList = useVersionList(); + const [versions, setVersions] = useState(["latest"]); + + useEffect(() => { + if (!versionList.data) return; + setVersions([ + "latest", + ...versionList.data.versions + .filter(({ type: releaseType }) => releaseType === "release") + .map(({ id }) => id), + ]); + }, [versionList.data]); + + return ( + + {versions.map((v, k) => ( + + {v} + + ))} + + ); +} diff --git a/src/components/servers/RconDialog.jsx b/src/components/servers/RconDialog.jsx index 5183d1a..579b97b 100644 --- a/src/components/servers/RconDialog.jsx +++ b/src/components/servers/RconDialog.jsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import useMediaQuery from "@mui/material/useMediaQuery"; import { useTheme } from "@mui/material/styles"; import Button from "@mui/material/Button"; @@ -16,15 +16,17 @@ export function useRconDialog(isOpen = false) { } export default function RconDialog(props) { - const { serverName, open, dialogToggle } = props; + const { server, open, dialogToggle } = props; + const { name: serverName, id: serverId } = server ?? {}; const theme = useTheme(); const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); + return ( RCON - {serverName} - + + {rcon && rcon.rconLive && } + {!(rcon && rcon.rconLive) && ( + + )} ); diff --git a/src/components/servers/ServerCard.jsx b/src/components/servers/ServerCard.jsx index d3a65e0..c2d5ee8 100644 --- a/src/components/servers/ServerCard.jsx +++ b/src/components/servers/ServerCard.jsx @@ -11,7 +11,6 @@ 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"; import FolderIcon from "@mui/icons-material/Folder"; @@ -19,10 +18,10 @@ import { Link } from "react-router-dom"; export default function ServerCard(props) { const { server, openRcon } = props; - const { name, metrics, ftpAvailable, serverAvailable, services } = server; - const startServer = useStartServer(name); - const stopServer = useStopServer(name); - const deleteServer = useDeleteServer(name); + const { name, id, metrics, ftpAvailable, serverAvailable, services } = server; + const startServer = useStartServer(id); + const stopServer = useStopServer(id); + const deleteServer = useDeleteServer(id); function toggleRcon() { if (!services.includes("server")) return; openRcon(); @@ -113,7 +112,7 @@ export default function ServerCard(props) { aria-label="Edit" size="large" component={Link} - to={`/mcl/edit?server=${name}`} + to={`/mcl/edit?server=${id}`} > @@ -122,8 +121,8 @@ export default function ServerCard(props) { aria-label="Files" size="large" component={Link} - to={`/mcl/files?server=${name}`} - disabled={!services.includes("ftp")} + to={`/mcl/files?server=${id}`} + disabled={!ftpAvailable} > diff --git a/src/css/header.css b/src/css/header.css deleted file mode 100644 index efa6fa9..0000000 --- a/src/css/header.css +++ /dev/null @@ -1,31 +0,0 @@ -.appbar-items { - font-size: 1.25rem; - font-family: "Roboto", "Helvetica", "Arial", sans-serif; - font-weight: 500; - line-height: 1.6; - letter-spacing: 0.0075em; -} - -.view > header { - transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; - box-shadow: - 0px 2px 4px -1px rgba(0, 0, 0, 0.2), - 0px 4px 5px 0px rgba(0, 0, 0, 0.14), - 0px 1px 10px 0px rgba(0, 0, 0, 0.12); - display: flex; - flex-direction: column; - width: 100%; - box-sizing: border-box; - flex-shrink: 0; - position: fixed; - top: 0; - left: auto; - right: 0; - color: rgba(0, 0, 0, 0.87); - z-index: 1302; - background-color: #29985c; -} -.view > header > div > div > a { - height: 40px; - width: 40px; -} diff --git a/src/nav/MCLMenu.jsx b/src/nav/MCLMenu.jsx index 706c971..6108f0a 100644 --- a/src/nav/MCLMenu.jsx +++ b/src/nav/MCLMenu.jsx @@ -13,7 +13,7 @@ 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 HomeIcon from "@mui/icons-material/Home"; +import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText from "@mui/material/ListItemText"; import List from "@mui/material/List"; import ListItemButton from "@mui/material/ListItemButton"; @@ -36,18 +36,52 @@ export default function MCLMenu() { theme.zIndex.modal + 2 - (isDrawer ? 1 : 0); return ( - - + + - - + + - + + + + + {pages.map( + (page, index) => + page.visible && ( + + {page.icon} + + + ), + )} + + + + {navHeader()} - + diff --git a/src/nav/MCLPages.jsx b/src/nav/MCLPages.jsx index d13364e..56ab52e 100644 --- a/src/nav/MCLPages.jsx +++ b/src/nav/MCLPages.jsx @@ -11,17 +11,20 @@ export default [ path: "/mcl/home", icon: , component: , + visible: true, }, { name: "Create", path: "/mcl/create", icon: , component: , + visible: true, }, { name: "Edit", path: "/mcl/files", icon: , component: , + visible: false, }, ]; diff --git a/src/pages/Create.jsx b/src/pages/Create.jsx index b42e3fe..b8e6963 100644 --- a/src/pages/Create.jsx +++ b/src/pages/Create.jsx @@ -1,11 +1,10 @@ import Box from "@mui/material/Box"; -import CreateOptions from "./CreateOptions.jsx"; +import CreateCoreOptions from "./CreateCoreOptions.jsx"; export default function Create() { return ( - {/**/} - + ); diff --git a/src/pages/CreateCoreOptions.jsx b/src/pages/CreateCoreOptions.jsx new file mode 100644 index 0000000..ee8b92f --- /dev/null +++ b/src/pages/CreateCoreOptions.jsx @@ -0,0 +1,145 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import FormControl from "@mui/material/FormControl"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Switch from "@mui/material/Switch"; +import Typography from "@mui/material/Typography"; +import { useCreateServer } from "@mcl/queries"; + +// Core Options +import NameOption from "@mcl/components/server-options/NameOption.jsx"; +import HostOption from "@mcl/components/server-options/HostOption.jsx"; +import VersionOption from "@mcl/components/server-options/VersionOption.jsx"; +import ServerTypeOption, { + serverTypeOptions, +} from "@mcl/components/server-options/ServerTypeOption.jsx"; +import CpuOption, { + cpuOptions, +} from "@mcl/components/server-options/CpuOption.jsx"; +import MemoryOption, { + memoryOptions, +} from "@mcl/components/server-options/MemoryOption.jsx"; + +import BackupHostOption from "@mcl/components/server-options/BackupHostOption.jsx"; +import BackupBucketOption from "@mcl/components/server-options/BackupBucketOption.jsx"; +import BackupIdOption from "@mcl/components/server-options/BackupIdOption.jsx"; +import BackupKeyOption from "@mcl/components/server-options/BackupKeyOption.jsx"; +import BackupIntervalOption, { + backupIntervalDefault, +} from "@mcl/components/server-options/BackupIntervalOption.jsx"; + +const defaultServer = { + version: "latest", + serverType: serverTypeOptions[0], + cpu: cpuOptions[0], + memory: memoryOptions[2], // 1.5GB +}; + +export default function CreateCoreOptions() { + const [backupEnabled, setBackupEnabled] = useState(false); + const [spec, setSpec] = useState(defaultServer); + const nav = useNavigate(); + const createServer = useCreateServer(spec); + + const updateSpec = (attr, val) => { + const s = { ...spec }; + s[attr] = val; + setSpec(s); + }; + + const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); + + async function upsertSpec() { + if (validateSpec() !== "validated") return; + createServer(spec) + // .then(() => nav("/")) + .catch(alert); + } + + function validateSpec() { + console.log("TODO CREATE VALIDATION"); + if (!spec.host) return alertValidationError("Host cannot be blank"); + if (!spec.name) return alertValidationError("Name not included"); + if (!spec.version) return alertValidationError("Version cannot be blank"); + return "validated"; + } + + function alertValidationError(reason) { + alert(`Could not validate spec because: ${reason}`); + } + + const toggleBackupEnabled = () => { + const s = { ...spec }; + if (!backupEnabled) { + (s.backupInterval = backupIntervalDefault), + (s.backupBucket = `/mcl/server-backups/${( + s.name ?? "my-server" + ).toLowerCase()}`); + } else for (var k in s) if (k.startsWith("backup")) delete s[k]; + setSpec(s); + console.log(s); + setBackupEnabled(!backupEnabled); + }; + + return ( + + + + + + + + + + } + label="Enable Backups?" + labelPlacement="start" + sx={{ mr: "auto" }} + /> + {backupEnabled && ( + + Backups + + + + + + + )} + + + + + ); +} diff --git a/src/pages/CreateOptions.jsx b/src/pages/CreateOptionsFull.jsx similarity index 100% rename from src/pages/CreateOptions.jsx rename to src/pages/CreateOptionsFull.jsx diff --git a/src/pages/Files.jsx b/src/pages/Files.jsx index 2794530..5226176 100644 --- a/src/pages/Files.jsx +++ b/src/pages/Files.jsx @@ -1,20 +1,36 @@ -import { useEffect } from "react"; +import { useState, useEffect } from "react"; import { useSearchParams, useNavigate } from "react-router-dom"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import Toolbar from "@mui/material/Toolbar"; +import FilePreview, { + useFilePreview, +} from "@mcl/components/files/FilePreview.jsx"; import MineclusterFiles from "@mcl/components/files/MineclusterFiles.jsx"; export default function Files() { + const [open, dialogToggle] = useFilePreview(); + const [previewData, setPreviewData] = useState(); const [searchParams] = useSearchParams(); const currentServer = searchParams.get("server"); const nav = useNavigate(); useEffect(() => { if (!currentServer) nav("/"); }, [currentServer]); + + function changePreview(name, fileData) { + setPreviewData({ name, fileData }); + dialogToggle(); + } + return ( - + + ); } diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 2a415cb..0e80d2a 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -30,6 +30,7 @@ export default function Home() { setServer(s); rconToggle(); }; + return ( @@ -50,10 +51,10 @@ export default function Home() { {!isLoading && servers.map((s, k) => ( - + ))} - + + ); diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx index 31c1389..3dbc6d4 100644 --- a/src/components/files/MineclusterFiles.jsx +++ b/src/components/files/MineclusterFiles.jsx @@ -105,7 +105,7 @@ export default function MineclusterFiles(props) { const formData = new FormData(); formData.append("file", file); formData.append("id", serverId); - formData.append("path", [...dirStack, name].join("/")); + formData.append("path", [...dirStack, file.name].join("/")); await fetch("/api/files/upload", { method: "POST", body: formData, @@ -125,7 +125,8 @@ export default function MineclusterFiles(props) { function previewFile(file) { const { name } = file; previewServerItem(serverId, [...dirStack, name].join("/")).then( - (fileData) => changePreview(name, fileData), + (fileData) => + changePreview(name, fileData, [...dirStack, name].join("/")), ); } diff --git a/src/components/files/TextEditor.jsx b/src/components/files/TextEditor.jsx new file mode 100644 index 0000000..6151cf8 --- /dev/null +++ b/src/components/files/TextEditor.jsx @@ -0,0 +1,21 @@ +import ReactQuill from "react-quill"; +import { useState, useEffect, useMemo, memo } from "react"; +import "react-quill/dist/quill.snow.css"; + +const buildDelta = (t) => { + if (!t) return; + const ops = t.split("\n").map((l) => ({ insert: `${l}\n` })); + return { ops }; +}; + +function TextEditor(props) { + const { text, onChange } = props; + const [delta, setDelta] = useState(); + const constructDelta = useMemo(() => buildDelta(text), [text]); + useEffect(() => setDelta(constructDelta), [text]); + + const onEditorChange = (c, d, s, editor) => onChange(editor.getText()); + + return ; +} +export default memo(TextEditor, (a, b) => a.text === b.text); diff --git a/src/components/server-options/ExtraPortsOption.jsx b/src/components/server-options/ExtraPortsOption.jsx new file mode 100644 index 0000000..57c026e --- /dev/null +++ b/src/components/server-options/ExtraPortsOption.jsx @@ -0,0 +1,41 @@ +import { useState } from "react"; +import TextField from "@mui/material/TextField"; +import Autocomplete from "@mui/material/Autocomplete"; +import Chip from "@mui/material/Chip"; + +const validatePort = (p) => p !== "25565" && p !== "25575" && p.length < 6; + +export default function ExtraPortsOption(props) { + const [extraPorts, setExtraPorts] = useState([]); + const { onChange } = props; + + function portChange(e, val, optionType, changedValue) { + if (optionType === "clear") { + setExtraPorts([]); + onChange("extraPorts", []); + return; + } + if (!validatePort(changedValue.option)) + return alert("That port cannot be added/removed as an extra port!"); + setExtraPorts(val); + onChange("extraPorts", val); + } + + return ( + } + renderTags={(value, getTagProps) => + value.map((option, index) => { + const defaultChipProps = getTagProps({ index }); + return ; + }) + } + /> + ); +} diff --git a/src/pages/CreateCoreOptions.jsx b/src/pages/CreateCoreOptions.jsx index ee8b92f..afe2f0d 100644 --- a/src/pages/CreateCoreOptions.jsx +++ b/src/pages/CreateCoreOptions.jsx @@ -21,6 +21,7 @@ import CpuOption, { import MemoryOption, { memoryOptions, } from "@mcl/components/server-options/MemoryOption.jsx"; +import ExtraPortsOption from "@mcl/components/server-options/ExtraPortsOption.jsx"; import BackupHostOption from "@mcl/components/server-options/BackupHostOption.jsx"; import BackupBucketOption from "@mcl/components/server-options/BackupBucketOption.jsx"; @@ -35,6 +36,7 @@ const defaultServer = { serverType: serverTypeOptions[0], cpu: cpuOptions[0], memory: memoryOptions[2], // 1.5GB + extraPorts: [], }; export default function CreateCoreOptions() { @@ -79,7 +81,6 @@ export default function CreateCoreOptions() { ).toLowerCase()}`); } else for (var k in s) if (k.startsWith("backup")) delete s[k]; setSpec(s); - console.log(s); setBackupEnabled(!backupEnabled); }; @@ -98,6 +99,7 @@ export default function CreateCoreOptions() { /> + export async function previewServerItem(serverId, path) { const resp = await fetchApiCore("/files/item", { id: serverId, path }); - if (!resp.status === 200) return console.log("AHHHH"); + if (resp.status !== 200) return console.log("AHHHH"); const blob = await resp.blob(); return blob; } From 3d73f69678a3a984d1de73950ff243f5d0a4c921 Mon Sep 17 00:00:00 2001 From: dunemask Date: Tue, 23 Jan 2024 20:10:00 +0000 Subject: [PATCH 23/56] [FEATURE] Mutable Servers & Edit UI (#8) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/8 --- lib/controllers/lifecycle-controller.js | 74 +++++++--- lib/database/queries/server-queries.js | 48 ++++++- lib/routes/server-route.js | 4 + .../server-options/BackupBucketOption.jsx | 2 +- .../server-options/BackupHostOption.jsx | 3 +- .../server-options/BackupIdOption.jsx | 3 +- src/components/server-options/CpuOption.jsx | 2 +- .../server-options/ExtraPortsOption.jsx | 3 +- src/components/server-options/HostOption.jsx | 3 +- .../server-options/MemoryOption.jsx | 2 +- src/components/server-options/NameOption.jsx | 3 +- .../server-options/ServerTypeOption.jsx | 2 +- .../server-options/VersionOption.jsx | 2 +- src/components/servers/ServerCard.jsx | 1 + src/nav/MCLPages.jsx | 10 +- src/pages/CreateCoreOptions.jsx | 8 +- src/pages/Edit.jsx | 14 ++ src/pages/EditCoreOptions.jsx | 134 ++++++++++++++++++ src/util/queries.js | 8 ++ 19 files changed, 291 insertions(+), 35 deletions(-) create mode 100644 src/pages/Edit.jsx create mode 100644 src/pages/EditCoreOptions.jsx diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 57b8385..5aa271d 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -4,34 +4,19 @@ import { createServerEntry, deleteServerEntry, getServerEntry, + modifyServerEntry, } from "../database/queries/server-queries.js"; -import { sendError } from "../util/ExpressClientError.js"; +import ExpressClientError, { sendError } from "../util/ExpressClientError.js"; import { toggleServer } from "../k8s/k8s-server-control.js"; const dnsRegex = new RegExp( `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`, ); -function payloadFilter(req, res) { +function backupPayloadFilter(req, res) { const serverSpec = req.body; - if (!serverSpec) return res.sendStatus(400); - const { name, host, version, serverType, memory, extraPorts } = serverSpec; const { backupHost, backupBucket, backupId, backupKey, backupInterval } = serverSpec; - if (!name) return res.status(400).send("Server name is required!"); - if (!host) return res.status(400).send("Server host is required!"); - if (!dnsRegex.test(host)) return res.status(400).send("Hostname invalid!"); - if (!version) return res.status(400).send("Server version is required!"); - if (!serverType) return res.status(400).send("Server type is required!"); - if (!memory) return res.status(400).send("Memory is required!"); - if ( - !!extraPorts && - (!Array.isArray(extraPorts) || - extraPorts.find((e) => typeof e !== "string" || e.length > 5)) - ) - return res - .status(400) - .send("Extra ports must be a list of strings with length of 5!"); // TODO: Impliment non creation time backups if ( !!backupHost || @@ -57,6 +42,27 @@ function payloadFilter(req, res) { return "filtered"; } +function payloadFilter(req, res) { + const serverSpec = req.body; + if (!serverSpec) return res.sendStatus(400); + const { name, host, version, serverType, memory, extraPorts } = serverSpec; + if (!name) return res.status(400).send("Server name is required!"); + if (!host) return res.status(400).send("Server host is required!"); + if (!dnsRegex.test(host)) return res.status(400).send("Hostname invalid!"); + if (!version) return res.status(400).send("Server version is required!"); + if (!serverType) return res.status(400).send("Server type is required!"); + if (!memory) return res.status(400).send("Memory is required!"); + if ( + !!extraPorts && + (!Array.isArray(extraPorts) || + extraPorts.find((e) => typeof e !== "string" || e.length > 5)) + ) + return res + .status(400) + .send("Extra ports must be a list of strings with length of 5!"); + return "filtered"; +} + function checkServerId(serverSpec) { if (!serverSpec) throw new ExpressClientError({ c: 400 }); if (!serverSpec.id) @@ -65,6 +71,7 @@ function checkServerId(serverSpec) { export async function createServer(req, res) { if (payloadFilter(req, res) !== "filtered") return; + if (backupPayloadFilter(req, res) !== "filtered") return; const serverSpec = req.body; try { const serverEntry = await createServerEntry(serverSpec); @@ -117,3 +124,34 @@ export async function stopServer(req, res) { .then(() => res.sendStatus(200)) .catch(sendError(res)); } + +export async function getServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerId(serverSpec); + } catch (e) { + return sendError(res)(e); + } + const { id } = serverSpec; + getServerEntry(id).then((s) => { + delete s.backupKey; // Do not let this ever get to an API client + s.backupBucket = s.backupPath; + delete s.backupPath; + delete s.backupId; // Do not let this ever get to an API client + res.json(s); + }); +} + +export async function modifyServer(req, res) { + if (payloadFilter(req, res) !== "filtered") return; + const serverSpec = req.body; + try { + checkServerId(serverSpec); + const serverEntry = await modifyServerEntry(serverSpec); + // await createServerResources(serverEntry); + res.sendStatus(200); + } catch (e) { + sendError(res)(e); + } +} diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index 93e84bd..66300bc 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -1,5 +1,10 @@ import pg from "../postgres.js"; -import { deleteQuery, insertQuery, selectWhereQuery } from "../pg-query.js"; +import { + deleteQuery, + insertQuery, + selectWhereQuery, + updateWhereAllQuery, +} from "../pg-query.js"; import ExpressClientError from "../../util/ExpressClientError.js"; const table = "servers"; @@ -30,7 +35,7 @@ export async function createServerEntry(serverSpec) { server_type, memory, extra_ports, - backup_enabled: !!backup_interval, // We already verified the payload, so any backup key will work + backup_enabled: !!backup_interval ? true : null, // We already verified the payload, so any backup key will work backup_host, backup_bucket_path, backup_id, @@ -128,6 +133,45 @@ export async function getServerEntry(serverId) { } } +export async function modifyServerEntry(serverSpec) { + const { + id, + name, + host, + version, + serverType: server_type, + memory, + extraPorts: extra_ports, + backupEnabled: backup_enabled, + backupHost: backup_host, + backupBucket: backup_bucket_path, + backupId: backup_id, + backupKey: backup_key, + backupInterval: backup_interval, + } = serverSpec; + + const q = updateWhereAllQuery( + table, + { + name, + host, + version, + server_type, + memory, + extra_ports, + backup_enabled, + backup_host, + backup_bucket_path, + backup_id, + backup_key, + backup_interval, + }, + { id }, + ); + + return pg.query(q); +} + export async function getServerEntries() { const q = `SELECT * FROM ${table}`; return pg.query(q); diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js index 7361abd..d6eb922 100644 --- a/lib/routes/server-route.js +++ b/lib/routes/server-route.js @@ -4,6 +4,8 @@ import { deleteServer, startServer, stopServer, + getServer, + modifyServer, } from "../controllers/lifecycle-controller.js"; import { serverInstances, @@ -18,4 +20,6 @@ router.post("/start", startServer); router.post("/stop", stopServer); router.get("/list", serverList); router.get("/instances", serverInstances); +router.post("/blueprint", getServer); +router.post("/modify", modifyServer); export default router; diff --git a/src/components/server-options/BackupBucketOption.jsx b/src/components/server-options/BackupBucketOption.jsx index bc7139d..7650187 100644 --- a/src/components/server-options/BackupBucketOption.jsx +++ b/src/components/server-options/BackupBucketOption.jsx @@ -6,7 +6,7 @@ export default function BackupBucketOption(props) { p !== "25565" && p !== "25575" && p.length < 6; export default function ExtraPortsOption(props) { - const [extraPorts, setExtraPorts] = useState([]); + const { extraPorts: initExtraPorts } = props; + const [extraPorts, setExtraPorts] = useState(initExtraPorts ?? []); const { onChange } = props; function portChange(e, val, optionType, changedValue) { diff --git a/src/components/server-options/HostOption.jsx b/src/components/server-options/HostOption.jsx index 7efe6a9..d03d1db 100644 --- a/src/components/server-options/HostOption.jsx +++ b/src/components/server-options/HostOption.jsx @@ -1,10 +1,11 @@ import TextField from "@mui/material/TextField"; export default function HostOption(props) { - const { onChange } = props; + const { value, onChange } = props; return ( diff --git a/src/nav/MCLPages.jsx b/src/nav/MCLPages.jsx index 56ab52e..c2518c7 100644 --- a/src/nav/MCLPages.jsx +++ b/src/nav/MCLPages.jsx @@ -1,6 +1,7 @@ import Home from "@mcl/pages/Home.jsx"; import Create from "@mcl/pages/Create.jsx"; import Files from "@mcl/pages/Files.jsx"; +import Edit from "@mcl/pages/Edit.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"; @@ -21,10 +22,17 @@ export default [ visible: true, }, { - name: "Edit", + name: "Files", path: "/mcl/files", icon: , component: , visible: false, }, + { + name: "Edit", + path: "/mcl/edit", + icon: , + component: , + visible: false, + }, ]; diff --git a/src/pages/CreateCoreOptions.jsx b/src/pages/CreateCoreOptions.jsx index afe2f0d..4d68121 100644 --- a/src/pages/CreateCoreOptions.jsx +++ b/src/pages/CreateCoreOptions.jsx @@ -55,8 +55,8 @@ export default function CreateCoreOptions() { async function upsertSpec() { if (validateSpec() !== "validated") return; - createServer(spec) - // .then(() => nav("/")) + createServer() + .then(() => nav("/")) .catch(alert); } @@ -90,8 +90,8 @@ export default function CreateCoreOptions() { sx={{ width: "100%", maxWidth: "600px", margin: "auto" }} > - - + + + + + + + ); +} diff --git a/src/pages/EditCoreOptions.jsx b/src/pages/EditCoreOptions.jsx new file mode 100644 index 0000000..163a6a1 --- /dev/null +++ b/src/pages/EditCoreOptions.jsx @@ -0,0 +1,134 @@ +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import FormControl from "@mui/material/FormControl"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Switch from "@mui/material/Switch"; +import Typography from "@mui/material/Typography"; +import { useGetServer, useModifyServer } from "@mcl/queries"; + +// Core Options +import NameOption from "@mcl/components/server-options/NameOption.jsx"; +import HostOption from "@mcl/components/server-options/HostOption.jsx"; +import VersionOption from "@mcl/components/server-options/VersionOption.jsx"; +import ServerTypeOption, { + serverTypeOptions, +} from "@mcl/components/server-options/ServerTypeOption.jsx"; +import CpuOption, { + cpuOptions, +} from "@mcl/components/server-options/CpuOption.jsx"; +import MemoryOption, { + memoryOptions, +} from "@mcl/components/server-options/MemoryOption.jsx"; +import ExtraPortsOption from "@mcl/components/server-options/ExtraPortsOption.jsx"; + +import BackupHostOption from "@mcl/components/server-options/BackupHostOption.jsx"; +import BackupBucketOption from "@mcl/components/server-options/BackupBucketOption.jsx"; +import BackupIdOption from "@mcl/components/server-options/BackupIdOption.jsx"; +import BackupKeyOption from "@mcl/components/server-options/BackupKeyOption.jsx"; +import BackupIntervalOption, { + backupIntervalDefault, +} from "@mcl/components/server-options/BackupIntervalOption.jsx"; + +export default function EditCoreOptions(props) { + const { serverId } = props; + const [spec, setSpec] = useState(); + const modifyServer = useModifyServer(spec); + const { isLoading, data: serverBlueprint } = useGetServer(serverId); + + useEffect(() => setSpec(serverBlueprint), [serverBlueprint]); + + const updateSpec = (attr, val) => { + const s = { ...spec }; + s[attr] = val; + setSpec(s); + }; + + const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); + + const upsertSpec = () => { + modifyServer(spec); + }; + + const toggleBackupEnabled = () => + updateSpec("backupEnabled", !spec.backupEnabled); + + function validateSpec() { + console.log("TODO CREATE VALIDATION"); + if (!spec.host) return alertValidationError("Host cannot be blank"); + if (!spec.name) return alertValidationError("Name not included"); + if (!spec.version) return alertValidationError("Version cannot be blank"); + return "validated"; + } + + function alertValidationError(reason) { + alert(`Could not validate spec because: ${reason}`); + } + + if (!spec) return; // TODO: Add loading for spec + return ( + + + + + + + + + + + {spec.backupEnabled !== null && ( + + } + label="Enable Backups?" + labelPlacement="start" + sx={{ mr: "auto" }} + /> + )} + + {/*spec.backupEnabled && ( // TODO: Disabled while secrets are insecure + + Backups + + + + + + + )*/} + + + + + ); +} diff --git a/src/util/queries.js b/src/util/queries.js index 2e02366..c80be01 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -39,6 +39,14 @@ export const useDeleteServer = (serverId) => postJsonApi("/server/delete", { id: serverId }, "server-instances", "DELETE"); export const useCreateServer = (spec) => postJsonApi("/server/create", spec, "server-list"); +export const useModifyServer = (spec) => + postJsonApi("/server/modify", spec, "server-list"); + +export const useGetServer = (serverId) => + useQuery({ + queryKey: [`server-blueprint-${serverId}`], + queryFn: fetchApiPost("/server/blueprint", { id: serverId }), + }); export const getServerFiles = async (serverId, path) => fetchApiCore("/files/list", { id: serverId, path }, "POST", true); From 43c440949816f848ec62ea92911d7b856150e30f Mon Sep 17 00:00:00 2001 From: dunemask Date: Wed, 24 Jan 2024 16:39:57 +0000 Subject: [PATCH 24/56] [FEATURE] Storage adjustments and minor tweaks (#9) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/9 --- lib/controllers/lifecycle-controller.js | 12 +++++-- .../migrations/1_create_servers_table.sql | 1 + lib/database/queries/server-queries.js | 17 ++++++++++ lib/k8s/configs/server-deployment.yml | 8 +++-- lib/k8s/server-containers.js | 22 ++++++++++--- lib/k8s/server-create.js | 29 +++++++++++------ .../server-options/BackupHostOption.jsx | 2 +- .../server-options/BackupIdOption.jsx | 2 +- .../server-options/BackupKeyOption.jsx | 3 +- .../server-options/StorageOption.jsx | 26 ++++++++++++++++ src/components/servers/RconSocket.js | 2 +- src/pages/CreateCoreOptions.jsx | 31 +++++++++++-------- src/pages/EditCoreOptions.jsx | 5 ++- 13 files changed, 121 insertions(+), 39 deletions(-) create mode 100644 src/components/server-options/StorageOption.jsx diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 5aa271d..ceede86 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -15,8 +15,14 @@ const dnsRegex = new RegExp( function backupPayloadFilter(req, res) { const serverSpec = req.body; - const { backupHost, backupBucket, backupId, backupKey, backupInterval } = - serverSpec; + const { + storage, + backupHost, + backupBucket, + backupId, + backupKey, + backupInterval, + } = serverSpec; // TODO: Impliment non creation time backups if ( !!backupHost || @@ -25,6 +31,8 @@ function backupPayloadFilter(req, res) { !!backupKey || !!backupInterval ) { + if (storage === 0) + return res.status(400).send("Backups cannot be used if storage is zero!"); // If any keys are required, all are required if ( !( diff --git a/lib/database/migrations/1_create_servers_table.sql b/lib/database/migrations/1_create_servers_table.sql index 3ef14ee..33ddc5a 100644 --- a/lib/database/migrations/1_create_servers_table.sql +++ b/lib/database/migrations/1_create_servers_table.sql @@ -7,6 +7,7 @@ CREATE TABLE servers ( server_type varchar(63) DEFAULT 'VANILLA', cpu varchar(63) DEFAULT '500', memory varchar(63) DEFAULT '512', + storage varchar(63) DEFAULT NULL, backup_enabled BOOLEAN DEFAULT FALSE, backup_host varchar(255) DEFAULT NULL, backup_bucket_path varchar(255) DEFAULT NULL, diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index 66300bc..c98902e 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -20,7 +20,9 @@ export async function createServerEntry(serverSpec) { host, version, serverType: server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage: storage_val, extraPorts: extra_ports, backupHost: backup_host, backupBucket: backup_bucket_path, @@ -28,12 +30,15 @@ export async function createServerEntry(serverSpec) { backupKey: backup_key, backupInterval: backup_interval, } = serverSpec; + var q = insertQuery(table, { name, host, version, server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage: !storage_val || storage_val === "0" ? null : storage_val, // 0, undefined, null, or "0" becomes null extra_ports, backup_enabled: !!backup_interval ? true : null, // We already verified the payload, so any backup key will work backup_host, @@ -51,7 +56,9 @@ export async function createServerEntry(serverSpec) { host, version, server_type: serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extra_ports: extraPorts, backup_enabled: backupEnabled, backup_host: backupHost, @@ -68,7 +75,9 @@ export async function createServerEntry(serverSpec) { host, version, serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extraPorts, backupEnabled, backupHost, @@ -102,7 +111,9 @@ export async function getServerEntry(serverId) { host, version, server_type: serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extra_ports: extraPorts, backup_enabled: backupEnabled, backup_host: backupHost, @@ -119,7 +130,9 @@ export async function getServerEntry(serverId) { host, version, serverType, + cpu, // TODO: Ignored for now by the K8S manifests memory, + storage, extraPorts, backupEnabled, backupHost, @@ -140,7 +153,9 @@ export async function modifyServerEntry(serverSpec) { host, version, serverType: server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + // storage, // DO NOT INCLUDE THIS KEY, Not all storage providers in kubernetes allow for dynamically resizable PVCs extraPorts: extra_ports, backupEnabled: backup_enabled, backupHost: backup_host, @@ -157,7 +172,9 @@ export async function modifyServerEntry(serverSpec) { host, version, server_type, + cpu, // TODO: Ignored for now by the K8S manifests memory, + // storage, // DO NOT INCLUDE THIS KEY, Not all storage providers in kubernetes allow for dynamically resizable PVCs extra_ports, backup_enabled, backup_host, diff --git a/lib/k8s/configs/server-deployment.yml b/lib/k8s/configs/server-deployment.yml index 275013a..0acd0cf 100644 --- a/lib/k8s/configs/server-deployment.yml +++ b/lib/k8s/configs/server-deployment.yml @@ -30,11 +30,13 @@ spec: # runAsUser: 1000 terminationGracePeriodSeconds: 30 volumes: - - name: datadir - persistentVolumeClaim: - claimName: changeme-pvc-name + - emptyDir: {} + name: datadir - emptyDir: {} name: backupdir + # - name: datadir + # persistentVolumeClaim: + # claimName: changeme-pvc-name # - name: rclone-config # secret: # defaultMode: 420 diff --git a/lib/k8s/server-containers.js b/lib/k8s/server-containers.js index 0192d2a..a969c69 100644 --- a/lib/k8s/server-containers.js +++ b/lib/k8s/server-containers.js @@ -4,7 +4,7 @@ import yaml from "js-yaml"; const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); export function getFtpContainer(serverSpec) { - const { mclName } = serverSpec; + const { mclName, storage } = serverSpec; const ftpContainer = loadYaml("lib/k8s/configs/containers/ftp-server.yml"); ftpContainer.name = `mcl-${mclName}-ftp`; const ftpPortList = [ @@ -18,11 +18,12 @@ export function getFtpContainer(serverSpec) { name, protocol: "TCP", })); + if (!storage) delete ftpContainer.volumeMounts; return ftpContainer; } export function getCoreServerContainer(serverSpec) { - const { mclName, version, serverType, memory } = serverSpec; + const { mclName, version, serverType, memory, storage } = serverSpec; const container = loadYaml("lib/k8s/configs/containers/minecraft-server.yml"); // Container Updates container.name = `mcl-${mclName}-server`; @@ -38,12 +39,21 @@ export function getCoreServerContainer(serverSpec) { // RCON const rs = `mcl-${mclName}-rcon-secret`; findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + if (!storage) delete container.volumeMounts; return container; } export function getServerContainer(serverSpec) { - const { difficulty, gamemode, motd, maxPlayers, seed, ops, whitelist } = - serverSpec; + const { + difficulty, + gamemode, + motd, + maxPlayers, + seed, + ops, + whitelist, + storage, + } = serverSpec; const container = getCoreServerContainer(serverSpec); const findEnv = (k) => container.env.find(({ name: n }) => n === k); @@ -57,12 +67,13 @@ export function getServerContainer(serverSpec) { updateEnv("SEED", seed); updateEnv("OPS", ops); updateEnv("WHITELIST", whitelist); */ + if (!storage) delete container.volumeMounts; return container; } export function getBackupContainer(serverSpec) { - const { mclName, backupEnabled, backupPath } = serverSpec; + const { mclName, backupEnabled, backupPath, storage } = serverSpec; const container = loadYaml("lib/k8s/configs/containers/minecraft-backup.yml"); if (!backupEnabled) return; const findEnv = (k) => container.env.find(({ name: n }) => n === k); @@ -73,6 +84,7 @@ export function getBackupContainer(serverSpec) { // RCON const rs = `mcl-${mclName}-rcon-secret`; findEnv("RCON_PASSWORD").valueFrom.secretKeyRef.name = rs; + if (!storage) delete container.volumeMounts; return container; } diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 7578838..421a244 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -86,18 +86,19 @@ function createRconSecret(serverSpec) { } function createServerVolume(serverSpec) { - const { mclName, id } = serverSpec; + const { mclName, id, storage } = serverSpec; + if (!storage) return; const volumeYaml = loadYaml("lib/k8s/configs/server-pvc.yml"); volumeYaml.metadata.labels.service = `mcl-${mclName}-server`; volumeYaml.metadata.name = `mcl-${mclName}-volume`; volumeYaml.metadata.namespace = namespace; volumeYaml.metadata.annotations["minecluster.dunemask.net/id"] = id; - volumeYaml.spec.resources.requests.storage = "5Gi"; // TODO: Changeme + volumeYaml.spec.resources.requests.storage = `${storage}Gi`; return volumeYaml; } function createServerDeploy(serverSpec) { - const { mclName, id, backupEnabled } = serverSpec; + const { mclName, id, backupEnabled, storage } = serverSpec; const deployYaml = loadYaml("lib/k8s/configs/server-deployment.yml"); const { metadata } = deployYaml; const serverContainer = getServerContainer(serverSpec); @@ -119,9 +120,18 @@ function createServerDeploy(serverSpec) { id; // Volumes - deployYaml.spec.template.spec.volumes.find( - ({ name }) => name === "datadir", - ).persistentVolumeClaim.claimName = `mcl-${mclName}-volume`; + if (!!storage) { + const dvi = deployYaml.spec.template.spec.volumes.findIndex( + ({ name }) => name === "datadir", + ); + delete deployYaml.spec.template.spec.volumes[dvi].emptyDir; + deployYaml.spec.template.spec.volumes[dvi] = { + ...deployYaml.spec.template.spec.volumes[dvi], + persistentVolumeClaim: { + claimName: `mcl-${mclName}-volume`, + }, + }; + } // Backups if (backupEnabled) { @@ -194,9 +204,10 @@ export default async function createServerResources(createSpec) { const rconService = createRconService(createSpec); const extraService = createExtraService(createSpec); const serverResources = []; - serverResources.push( - k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume), - ); + if (!!serverVolume) + serverResources.push( + k8sCore.createNamespacedPersistentVolumeClaim(namespace, serverVolume), + ); if (!!extraService) serverResources.push( k8sCore.createNamespacedService(namespace, extraService), diff --git a/src/components/server-options/BackupHostOption.jsx b/src/components/server-options/BackupHostOption.jsx index 8f0798b..5d96002 100644 --- a/src/components/server-options/BackupHostOption.jsx +++ b/src/components/server-options/BackupHostOption.jsx @@ -6,7 +6,7 @@ export default function BackupHostOption(props) { (i + 1) * 0.5); + +export default function StorageOption(props) { + const { value, onChange } = props; + return ( + + No Storage + {storageOptions.map((o, i) => ( + {`${o} GB`} + ))} + + ); +} diff --git a/src/components/servers/RconSocket.js b/src/components/servers/RconSocket.js index 42a1226..f18c0ef 100644 --- a/src/components/servers/RconSocket.js +++ b/src/components/servers/RconSocket.js @@ -22,7 +22,7 @@ export default class RconSocket { onRconError(v) { this.rconLive = false; - console.log("Server sent" + v); + console.log("Server sent: ", v); } onConnect() { diff --git a/src/pages/CreateCoreOptions.jsx b/src/pages/CreateCoreOptions.jsx index 4d68121..ad983ae 100644 --- a/src/pages/CreateCoreOptions.jsx +++ b/src/pages/CreateCoreOptions.jsx @@ -22,6 +22,7 @@ import MemoryOption, { memoryOptions, } from "@mcl/components/server-options/MemoryOption.jsx"; import ExtraPortsOption from "@mcl/components/server-options/ExtraPortsOption.jsx"; +import StorageOption from "@mcl/components/server-options/StorageOption.jsx"; import BackupHostOption from "@mcl/components/server-options/BackupHostOption.jsx"; import BackupBucketOption from "@mcl/components/server-options/BackupBucketOption.jsx"; @@ -36,6 +37,7 @@ const defaultServer = { serverType: serverTypeOptions[0], cpu: cpuOptions[0], memory: memoryOptions[2], // 1.5GB + storage: 0, extraPorts: [], }; @@ -99,20 +101,23 @@ export default function CreateCoreOptions() { /> + - - } - label="Enable Backups?" - labelPlacement="start" - sx={{ mr: "auto" }} - /> - {backupEnabled && ( + {spec.storage !== 0 && ( + + } + label="Enable Backups?" + labelPlacement="start" + sx={{ mr: "auto" }} + /> + )} + {backupEnabled && spec.storage !== 0 && ( setSpec(serverBlueprint), [serverBlueprint]); @@ -47,9 +48,7 @@ export default function EditCoreOptions(props) { const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); - const upsertSpec = () => { - modifyServer(spec); - }; + const upsertSpec = () => modifyServer().then(() => nav("/")); const toggleBackupEnabled = () => updateSpec("backupEnabled", !spec.backupEnabled); From 8a70fad76a490c5f477062da140b181d9930e172 Mon Sep 17 00:00:00 2001 From: dunemask Date: Wed, 24 Jan 2024 17:25:43 +0000 Subject: [PATCH 25/56] [FEATURE] Cluster Wide Helm Value Toggle (#10) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/10 --- templates/clusterrole-binding.yaml | 14 ++++++++++++++ templates/clusterrole.yaml | 27 +++++++++++++++++++++++++++ values.yaml | 1 + 3 files changed, 42 insertions(+) create mode 100644 templates/clusterrole-binding.yaml create mode 100644 templates/clusterrole.yaml diff --git a/templates/clusterrole-binding.yaml b/templates/clusterrole-binding.yaml new file mode 100644 index 0000000..0a5e7d4 --- /dev/null +++ b/templates/clusterrole-binding.yaml @@ -0,0 +1,14 @@ +{{- if and (.Values.serviceAccount.create) (.Values.serviceAccount.clusterWide) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "minecluster.serviceAccountName" . }} +subjects: +- kind: ServiceAccount + name: {{ include "minecluster.serviceAccountName" . }} + namespace: {{ .Values.mcl.deploymentNamespace | default .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "minecluster.serviceAccountName" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/templates/clusterrole.yaml b/templates/clusterrole.yaml new file mode 100644 index 0000000..a0fb3e5 --- /dev/null +++ b/templates/clusterrole.yaml @@ -0,0 +1,27 @@ +{{- if and (.Values.serviceAccount.create) (.Values.serviceAccount.clusterWide) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "minecluster.serviceAccountName" . }} +rules: +- apiGroups: ["apps"] + resources: + - deployments + verbs: ["get", "list", "watch", "create", "patch", "update", "delete"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list"] +- apiGroups: [""] + resources: + - services + - pods + - pods/log + - containers + - persistentvolumeclaims + - secrets + verbs: ["get", "list", "watch", "create", "patch", "update", "delete"] +- apiGroups: ["metrics.k8s.io"] + resources: ["pods"] + verbs: ["list"] +{{- end }} diff --git a/values.yaml b/values.yaml index 2339df8..922fb54 100644 --- a/values.yaml +++ b/values.yaml @@ -15,6 +15,7 @@ nameOverride: "" fullnameOverride: "" serviceAccount: + clusterWide: false # Specifies whether a service account should be created create: true # Annotations to add to the service account From 4390f90b1c0cbd6e278c093274c294af264381ca Mon Sep 17 00:00:00 2001 From: Dunemask Date: Sat, 27 Jan 2024 22:42:32 -0700 Subject: [PATCH 26/56] [CHORE] Adjust repository backup path --- .gitea/workflows/s3-repo-backup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/s3-repo-backup.yml b/.gitea/workflows/s3-repo-backup.yml index 68c426c..77b0702 100644 --- a/.gitea/workflows/s3-repo-backup.yml +++ b/.gitea/workflows/s3-repo-backup.yml @@ -22,7 +22,7 @@ jobs: ACCESS_KEY_ID: ${{ env.S3_BACKUP_KEY_ID }} SECRET_ACCESS_KEY: ${{ env.S3_BACKUP_KEY }} MIRROR_SOURCE: ${{ env.REPO_DIR }} - MIRROR_TARGET: repository-backups/${{ gitea.repository }} + MIRROR_TARGET: backups/gitea-repositories/${{ gitea.repository }} STORAGE_SERVICE_URL: ${{env.S3_BACKUP_ENDPOINT}} with: args: --overwrite --remove From edbfc2348ae462ed6f8b7d4926940d9470087f25 Mon Sep 17 00:00:00 2001 From: dunemask Date: Sun, 4 Feb 2024 04:59:38 +0000 Subject: [PATCH 27/56] [FEATURE] Basic changes for basic testing in cubit (#11) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/11 --- lib/controllers/lifecycle-controller.js | 2 +- lib/k8s/server-status.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index ceede86..47acb41 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -84,7 +84,7 @@ export async function createServer(req, res) { try { const serverEntry = await createServerEntry(serverSpec); await createServerResources(serverEntry); - res.sendStatus(200); + res.json(serverEntry); } catch (e) { sendError(res)(e); } diff --git a/lib/k8s/server-status.js b/lib/k8s/server-status.js index 6317d8e..43f00af 100644 --- a/lib/k8s/server-status.js +++ b/lib/k8s/server-status.js @@ -39,7 +39,7 @@ function getServerStatus(server) { ) !== undefined; const serverAvailable = services.includes(`server`) && deploymentAvailable; const ftpAvailable = services.includes("ftp"); // TODO this needs some handling for container creation - return { serverAvailable, ftpAvailable, services }; + return { serverAvailable, ftpAvailable, services, deploymentAvailable }; } export async function getInstances() { @@ -53,15 +53,18 @@ export async function getInstances() { const serverInstances = serverDeployments.map((s) => { serverId = s.metadata.annotations["minecluster.dunemask.net/id"]; const entry = entries.find((e) => e.id === serverId); - const { ftpAvailable, serverAvailable, services } = getServerStatus(s); + const { ftpAvailable, serverAvailable, services, deploymentAvailable } = + getServerStatus(s); metrics = getServerMetrics(podMetricsRes, serverId, serverAvailable); return { name: !!entry ? entry.name : "Unknown", + host: !!entry ? entry.host : "Unkonwn", id: serverId, metrics, services, serverAvailable, ftpAvailable, + deploymentAvailable, }; }); return serverInstances; From 78c5b7248215bcac15815626bca2ca163a8e3239 Mon Sep 17 00:00:00 2001 From: dunemask Date: Mon, 5 Feb 2024 02:13:32 +0000 Subject: [PATCH 28/56] [FEATURE] Integrated Minecluster with Cairo & Established Gitea workflows (#12) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/12 --- .gitea/workflows/deploy.edge.yml | 28 +++++++++ .gitea/workflows/qa-api-tests.yml | 36 +++++++++++ lib/controllers/file-controller.js | 11 ++++ lib/controllers/lifecycle-controller.js | 18 +++--- lib/controllers/status-controller.js | 6 +- .../sub-controllers/console-controller.js | 5 +- .../migrations/1_create_servers_table.sql | 1 + lib/database/queries/server-queries.js | 23 +++++-- lib/k8s/k8s-config.js | 12 ++++ lib/k8s/k8s-server-control.js | 18 +++++- lib/k8s/server-create.js | 3 +- lib/k8s/server-delete.js | 3 +- lib/k8s/server-status.js | 9 ++- lib/routes/auth-route.js | 16 +++++ lib/routes/files-route.js | 4 +- lib/routes/middlewares/auth-middleware.js | 33 ++++++++++ lib/routes/server-route.js | 5 +- lib/routes/system-route.js | 7 ++- lib/server/router.js | 2 + package-lock.json | 41 ++++++++++++ package.json | 27 ++++---- src/components/files/FilePreview.jsx | 3 +- src/components/files/MineclusterFiles.jsx | 2 + src/components/servers/RconSocket.js | 2 + src/components/servers/RconView.jsx | 8 ++- src/ctx/SettingsContext.jsx | 2 + src/nav/Viewport.jsx | 7 ++- src/pages/Auth.jsx | 63 +++++++++++++++++++ src/util/auth.js | 40 ++++++++++++ src/util/queries.js | 9 ++- 30 files changed, 391 insertions(+), 53 deletions(-) create mode 100644 .gitea/workflows/deploy.edge.yml create mode 100644 .gitea/workflows/qa-api-tests.yml create mode 100644 lib/k8s/k8s-config.js create mode 100644 lib/routes/auth-route.js create mode 100644 lib/routes/middlewares/auth-middleware.js create mode 100644 src/pages/Auth.jsx create mode 100644 src/util/auth.js diff --git a/.gitea/workflows/deploy.edge.yml b/.gitea/workflows/deploy.edge.yml new file mode 100644 index 0000000..bae115f --- /dev/null +++ b/.gitea/workflows/deploy.edge.yml @@ -0,0 +1,28 @@ +name: Deploy Edge +run-name: ${{ gitea.actor }} Deploy Edge +on: + push: + branches: [ master ] + +env: + GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} + KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_EDGE }} + OASIS_PROD_CONFIG: ${{ secrets.OASIS_PROD_CONFIG }} + GARDEN_DEPLOY_ACTION: minecluster + # Additional Deploy Envars + POSTGRES_PROD_PASSWORD: ${{ secrets.POSTGRES_PROD_PASSWORD }} + MCL_KUBECONFIG: ${{ secrets.KUBECONFIG_USW_MC }} + + +jobs: + deploy-edge: + steps: + - name: Oasis Setup + uses: https://gitea.dunemask.dev/elysium/oasis-action@master + with: + gitea-token: ${{ env.GITEA_TOKEN }} + kubeconfig: ${{ env.KUBECONFIG_BASE64 }} + oasis-prod-config: ${{ env. OASIS_PROD_CONFIG }} + - name: Deploy to Edge env + run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge + working-directory: ${{ env.OASIS_WORKSPACE }} \ No newline at end of file diff --git a/.gitea/workflows/qa-api-tests.yml b/.gitea/workflows/qa-api-tests.yml new file mode 100644 index 0000000..4014415 --- /dev/null +++ b/.gitea/workflows/qa-api-tests.yml @@ -0,0 +1,36 @@ +name: QA API Tests +run-name: ${{ gitea.actor }} QA API Test +on: + pull_request: + branches: [ master ] + +env: + REPO_DIR: ${{ gitea.workspace }}/minecluster + KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_DEV }} + GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} + GARDEN_LINK_ACTION: build.minecluster-image + +jobs: + qa-api-tests: + steps: + - name: Oasis Setup + uses: https://gitea.dunemask.dev/elysium/oasis-action@master + with: + gitea-token: ${{ env.GITEA_TOKEN }} + kubeconfig: ${{ env.KUBECONFIG_BASE64 }} + # Test Code + - name: Checkout repository + uses: actions/checkout@v3 + with: + path: ${{ env.REPO_DIR }} + # Garden tests + - name: Link Repo code to Garden + run: garden link action $GARDEN_LINK_ACTION $REPO_DIR --env usw-ci --var cubit-projects=cairo,minecluster + working-directory: ${{ env.OASIS_WORKSPACE }} + # Cubit CI Tests + - name: Run Cubit tests in CI env + run: garden workflow qa-api-tests --env usw-ci --var ci-ttl=25 + working-directory: ${{ env.OASIS_WORKSPACE }} + - name: Status Alert + if: always() + run: echo "The Job ended with status ${{ job.status }}." \ No newline at end of file diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js index 1a92c17..83e1ab5 100644 --- a/lib/controllers/file-controller.js +++ b/lib/controllers/file-controller.js @@ -6,11 +6,14 @@ import { uploadServerItem, } from "../k8s/server-files.js"; import { sendError } from "../util/ExpressClientError.js"; +import { checkAuthorization } from "../database/queries/server-queries.js"; export async function listFiles(req, res) { const serverSpec = req.body; if (!serverSpec) return res.sendStatus(400); if (!serverSpec.id) return res.status(400).send("Server id missing!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) return res.sendStatus(403); listServerFiles(serverSpec) .then((f) => { const fileData = f.map((fi, i) => ({ @@ -31,6 +34,8 @@ export async function createFolder(req, res) { if (!serverSpec) return res.sendStatus(400); if (!serverSpec.id) return res.status(400).send("Server id missing!"); if (!serverSpec.path) return res.status(400).send("Path required!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) return res.sendStatus(403); createServerFolder(serverSpec) .then(() => res.sendStatus(200)) .catch(sendError(res)); @@ -43,6 +48,8 @@ export async function deleteItem(req, res) { if (!serverSpec.path) return res.status(400).send("Path required!"); if (serverSpec.isDir === undefined || serverSpec.isDir === null) return res.status(400).send("IsDIr required!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) return res.sendStatus(403); removeServerItem(serverSpec) .then(() => res.sendStatus(200)) .catch(sendError(res)); @@ -52,6 +59,8 @@ export async function uploadItem(req, res) { const serverSpec = req.body; if (!serverSpec.id) return res.status(400).send("Server id missing!"); if (!serverSpec.path) return res.status(400).send("Path required!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) return res.sendStatus(403); uploadServerItem(serverSpec, req.file) .then(() => res.sendStatus(200)) .catch(sendError(res)); @@ -61,6 +70,8 @@ export async function getItem(req, res) { const serverSpec = req.body; if (!serverSpec.id) return res.status(400).send("Server id missing!"); if (!serverSpec.path) return res.status(400).send("Path required!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) return res.sendStatus(403); getServerItem(serverSpec, res) .then(({ ds, ftpTransfer }) => { ds.pipe(res).on("error", sendError(res)); diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 47acb41..d5b9e3a 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -8,6 +8,7 @@ import { } from "../database/queries/server-queries.js"; import ExpressClientError, { sendError } from "../util/ExpressClientError.js"; import { toggleServer } from "../k8s/k8s-server-control.js"; +import { checkAuthorization } from "../database/queries/server-queries.js"; const dnsRegex = new RegExp( `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`, @@ -71,10 +72,13 @@ function payloadFilter(req, res) { return "filtered"; } -function checkServerId(serverSpec) { +async function checkServerId(cairoId, serverSpec) { if (!serverSpec) throw new ExpressClientError({ c: 400 }); if (!serverSpec.id) throw new ExpressClientError({ c: 400, m: "Server id missing!" }); + const authorized = await checkAuthorization(serverSpec.id, cairoId); + if (!authorized) + throw new ExpressClientError({ c: 403, m: "Access forbidden!" }); } export async function createServer(req, res) { @@ -82,7 +86,7 @@ export async function createServer(req, res) { if (backupPayloadFilter(req, res) !== "filtered") return; const serverSpec = req.body; try { - const serverEntry = await createServerEntry(serverSpec); + const serverEntry = await createServerEntry(req.cairoId, serverSpec); await createServerResources(serverEntry); res.json(serverEntry); } catch (e) { @@ -94,7 +98,7 @@ export async function deleteServer(req, res) { // Ensure spec is safe const serverSpec = req.body; try { - checkServerId(serverSpec); + await checkServerId(req.cairoId, serverSpec); } catch (e) { return sendError(res)(e); } @@ -109,7 +113,7 @@ export async function startServer(req, res) { // Ensure spec is safe const serverSpec = req.body; try { - checkServerId(serverSpec); + await checkServerId(req.cairoId, serverSpec); } catch (e) { return sendError(res)(e); } @@ -123,7 +127,7 @@ export async function stopServer(req, res) { // Ensure spec is safe const serverSpec = req.body; try { - checkServerId(serverSpec); + await checkServerId(req.cairoId, serverSpec); } catch (e) { return sendError(res)(e); } @@ -137,7 +141,7 @@ export async function getServer(req, res) { // Ensure spec is safe const serverSpec = req.body; try { - checkServerId(serverSpec); + await checkServerId(req.cairoId, serverSpec); } catch (e) { return sendError(res)(e); } @@ -155,7 +159,7 @@ export async function modifyServer(req, res) { if (payloadFilter(req, res) !== "filtered") return; const serverSpec = req.body; try { - checkServerId(serverSpec); + await checkServerId(req.cairoId, serverSpec); const serverEntry = await modifyServerEntry(serverSpec); // await createServerResources(serverEntry); res.sendStatus(200); diff --git a/lib/controllers/status-controller.js b/lib/controllers/status-controller.js index cd5ff57..a36a53b 100644 --- a/lib/controllers/status-controller.js +++ b/lib/controllers/status-controller.js @@ -1,9 +1,9 @@ -import { getDeployments } from "../k8s/k8s-server-control.js"; +import { getUserDeployments } from "../k8s/k8s-server-control.js"; import { getInstances } from "../k8s/server-status.js"; import { sendError } from "../util/ExpressClientError.js"; export function serverList(req, res) { - getDeployments() + getUserDeployments(req.cairoId) .then((sd) => res.json(sd.map((s) => s.metadata.name.substring(4)))) .catch((e) => { ERR("STATUS CONTROLLER", e); @@ -12,7 +12,7 @@ export function serverList(req, res) { } export function serverInstances(req, res) { - getInstances() + getInstances(req.cairoId) .then((i) => res.json(i)) .catch(sendError(res)); } diff --git a/lib/controllers/sub-controllers/console-controller.js b/lib/controllers/sub-controllers/console-controller.js index 264146a..6713960 100644 --- a/lib/controllers/sub-controllers/console-controller.js +++ b/lib/controllers/sub-controllers/console-controller.js @@ -4,10 +4,9 @@ import { Rcon as RconClient } from "rcon-client"; import stream from "stream"; import { ERR, WARN } from "../../util/logging.js"; import { getServerEntry } from "../../database/queries/server-queries.js"; - +import kc from "../../k8s/k8s-config.js"; // Kubernetes Configuration -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); + const k8sCore = kc.makeApiClient(k8s.CoreV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; diff --git a/lib/database/migrations/1_create_servers_table.sql b/lib/database/migrations/1_create_servers_table.sql index 33ddc5a..fe3f357 100644 --- a/lib/database/migrations/1_create_servers_table.sql +++ b/lib/database/migrations/1_create_servers_table.sql @@ -1,6 +1,7 @@ CREATE SEQUENCE servers_id_seq; CREATE TABLE servers ( id bigint NOT NULL DEFAULT nextval('servers_id_seq') PRIMARY KEY, + owner_cairo_id bigint, host varchar(255) DEFAULT NULL, name varchar(255) DEFAULT NULL, version varchar(63) DEFAULT 'latest', diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index c98902e..326572b 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -2,7 +2,7 @@ import pg from "../postgres.js"; import { deleteQuery, insertQuery, - selectWhereQuery, + selectWhereAllQuery, updateWhereAllQuery, } from "../pg-query.js"; import ExpressClientError from "../../util/ExpressClientError.js"; @@ -12,9 +12,18 @@ const asExpressClientError = (e) => { throw new ExpressClientError({ m: e.message, c: 409 }); }; -const getMclName = (host, id) => `${host.replaceAll(".", "-")}-${id}`; +const getMclName = (host, id) => + `${host.toLowerCase().replaceAll(".", "-")}-${id}`; -export async function createServerEntry(serverSpec) { +export async function checkAuthorization(serverId, cairoId) { + const q = selectWhereAllQuery(table, { + id: serverId, + owner_cairo_id: cairoId, + }); + return (await pg.query(q)).length === 1; +} + +export async function createServerEntry(cairoId, serverSpec) { const { name, host, @@ -33,6 +42,7 @@ export async function createServerEntry(serverSpec) { var q = insertQuery(table, { name, + owner_cairo_id: cairoId, host, version, server_type, @@ -52,6 +62,7 @@ export async function createServerEntry(serverSpec) { const entries = await pg.query(q); const { id, + owner_cairo_id: ownerCairoId, name, host, version, @@ -72,6 +83,7 @@ export async function createServerEntry(serverSpec) { name, mclName, id, + ownerCairoId, host, version, serverType, @@ -99,7 +111,7 @@ export async function deleteServerEntry(serverId) { export async function getServerEntry(serverId) { if (!serverId) asExpressClientError({ message: "Server ID Required!" }); - const q = selectWhereQuery(table, { id: serverId }); + const q = selectWhereAllQuery(table, { id: serverId }); try { const serverSpecs = await pg.query(q); if (serverSpecs.length === 0) return []; @@ -107,6 +119,7 @@ export async function getServerEntry(serverId) { throw Error("Multiple servers found with the same name!"); const { id, + owner_cairo_id: ownerCairoId, name, host, version, @@ -127,6 +140,7 @@ export async function getServerEntry(serverId) { name, mclName, id, + ownerCairoId, host, version, serverType, @@ -149,6 +163,7 @@ export async function getServerEntry(serverId) { export async function modifyServerEntry(serverSpec) { const { id, + // ownerCairoId: owner_cairo_id, // DIsabled! If these becomes a reqest, please create a new function! name, host, version, diff --git a/lib/k8s/k8s-config.js b/lib/k8s/k8s-config.js new file mode 100644 index 0000000..4167552 --- /dev/null +++ b/lib/k8s/k8s-config.js @@ -0,0 +1,12 @@ +import k8s from "@kubernetes/client-node"; +const MCL_KUBECONFIG = process.env.MCL_KUBECONFIG; +const envConfig = MCL_KUBECONFIG ? MCL_KUBECONFIG : null; +const kc = new k8s.KubeConfig(); +try { + if (!!envConfig) + kc.loadFromString(Buffer.from(envConfig, "base64").toString("utf8")); + else kc.loadFromDefault(); +} catch (e) { + kc.loadFromDefault(); +} +export default kc; diff --git a/lib/k8s/k8s-server-control.js b/lib/k8s/k8s-server-control.js index f82187a..c708328 100644 --- a/lib/k8s/k8s-server-control.js +++ b/lib/k8s/k8s-server-control.js @@ -7,8 +7,8 @@ import { getCoreServerContainer, getBackupContainer, } from "./server-containers.js"; -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); +import { checkAuthorization } from "../database/queries/server-queries.js"; +import kc from "./k8s-config.js"; const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const k8sCore = kc.makeApiClient(k8s.CoreV1Api); @@ -25,6 +25,20 @@ const mineclusterManaged = (o) => export const serverMatch = (serverId) => (o) => o.metadata.annotations["minecluster.dunemask.net/id"] === serverId; +export const cairoMatch = (cairoId) => (o) => + checkAuthorization( + o.metadata.annotations["minecluster.dunemask.net/id"], + cairoId, + ); + +export async function getUserDeployments(cairoId) { + const authFIlter = cairoMatch(cairoId); + const allDeployments = await getDeployments(); + const authChecks = allDeployments.map(authFIlter); + const authorizations = await Promise.all(authChecks); + return allDeployments.filter((_d, i) => authorizations[i]); +} + export async function getDeployments() { const deploymentRes = await k8sDeps.listNamespacedDeployment(namespace); const serverDeployments = deploymentRes.body.items.filter(mineclusterManaged); diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 421a244..3d4618a 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -11,8 +11,7 @@ import { getBackupContainer, } from "./server-containers.js"; -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); +import kc from "./k8s-config.js"; const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const k8sCore = kc.makeApiClient(k8s.CoreV1Api); const namespace = process.env.MCL_SERVER_NAMESPACE; diff --git a/lib/k8s/server-delete.js b/lib/k8s/server-delete.js index 4ced830..c0364a8 100644 --- a/lib/k8s/server-delete.js +++ b/lib/k8s/server-delete.js @@ -2,8 +2,7 @@ import k8s from "@kubernetes/client-node"; import { ERR } from "../util/logging.js"; import { getServerAssets } from "./k8s-server-control.js"; import ExpressClientError from "../util/ExpressClientError.js"; -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); +import kc from "./k8s-config.js"; const k8sDeps = kc.makeApiClient(k8s.AppsV1Api); const k8sCore = kc.makeApiClient(k8s.CoreV1Api); diff --git a/lib/k8s/server-status.js b/lib/k8s/server-status.js index 43f00af..0c421c1 100644 --- a/lib/k8s/server-status.js +++ b/lib/k8s/server-status.js @@ -1,8 +1,7 @@ import k8s from "@kubernetes/client-node"; -import { getDeployments } from "./k8s-server-control.js"; +import { getUserDeployments } from "./k8s-server-control.js"; import { getServerEntries } from "../database/queries/server-queries.js"; -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); +import kc from "./k8s-config.js"; const k8sMetrics = new k8s.Metrics(kc); const namespace = process.env.MCL_SERVER_NAMESPACE; @@ -42,9 +41,9 @@ function getServerStatus(server) { return { serverAvailable, ftpAvailable, services, deploymentAvailable }; } -export async function getInstances() { +export async function getInstances(cairoId) { const [serverDeployments, podMetricsRes, entries] = await Promise.all([ - getDeployments(), + getUserDeployments(cairoId), k8sMetrics.getPodMetrics(namespace), getServerEntries(), ]); diff --git a/lib/routes/auth-route.js b/lib/routes/auth-route.js new file mode 100644 index 0000000..8409975 --- /dev/null +++ b/lib/routes/auth-route.js @@ -0,0 +1,16 @@ +import { Router } from "express"; +import cairoAuthMiddleware from "./middlewares/auth-middleware.js"; +const router = Router(); + +const ok = (_r, res) => res.sendStatus(200); + +function cairoRedirect(req, res) { + res.redirect( + `${process.env.MCL_CAIRO_URL}/cairo/auth?redirectUri=${req.query.redirectUri}`, + ); +} + +router.get("/verify", cairoAuthMiddleware, ok); +router.get("/redirect", cairoRedirect); + +export default router; diff --git a/lib/routes/files-route.js b/lib/routes/files-route.js index c27c175..1092a81 100644 --- a/lib/routes/files-route.js +++ b/lib/routes/files-route.js @@ -8,8 +8,10 @@ import { getItem, } from "../controllers/file-controller.js"; +import cairoAuthMiddleware from "./middlewares/auth-middleware.js"; + const router = Router(); -router.use(jsonMiddleware()); +router.use([jsonMiddleware(), cairoAuthMiddleware]); const multerMiddleware = multer(); router.post("/list", listFiles); diff --git a/lib/routes/middlewares/auth-middleware.js b/lib/routes/middlewares/auth-middleware.js new file mode 100644 index 0000000..0a73234 --- /dev/null +++ b/lib/routes/middlewares/auth-middleware.js @@ -0,0 +1,33 @@ +// Imports +import { Router } from "express"; +import bearerTokenMiddleware from "express-bearer-token"; +import { ERR, VERB } from "../../util/logging.js"; + +// Constants +const { MCL_CAIRO_URL } = process.env; +const cairoAuthMiddleware = Router(); + +const cairoAuthenticate = async (token) => { + const config = { headers: { Authorization: `Bearer ${token}` } }; + return fetch(`${MCL_CAIRO_URL}/api/user/info`, config).then((res) => + res.json(), + ); +}; + +// Middleware +const cairoAuthHandler = (req, res, next) => { + if (!req.token) return res.status(401).send("Cairo auth required!"); + VERB("AUTH", `${MCL_CAIRO_URL}/api/user/info`); + cairoAuthenticate(req.token) + .then((authData) => (req.cairoId = authData.id)) + .then(() => next()) + .catch((err) => { + ERR("AUTH", err.response ? err.response.data : err.message); + if (!err.response) return res.status(500).send(`Auth failure ${err}`); + return res.status(err.response.status).send(err.response.data); + }); +}; + +cairoAuthMiddleware.use([bearerTokenMiddleware(), cairoAuthHandler]); + +export default cairoAuthMiddleware; diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js index d6eb922..d8ae832 100644 --- a/lib/routes/server-route.js +++ b/lib/routes/server-route.js @@ -11,8 +11,11 @@ import { serverInstances, serverList, } from "../controllers/status-controller.js"; + +import cairoAuthMiddleware from "./middlewares/auth-middleware.js"; + const router = Router(); -router.use(jsonMiddleware()); +router.use([jsonMiddleware(), cairoAuthMiddleware]); // Routes router.post("/create", createServer); router.delete("/delete", deleteServer); diff --git a/lib/routes/system-route.js b/lib/routes/system-route.js index 66e1022..ef913ed 100644 --- a/lib/routes/system-route.js +++ b/lib/routes/system-route.js @@ -1,9 +1,12 @@ import { Router } from "express"; import k8s from "@kubernetes/client-node"; import { WARN } from "../util/logging.js"; +import kc from "../k8s/k8s-config.js"; const router = Router(); -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); + +import cairoAuthMiddleware from "./middlewares/auth-middleware.js"; +router.use(cairoAuthMiddleware); + const k8sApi = kc.makeApiClient(k8s.CoreV1Api); // Get Routes router.get("/available", (req, res) => { diff --git a/lib/server/router.js b/lib/server/router.js index ccedebb..b4eb444 100644 --- a/lib/server/router.js +++ b/lib/server/router.js @@ -3,6 +3,7 @@ import express from "express"; // Routes import vitals from "../routes/vitals-route.js"; +import authRoute from "../routes/auth-route.js"; import systemRoute from "../routes/system-route.js"; import serverRoute from "../routes/server-route.js"; import filesRoute from "../routes/files-route.js"; @@ -22,6 +23,7 @@ export default function buildRoutes(pg, skio) { // Middlewares // Routes + router.use("/api/auth", authRoute); router.use("/api/system", systemRoute); router.use("/api/server", serverRoute); router.use("/api/files", filesRoute); diff --git a/package-lock.json b/package-lock.json index a773352..f506448 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", + "express-bearer-token": "^2.4.0", "figlet": "^1.7.0", "js-yaml": "^4.1.0", "moment": "^2.29.4", @@ -4603,6 +4604,26 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "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", @@ -5073,6 +5094,26 @@ "node": ">= 0.10.0" } }, + "node_modules/express-bearer-token": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/express-bearer-token/-/express-bearer-token-2.4.0.tgz", + "integrity": "sha512-2+kRZT2xo+pmmvSY7Ma5FzxTJpO3kGaPCEXPbAm3GaoZ/z6FE4K6L7cvs1AUZwY2xkk15PcQw7t4dWjsl5rdJw==", + "dependencies": { + "cookie": "^0.3.1", + "cookie-parser": "^1.4.4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/express-bearer-token/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/package.json b/package.json index af82f14..353c74d 100644 --- a/package.json +++ b/package.json @@ -22,41 +22,42 @@ "author": "Dunemask", "license": "LGPL-2.1", "devDependencies": { - "@emotion/react": "^11.11.1", + "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.19", - "@mui/material": "^5.14.20", - "@tanstack/react-query": "^5.12.2", + "@mui/icons-material": "^5.15.7", + "@mui/material": "^5.15.7", + "@tanstack/react-query": "^5.18.1", "@vitejs/plugin-react": "^4.2.1", "chonky": "^2.3.2", "chonky-icon-fontawesome": "^2.3.2", "concurrently": "^8.2.2", - "nodemon": "^3.0.2", - "prettier": "^3.1.0", + "nodemon": "^3.0.3", + "prettier": "^3.2.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-quill": "^2.0.0", - "react-router-dom": "^6.20.1", - "react-toastify": "^9.1.3", - "socket.io-client": "^4.7.2", - "vite": "^5.0.7" + "react-router-dom": "^6.22.0", + "react-toastify": "^10.0.4", + "socket.io-client": "^4.7.4", + "vite": "^5.0.12" }, "dependencies": { "@kubernetes/client-node": "^0.20.0", - "aws-sdk": "^2.1514.0", + "aws-sdk": "^2.1550.0", "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", "express": "^4.18.2", + "express-bearer-token": "^2.4.0", "figlet": "^1.7.0", "js-yaml": "^4.1.0", - "moment": "^2.29.4", + "moment": "^2.30.1", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", "pg-promise": "^11.5.4", "postgres-migrations": "^5.3.0", "rcon-client": "^4.2.4", - "socket.io": "^4.7.2", + "socket.io": "^4.7.4", "uuid": "^9.0.1" } } diff --git a/src/components/files/FilePreview.jsx b/src/components/files/FilePreview.jsx index 8a7d27c..0241cf5 100644 --- a/src/components/files/FilePreview.jsx +++ b/src/components/files/FilePreview.jsx @@ -7,8 +7,8 @@ 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 TextEditor from "./TextEditor.jsx"; +import { cairoAuthHeader } from "@mcl/util/auth.js"; const textFileTypes = ["properties", "txt", "yaml", "yml", "json", "env"]; const imageFileTypes = ["png", "jpeg", "jpg"]; @@ -52,6 +52,7 @@ export default function FilePreview(props) { await fetch("/api/files/upload", { method: "POST", body: formData, + headers: cairoAuthHeader(), }); dialogToggle(); } diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx index 3dbc6d4..e41652e 100644 --- a/src/components/files/MineclusterFiles.jsx +++ b/src/components/files/MineclusterFiles.jsx @@ -18,6 +18,7 @@ import { getServerItem, } from "@mcl/queries"; import { previewServerItem } from "../../util/queries"; +import { cairoAuthHeader } from "@mcl/util/auth.js"; import { supportedFileTypes } from "./FilePreview.jsx"; @@ -109,6 +110,7 @@ export default function MineclusterFiles(props) { await fetch("/api/files/upload", { method: "POST", body: formData, + headers: cairoAuthHeader(), }); } diff --git a/src/components/servers/RconSocket.js b/src/components/servers/RconSocket.js index f18c0ef..330b85d 100644 --- a/src/components/servers/RconSocket.js +++ b/src/components/servers/RconSocket.js @@ -8,6 +8,7 @@ export default class RconSocket { this.sk.on("rcon-error", this.onRconError.bind(this)); this.sk.on("error", () => console.log("WHOOSPSIE I GUESS?")); this.rconLive = false; + this.rconError = false; } onPush(p) { @@ -22,6 +23,7 @@ export default class RconSocket { onRconError(v) { this.rconLive = false; + this.rconError = true; console.log("Server sent: ", v); } diff --git a/src/components/servers/RconView.jsx b/src/components/servers/RconView.jsx index d4c99fd..24f87ee 100644 --- a/src/components/servers/RconView.jsx +++ b/src/components/servers/RconView.jsx @@ -55,10 +55,12 @@ export default function RconView(props) { variant="outlined" value={cmd} onChange={updateCmd} - disabled={!(rcon && rcon.rconLive)} + disabled={!(rcon && rcon.rconLive && !rcon.rconError)} /> - {rcon && rcon.rconLive && } - {!(rcon && rcon.rconLive) && ( + {rcon && rcon.rconLive && !rcon.rconError && ( + + )} + {!(rcon && rcon.rconLive && !rcon.rconError) && ( )} diff --git a/src/ctx/SettingsContext.jsx b/src/ctx/SettingsContext.jsx index e323177..9d2ef57 100644 --- a/src/ctx/SettingsContext.jsx +++ b/src/ctx/SettingsContext.jsx @@ -10,6 +10,7 @@ const defaultSettings = { simplifiedControls: false, logAppDetails: true, defaultPage: "home", + cairoAuth: null, }; const settings = localSettings ? JSON.parse(localSettings) : defaultSettings; @@ -27,6 +28,7 @@ const settingsUpdater = (oldState, settingsUpdate) => { if (settingsUpdate[k] === undefined) continue; settingsToUpdate[k] = settingsUpdate[k]; } + console.log("SAVING", settingsToUpdate); localStorage.setItem("settings", JSON.stringify(settingsToUpdate)); }; diff --git a/src/nav/Viewport.jsx b/src/nav/Viewport.jsx index a6b7622..fabe10c 100644 --- a/src/nav/Viewport.jsx +++ b/src/nav/Viewport.jsx @@ -1,13 +1,14 @@ -import Box from "@mui/material/Box"; import Toolbar from "@mui/material/Toolbar"; import MCLPortal from "./MCLPortal.jsx"; -import Button from "@mui/material/Button"; -import SpeedDialIcon from "@mui/material/SpeedDialIcon"; // Import Navbar /*import Navbar from "./Navbar.jsx";*/ +import { useCairoAuth } from "@mcl/util/auth.js"; import MCLMenu from "./MCLMenu.jsx"; +import Auth from "@mcl/pages/Auth.jsx"; export default function Views() { + const auth = useCairoAuth(); + if (!auth) return ; return (
diff --git a/src/pages/Auth.jsx b/src/pages/Auth.jsx new file mode 100644 index 0000000..e7278fa --- /dev/null +++ b/src/pages/Auth.jsx @@ -0,0 +1,63 @@ +import { useState, useEffect } from "react"; +import { useSearchParams, useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Typography from "@mui/material/Typography"; + +export default function Auth() { + const [searchParams] = useSearchParams(); + const currentServer = searchParams.get("token"); + + const nav = useNavigate(); + + const cairoLogin = () => + (window.location.href = `/api/auth/redirect?redirectUri=${window.location.href}`); + + return ( + theme.palette.primary.main, + }} + > + + + + + + + + + ); +} diff --git a/src/util/auth.js b/src/util/auth.js new file mode 100644 index 0000000..fe3138b --- /dev/null +++ b/src/util/auth.js @@ -0,0 +1,40 @@ +import { useState, useContext, useEffect } from "react"; +import { useSearchParams, useNavigate } from "react-router-dom"; +import SettingsContext from "@mcl/settings"; + +const verifyAuth = (authToken) => + fetch("/api/auth/verify", { + headers: { Authorization: `Bearer ${authToken}` }, + }) + .then((res) => res.status === 200) + .catch(() => false); + +export function useCairoAuth() { + const { state: settings, updateSettings } = useContext(SettingsContext); + const [auth, setAuth] = useState(!!settings.cairoAuth); + const [searchParams] = useSearchParams(); + const nav = useNavigate(); + + useEffect(() => { + const webToken = searchParams.get("cairoAuthToken"); + if (!webToken) return; + verifyAuth(webToken).then(setAuth); + updateSettings({ cairoAuth: webToken }); + nav("/"); + }, [searchParams]); + + useEffect(() => { + verifyAuth(settings.cairoAuth).then(setAuth); + nav("/"); + }, [settings.cairoAuth]); + + return auth; +} + +export function getAuthTokenFromStorage() { + return JSON.parse(localStorage.getItem("settings")).cairoAuth; +} + +export function cairoAuthHeader() { + return { Authorization: `Bearer ${getAuthTokenFromStorage()}` }; +} diff --git a/src/util/queries.js b/src/util/queries.js index c80be01..14a7035 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -1,12 +1,17 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { cairoAuthHeader } from "@mcl/util/auth.js"; + const fetchApi = (subPath) => async () => - fetch(`/api${subPath}`).then((res) => res.json()); + fetch(`/api${subPath}`, { headers: cairoAuthHeader() }).then((res) => + res.json(), + ); const fetchApiCore = async (subPath, json, method = "POST", jsonify = false) => fetch(`/api${subPath}`, { method, headers: { "Content-Type": "application/json", + ...cairoAuthHeader(), }, body: JSON.stringify(json), }).then((res) => (jsonify ? res.json() : res)); @@ -16,6 +21,7 @@ const fetchApiPost = (subPath, json) => async () => method: "POST", headers: { "Content-Type": "application/json", + ...cairoAuthHeader(), }, body: JSON.stringify(json), }).then((res) => res.json()); @@ -117,6 +123,7 @@ const postJsonApi = (subPath, body, invalidate, method = "POST") => { method, headers: { "Content-Type": "application/json", + ...cairoAuthHeader(), }, body: JSON.stringify(body), }); From 40b3a42c7346683cd6ee838501b999af102ef8ac Mon Sep 17 00:00:00 2001 From: Dunemask Date: Sun, 4 Feb 2024 19:33:40 -0700 Subject: [PATCH 29/56] [HOTFIX] Postgres Password Fix --- lib/database/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/database/postgres.js b/lib/database/postgres.js index eb2a037..452b53c 100644 --- a/lib/database/postgres.js +++ b/lib/database/postgres.js @@ -11,7 +11,7 @@ const { MCL_POSTGRES_DATABASE: database, MCL_POSTGRES_ENABLED: pgEnabled, MCL_POSTGRES_HOST: host, - MCL_POSTGRES_PASSWORD: password, + MCL_POSTGRES_PASS: password, MCL_POSTGRES_PORT: port, MCL_POSTGRES_USER: user, } = process.env; From 1eaa7ff5a5dd3c2f495ea89b46e44df9dd6baf9a Mon Sep 17 00:00:00 2001 From: dunemask Date: Mon, 5 Feb 2024 03:16:53 +0000 Subject: [PATCH 30/56] [FIX] Enable Correct Production Hooks (#13) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/13 --- src/util/auth.js | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/util/auth.js b/src/util/auth.js index fe3138b..f25a6bb 100644 --- a/src/util/auth.js +++ b/src/util/auth.js @@ -1,6 +1,8 @@ -import { useState, useContext, useEffect } from "react"; -import { useSearchParams, useNavigate } from "react-router-dom"; -import SettingsContext from "@mcl/settings"; +import { useState, useEffect } from "react"; +import { useSearchParams } from "react-router-dom"; + +const tokenStorageName = "cairoAuthToken"; +const tokenQuery = "cairoAuthToken"; const verifyAuth = (authToken) => fetch("/api/auth/verify", { @@ -10,29 +12,34 @@ const verifyAuth = (authToken) => .catch(() => false); export function useCairoAuth() { - const { state: settings, updateSettings } = useContext(SettingsContext); - const [auth, setAuth] = useState(!!settings.cairoAuth); - const [searchParams] = useSearchParams(); - const nav = useNavigate(); + const [authToken, setAuthToken] = useState( + localStorage.getItem(tokenStorageName), + ); + const [auth, setAuth] = useState(false); + const [searchParams, setSearchParams] = useSearchParams(); useEffect(() => { - const webToken = searchParams.get("cairoAuthToken"); + if (!authToken) return; + verifyAuth(authToken).then((authorized) => { + if (!authorized) localStorage.removeItem(tokenStorageName); + setAuth(authorized); + }); + }, [authToken]); + + useEffect(() => { + const webToken = searchParams.get(tokenQuery); if (!webToken) return; - verifyAuth(webToken).then(setAuth); - updateSettings({ cairoAuth: webToken }); - nav("/"); + localStorage.setItem(tokenStorageName, webToken); + searchParams.delete(tokenQuery); + setAuthToken(webToken); + setSearchParams(searchParams); }, [searchParams]); - useEffect(() => { - verifyAuth(settings.cairoAuth).then(setAuth); - nav("/"); - }, [settings.cairoAuth]); - return auth; } export function getAuthTokenFromStorage() { - return JSON.parse(localStorage.getItem("settings")).cairoAuth; + return localStorage.getItem(tokenStorageName); } export function cairoAuthHeader() { From bee4e61c87966a3d47f7d0595a0aa527d3a98ad4 Mon Sep 17 00:00:00 2001 From: dunemask Date: Mon, 5 Feb 2024 04:11:50 +0000 Subject: [PATCH 31/56] [FEATURE] Minecluster Icons (#14) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/14 --- index.html | 9 + public/icons/android-chrome-192x192.png | Bin 0 -> 8839 bytes public/icons/android-chrome-512x512.png | Bin 0 -> 60570 bytes .../apple-touch-icon-120x120-precomposed.png | Bin 0 -> 4387 bytes public/icons/apple-touch-icon-120x120.png | Bin 0 -> 4060 bytes .../apple-touch-icon-152x152-precomposed.png | Bin 0 -> 6335 bytes public/icons/apple-touch-icon-152x152.png | Bin 0 -> 6229 bytes .../apple-touch-icon-180x180-precomposed.png | Bin 0 -> 8553 bytes public/icons/apple-touch-icon-180x180.png | Bin 0 -> 8150 bytes .../apple-touch-icon-60x60-precomposed.png | Bin 0 -> 1826 bytes public/icons/apple-touch-icon-60x60.png | Bin 0 -> 1646 bytes .../apple-touch-icon-76x76-precomposed.png | Bin 0 -> 2494 bytes public/icons/apple-touch-icon-76x76.png | Bin 0 -> 2210 bytes public/icons/apple-touch-icon-precomposed.png | Bin 0 -> 8553 bytes public/icons/apple-touch-icon.png | Bin 0 -> 8150 bytes public/icons/browserconfig.xml | 9 + public/icons/favicon-16x16.png | Bin 0 -> 444 bytes public/icons/favicon-32x32.png | Bin 0 -> 854 bytes public/icons/favicon.ico | Bin 0 -> 7406 bytes public/icons/mstile-150x150.png | Bin 0 -> 5158 bytes public/icons/safari-pinned-tab.svg | 252 ++++++++++++++++++ public/icons/site.webmanifest | 19 ++ 22 files changed, 289 insertions(+) create mode 100644 public/icons/android-chrome-192x192.png create mode 100644 public/icons/android-chrome-512x512.png create mode 100644 public/icons/apple-touch-icon-120x120-precomposed.png create mode 100644 public/icons/apple-touch-icon-120x120.png create mode 100644 public/icons/apple-touch-icon-152x152-precomposed.png create mode 100644 public/icons/apple-touch-icon-152x152.png create mode 100644 public/icons/apple-touch-icon-180x180-precomposed.png create mode 100644 public/icons/apple-touch-icon-180x180.png create mode 100644 public/icons/apple-touch-icon-60x60-precomposed.png create mode 100644 public/icons/apple-touch-icon-60x60.png create mode 100644 public/icons/apple-touch-icon-76x76-precomposed.png create mode 100644 public/icons/apple-touch-icon-76x76.png create mode 100644 public/icons/apple-touch-icon-precomposed.png create mode 100644 public/icons/apple-touch-icon.png create mode 100644 public/icons/browserconfig.xml create mode 100644 public/icons/favicon-16x16.png create mode 100644 public/icons/favicon-32x32.png create mode 100644 public/icons/favicon.ico create mode 100644 public/icons/mstile-150x150.png create mode 100644 public/icons/safari-pinned-tab.svg create mode 100644 public/icons/site.webmanifest diff --git a/index.html b/index.html index ce38114..4fadd4e 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,15 @@ + + + + + + + + + Minecluster diff --git a/public/icons/android-chrome-192x192.png b/public/icons/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..5f91c4adc8e9f1712ce88345ec7b5ff7b45d4fc0 GIT binary patch literal 8839 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 literal 0 HcmV?d00001 diff --git a/public/icons/android-chrome-512x512.png b/public/icons/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..ffad351cf341c8034b869473d58a366a9262410f GIT binary patch literal 60570 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%0AY_ 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 literal 0 HcmV?d00001 diff --git a/public/icons/apple-touch-icon-120x120-precomposed.png b/public/icons/apple-touch-icon-120x120-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..1fae26b22d04fe1f9948801a3b57af42a515a74f GIT binary patch literal 4387 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 O00000{{R3FC5Sl00004XF*Lt006O% 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 literal 0 HcmV?d00001 diff --git a/public/icons/apple-touch-icon-60x60-precomposed.png b/public/icons/apple-touch-icon-60x60-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..26178b4be0296a65400083b191a869ce635916d5 GIT binary patch literal 1826 zcmV+-2i^FIP)Px#mQYMoMNDaN9zIAscxg9oVJS~YHECWtb7dz>MI=K$ zE?ZJQeQh#hSub5wL4$EbiFPYgOD0J}95_Qqk9r|RO(afINtJypZeBEnXE=~+Xz+qN zoNyU1Jx-v8Oq+pIuZ=&ZcQ1QjWYeHVwt!K=iczSESh|#a?Xzv)rzTxeT*aAm=dLJc zS4hTfU*3OF(0E+Xltiv=jP$)>xGN)Uxv0`91QG!hpC6=f8d|NrOSt*UMyzD%E!8BO@Ox0Ws%%c3>;nr=3m z^?JQrE*A^WbA8`;oH;MY!57!_7K_DliA&a-&Gc(xnKdEugC%suOK{iq2wpObHP!fJ zGqAWlqf7>}m?v?gE!R&z*(J+DmB=s*cRT#UIMms?ajxm724=k3Ng%(M6p`pcUBWVI}z z&*!D8F3+2&haCA2dTI@(J&#!AsYmaB|K1rFI{2imQNY4#Sw?HZF9ZHTTmNH6=%sBh z{6Atpjp-il6V2@LK7S+j20b!O5hSY#Dx~)8%rk(i56DS zsx8minO2sai#i8GXHpZ<%nAz%nuiK_+ zUR{k2{xGycGugbz9UaX@xsb{H=(6Ex>r$_!0*-bbPRiG zOAF6e;o)=<6mfR1m&#XY@KELW+)?BO;nnT1BWdg~z4W|+z z-9ufb5$*NmBZ-@6<}+_qi%+z~tM} zu(;l7Sf$E$&U;}}xy!y)eu6*b>Qqy$L-LK3S*A00huft(!P&}j-Rrp{-}Dlr<&y(q3?CA(q`xWM73yhq4$u-T9u|^UG{1~FgsRw?6=RJ&UD=1|xtG>GK#ps8lL7 zaPSE~38p%$dD=1qB;~u5`5dy?;kTc#H-hiaGj(UW%9-KjE~wQ|eQxgJ@&TiPjqN)o z*O|gjIOM$F7z+CgXj$Fsf5H`JL0h0)DfVzvqLa|_B~6AdS7!{uTIS#wb~OCNn6B>? ziVgOa<^hJmZk1;|SI%vX8CaG#fmc6aJQI1&*7vq(2u_keSjbuTY8p7MTACDBncwqI z_?XhPA$RZQmE}3@LXN*_5NumwKBf8YHy9&3pzDESgjUU&8j2@CR zc=Vi>4x2OVZ)q9t96O;oqf3&t?a0v~_b`ni90`2eW?Z}{#4C+zSv!vBM%e5seV*{? z&w@W_QF~E!@KMXgBNzulJ%%`FhHc}0y_Opg8})4L$eB!!UWVt`KN{}6?u`14qU zMJAbz{aqh2!$umV8sP1QPkCfHiil-2wq4^|&us&H-%Llwx}5L$7q+0di#s|BTK#D? z2)%EnBU0LK>C0vlQR$5=zHGh0^+G>l4g4)I(ciS#fngc;LoG~C$=M*iS^|#rvcEMw zuz(|XI6Nz>0Q1sSj~#h2oaxuW{{ZR| z7GF+=Egt{?09SfcSaechcOY6Cgx@G{a;ABePT>%h=S&#LUDT#0SfONT5nC0O}VJbn-$q Ql>h($07*qoM6N<$f{#IH;{X5v literal 0 HcmV?d00001 diff --git a/public/icons/apple-touch-icon-60x60.png b/public/icons/apple-touch-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..c23ddf35aff0f8b5bbcb40c4e83800895c2268df GIT binary patch literal 1646 zcmV-!29f!RP)Px#bx=%HMK*0=KYng2R!%NmQ!{2;LWOfhjCeV6WgR<4 zJa}nIm3=K@Rv<%5Crw5gGCob7gd|N;QmTqSr*k7hJv*9jD{NeN>#{V3XE%>(P{E00 z)1hwQs717XTECY{$Z%%yfLzU&Fn?lJwUI4$UR>LKYV3xJ^Si}D=&Aq!1vE)SK~zY` zeV2)HvpNig9m1Lr0xr}hp<(a)KjJ--Y#?p_tC>!-@Ntf1StzRbkhmd&AUL0|VW?D+ zWQY?*mL*A|R2W{b=QFOrbwU({`Y8Uv5*S4howg)R{btFrppRjA$bS(h>n>|dE1zg)*)q!#(o!()yzjIaXIK(_64@Q?INJ8{ z4V=Y!;n}uqb=wmiG0TphL)&SNy4KzB+`R9!hhbW6ETQZ2($>@zcC_8Htc-iwORG&d ziop($eGbd=dUf@f88ePqre6z!)UkA;H)*wHI=)np#lB*#FGP(^p%^v2qtrd|Eod?> zIa3GW=^-fAiOa_^qC;f}=9PDZKc|DV+O`KUe+ap{*j$t-2w)-AyopK!%{O!aXGT$#}#!?CeT-!BFSbng1Tf0;-U zZ#stKXouY%Bh>^WV!Nz;zrN;qws_I6+C=pEXsYKh$zG$x0f#Qv4mQ>#nO=pl^{b~B zgGpw50r+#6s;yAeR+-iGcviJB5pG)PZduob|KPw@u~H|x@kFrCcc``_L2!$8QIoEa zGSmjCE-yPb_e+D^%}ChiWAckup$ZT1XRGaq%TxvRre4{yX;gE$H(~e&v-AevslHn5 zvHBavrviWdhA$pA28O1nY35pN>#<=Nm0tgb6G=9~U%IwtR!vopdZA?XNZO+3OWZWZ zm>VZ_(m)0-Z@TE0?u~qgbj50cHu%&%ACoYnHwM`>M(&Bhpn6h90 z0}q-TKr~Z%uA26zTd7cSKdSof@e9s27@e!*WzQPtVQvs~Ff^J1PDa<_ME?_}(>`?C z&XyWLi?fGaXsH)yG^3VV#qc+bzDceAiAo{Xq8XrFo@VYOwH}~4wC$k_zQGe6ciev9 zHe?%#xn>)xA88k~CZKFHIClF)Xve?YJ032^*V z8NO9so(V@E)7)mMS#OR(UV}W%_UE00Wzi~4b9x4lxLdk+3|X*c?qC@bLgnTV@(tMI zK66|%cihy9|Hl%oU<^^w+2DCdb}>DGDXp0n@pMc|@faWW4cMa_mume8_1 z`6VA=NGEx|;{nNY06nv83icI%&n%OE6rB70)u99A;3p54&*`c(~l?Vow#p`B7LV zgKgZ+aN^O!)NUpiJE|UD9@8tVQj= z7p^>qZKJ2m_@&?I+?87HNkkYQerp5-AL&z+7tFXyp*j_qwk$orvp1Ubk96*n{IS6< z_jnuZzmR0!{y5OUJzRL@6Cgx@G{a;A sBePT>%h=S&#LUDT#0SfONT5nC0O}VJbn-$ql>h($07*qoM6N<$f;i_DZ~y=R literal 0 HcmV?d00001 diff --git a/public/icons/apple-touch-icon-76x76-precomposed.png b/public/icons/apple-touch-icon-76x76-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..1e0a2f87f53d7d2f9efc093ecd5de4b339582a77 GIT binary patch literal 2494 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 IM6N<$g0TjJ{{R30 literal 0 HcmV?d00001 diff --git a/public/icons/apple-touch-icon-76x76.png b/public/icons/apple-touch-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..954eb27934ff2ddbe078ad0d7c583d51ffde1fca GIT binary patch literal 2210 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 literal 0 HcmV?d00001 diff --git a/public/icons/apple-touch-icon-precomposed.png b/public/icons/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..b3fc31af1515b4464262dad02e53ec0b28a7c97e GIT binary patch literal 8553 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 literal 0 HcmV?d00001 diff --git a/public/icons/browserconfig.xml b/public/icons/browserconfig.xml new file mode 100644 index 0000000..0502cdd --- /dev/null +++ b/public/icons/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #00aba9 + + + diff --git a/public/icons/favicon-16x16.png b/public/icons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..821bb9fab1c6d189d8c29ad22d71779e8c877f8c GIT binary patch literal 444 zcmV;t0YmPx#OHfQyML~seBS}vxR#8*1jWcIkJ$-CPr*=1PVj)6C zJ9TFrIzcU8R5XKUMvi)6&6z1qM_JT(O{RuazmH0pfIE|IMz(TO#fo0Sm~Y*s@*>k9 z00022NklwY~RLeHLB|Be#fvQW%`Rv7jqV)hLl9GsX z-rljMq(>|(S<@>=wV1?-)0q7aJNpSa>P>oU00012dQ@0+Qek%>aB^>EX>4U6ba`-P zAZc)PV*mhnoa6Eg2ys>@D9TUE%t_@^00ScnE@KN5BNI!L6ay0=M1VBIWCJ6!R3OXP m)X2ol#2my2%YaCrN-hBE7ZG&wLN%2D0000Px#Y*0*8MK)|;AVW+fO;RgaQ9E~N9Xm!ja%4Y#ZZT(C zE?-tAOhrweghGXKMT&N6+@@5ykv5EKM~`_LGd?R+Oi7h~BSJkqm~cR(b2EWuN3ee| zcVcAHpjgI}UfX|BtBX*~b$#fuNV;!j@PBOPoUxNqGXMYrB}qg(^E*sxm?cN+0V2^Kk7h#_Qz+ek|)@xeIy{TtN8i zbq2G)c5O^>>)i!$f*n>LLg}v^=d~{*h2Z-kWl*}~&@YB)jNyby%txZIB%lOP=DKAd zlD&ZdAQ}cnRT2Po1A#0e&hxcjI+_Q_iRc61?C_6h!WifN2l~w$T+`>d-!If}{lCDr z_Um$;UUgmY=e3|<_y!JGZvB3mU`#aUoBho31+*~+JiC7I9#8qb;Z9XNaLos>ZH=J_ ze(2W?FJW+@s%70;&DXpES%|ET#t(3DD9>b({RKK}Wl)y8 zB<2iBm;q4~LRM)o)4Nc5WQSrZnx@HE7edOKXFI(tWN5AtAg~0DU|AMYb3#RF6Cgx@G{a;ABePT>%h=S&#LUDT g#0SfONT5nC0O}VJbn-$ql>h($07*qoM6N<$g1DA>x&QzG literal 0 HcmV?d00001 diff --git a/public/icons/favicon.ico b/public/icons/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a19896dce3da7a6ce7d31812b23ae657831ddd6c GIT binary patch literal 7406 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 literal 0 HcmV?d00001 diff --git a/public/icons/safari-pinned-tab.svg b/public/icons/safari-pinned-tab.svg new file mode 100644 index 0000000..ad6d511 --- /dev/null +++ b/public/icons/safari-pinned-tab.svg @@ -0,0 +1,252 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + + + + + + + + + + diff --git a/public/icons/site.webmanifest b/public/icons/site.webmanifest new file mode 100644 index 0000000..c008ad1 --- /dev/null +++ b/public/icons/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Minecluster", + "short_name": "Minecluster", + "icons": [ + { + "src": "/icons/android-chrome-192x192.png?v=feb4-24-mineblock", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icons/android-chrome-512x512.png?v=feb4-24-mineblock", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#249c6b", + "background_color": "#249c6b", + "display": "standalone" +} From 1741356e5fb4d8269b7e20cbbf1ce79b8f7815f2 Mon Sep 17 00:00:00 2001 From: dunemask Date: Fri, 9 Feb 2024 16:37:45 +0000 Subject: [PATCH 32/56] [HOTIX] Get Backups working (#15) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/15 --- lib/k8s/server-create.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 3d4618a..004fd03 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -66,6 +66,8 @@ function createBackupSecret(serverSpec) { `secret_access_key = ${backupKey}`, `endpoint = ${backupHost}`, `acl = private`, + `no_check_bucket = true`, + `no_check_container = true` ].join("\n"); backupYaml.data["rclone.conf"] = Buffer.from(rcloneConfig).toString("base64"); return backupYaml; From 2fe79d0c576b6e3b96d67f60d811af68ed5c1f2b Mon Sep 17 00:00:00 2001 From: dunemask Date: Sat, 10 Feb 2024 04:55:12 +0000 Subject: [PATCH 33/56] [FEATURE] New Deploy Pattern (#16) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/16 --- .gitea/workflows/deploy-edge-proxy.yml | 23 +++++++++++++++++++ .../{deploy.edge.yml => deploy-edge.yml} | 10 ++++---- 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 .gitea/workflows/deploy-edge-proxy.yml rename .gitea/workflows/{deploy.edge.yml => deploy-edge.yml} (72%) diff --git a/.gitea/workflows/deploy-edge-proxy.yml b/.gitea/workflows/deploy-edge-proxy.yml new file mode 100644 index 0000000..3551003 --- /dev/null +++ b/.gitea/workflows/deploy-edge-proxy.yml @@ -0,0 +1,23 @@ +name: Deploy Edge Proxy +run-name: ${{ gitea.actor }} Deploy Edge Proxy +on: + push: + branches: [ master ] + +env: + GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} + KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_EDGE }} + GARDEN_DEPLOY_ACTION: minecluster-proxy + + +jobs: + deploy-edge: + steps: + - name: Oasis Setup + uses: https://gitea.dunemask.dev/elysium/oasis-action@master + with: + gitea-token: ${{ env.GITEA_TOKEN }} + kubeconfig: ${{ env.KUBECONFIG_BASE64 }} + - name: Deploy to Edge env + run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge + working-directory: ${{ env.OASIS_WORKSPACE }} \ No newline at end of file diff --git a/.gitea/workflows/deploy.edge.yml b/.gitea/workflows/deploy-edge.yml similarity index 72% rename from .gitea/workflows/deploy.edge.yml rename to .gitea/workflows/deploy-edge.yml index bae115f..fc9ed65 100644 --- a/.gitea/workflows/deploy.edge.yml +++ b/.gitea/workflows/deploy-edge.yml @@ -1,13 +1,12 @@ -name: Deploy Edge -run-name: ${{ gitea.actor }} Deploy Edge +name: Deploy USW-MC +run-name: ${{ gitea.actor }} Deploy USW-MC on: push: branches: [ master ] env: GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} - KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_EDGE }} - OASIS_PROD_CONFIG: ${{ secrets.OASIS_PROD_CONFIG }} + KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_MC }} GARDEN_DEPLOY_ACTION: minecluster # Additional Deploy Envars POSTGRES_PROD_PASSWORD: ${{ secrets.POSTGRES_PROD_PASSWORD }} @@ -22,7 +21,6 @@ jobs: with: gitea-token: ${{ env.GITEA_TOKEN }} kubeconfig: ${{ env.KUBECONFIG_BASE64 }} - oasis-prod-config: ${{ env. OASIS_PROD_CONFIG }} - name: Deploy to Edge env - run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge + run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-mc working-directory: ${{ env.OASIS_WORKSPACE }} \ No newline at end of file From 4959d6c1feb704246f55ddb3ad1db8341717b0b7 Mon Sep 17 00:00:00 2001 From: dunemask Date: Sat, 10 Feb 2024 07:22:48 +0000 Subject: [PATCH 34/56] [FEATURE} Change extra ports from ClusterIp to LoadBalancer (#17) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/17 --- lib/k8s/configs/extra-svc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/k8s/configs/extra-svc.yml b/lib/k8s/configs/extra-svc.yml index 447a169..dee717f 100644 --- a/lib/k8s/configs/extra-svc.yml +++ b/lib/k8s/configs/extra-svc.yml @@ -20,4 +20,4 @@ spec: selector: app: changeme-app sessionAffinity: None - type: ClusterIP + type: LoadBalancer From 0a0f9c84636feee576ddb4a72d959b8adfeac0b7 Mon Sep 17 00:00:00 2001 From: dunemask Date: Sun, 11 Feb 2024 03:57:01 +0000 Subject: [PATCH 35/56] [FEATURE] Several QOL Updates (#18) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/18 --- lib/controllers/file-controller.js | 16 + .../sub-controllers/console-controller.js | 10 +- lib/k8s/server-create.js | 2 +- lib/k8s/server-files.js | 14 +- lib/routes/files-route.js | 2 + lib/routes/middlewares/auth-middleware.js | 1 - lib/storage/s3-integration.js | 34 - package-lock.json | 954 +++++------------- package.json | 15 +- .../files/ChonkyStyledFileBrowser.jsx | 42 - src/components/files/FilePreview.jsx | 17 +- src/components/files/MineclusterFiles.jsx | 74 +- src/components/servers/RconDialog.jsx | 17 +- src/components/servers/RconView.jsx | 52 +- src/css/rcon.css | 3 +- src/util/queries.js | 7 + 16 files changed, 432 insertions(+), 828 deletions(-) delete mode 100644 lib/storage/s3-integration.js delete mode 100644 src/components/files/ChonkyStyledFileBrowser.jsx diff --git a/lib/controllers/file-controller.js b/lib/controllers/file-controller.js index 83e1ab5..e5e7075 100644 --- a/lib/controllers/file-controller.js +++ b/lib/controllers/file-controller.js @@ -4,6 +4,7 @@ import { listServerFiles, removeServerItem, uploadServerItem, + moveServerItems, } from "../k8s/server-files.js"; import { sendError } from "../util/ExpressClientError.js"; import { checkAuthorization } from "../database/queries/server-queries.js"; @@ -79,3 +80,18 @@ export async function getItem(req, res) { }) .catch(sendError(res)); } + +export async function moveItems(req, res) { + const serverSpec = req.body; + if (!serverSpec.id) return res.status(400).send("Server id missing!"); + if (!serverSpec.destination) + return res.status(400).send("Destination required!"); + if (!serverSpec.origin) return res.status(400).send("Origin required!"); + if (!serverSpec.files || !Array.isArray(serverSpec.files)) + return res.status(400).send("Files required!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) return res.sendStatus(403); + moveServerItems(serverSpec) + .then(() => res.sendStatus(200)) + .catch(sendError(res)); +} diff --git a/lib/controllers/sub-controllers/console-controller.js b/lib/controllers/sub-controllers/console-controller.js index 6713960..b272f03 100644 --- a/lib/controllers/sub-controllers/console-controller.js +++ b/lib/controllers/sub-controllers/console-controller.js @@ -26,9 +26,13 @@ export async function webConsoleLogs(socket) { const log = new k8s.Log(kc); const logStream = new stream.PassThrough(); - logStream.on("data", (chunk) => - socket.emit("push", Buffer.from(chunk).toString()), - ); + var logstreamBuffer = ""; + logStream.on("data", (chunk) => { + const bufferString = Buffer.from(chunk).toString(); + if (!bufferString.includes("\n")) return (logstreamBuffer += bufferString); + const clientChunks = `${logstreamBuffer}${bufferString}`.split("\n"); + for (var c of clientChunks) socket.emit("push", c); + }); log .log(namespace, mcsPods[0], containerName, logStream, { follow: true, diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 004fd03..30e21fa 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -67,7 +67,7 @@ function createBackupSecret(serverSpec) { `endpoint = ${backupHost}`, `acl = private`, `no_check_bucket = true`, - `no_check_container = true` + `no_check_container = true`, ].join("\n"); backupYaml.data["rclone.conf"] = Buffer.from(rcloneConfig).toString("base64"); return backupYaml; diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js index ce29a02..efa32d8 100644 --- a/lib/k8s/server-files.js +++ b/lib/k8s/server-files.js @@ -86,12 +86,22 @@ export async function uploadServerItem(serverSpec, file) { }).catch(handleError); } -export async function getServerItem(serverSpec, writableStream) { +export async function getServerItem(serverSpec) { const { path } = serverSpec; - const ds = new Transform({ transform: (c, e, cb) => cb(null, c) }); + const ds = new Transform({ transform: (c, _e, cb) => cb(null, c) }); pathSecurityCheck(path); const ftpTransfer = useServerFtp(serverSpec, async (c) => { await c.downloadTo(ds, path); }).catch(handleError); return { ds, ftpTransfer }; } + +export async function moveServerItems(serverSpec) { + const { destination, origin, files } = serverSpec; + useServerFtp(serverSpec, async (c) => + Promise.all( + files.map((f) => c.rename(`${origin}/${f}`, `${destination}/${f}`)), + ), + ).catch(handleError); + return files; +} diff --git a/lib/routes/files-route.js b/lib/routes/files-route.js index 1092a81..d82f780 100644 --- a/lib/routes/files-route.js +++ b/lib/routes/files-route.js @@ -6,6 +6,7 @@ import { listFiles, uploadItem, getItem, + moveItems, } from "../controllers/file-controller.js"; import cairoAuthMiddleware from "./middlewares/auth-middleware.js"; @@ -18,6 +19,7 @@ router.post("/list", listFiles); router.post("/folder", createFolder); router.delete("/item", deleteItem); router.post("/item", getItem); +router.post("/move", moveItems); router.post("/upload", multerMiddleware.single("file"), uploadItem); export default router; diff --git a/lib/routes/middlewares/auth-middleware.js b/lib/routes/middlewares/auth-middleware.js index 0a73234..8f4318f 100644 --- a/lib/routes/middlewares/auth-middleware.js +++ b/lib/routes/middlewares/auth-middleware.js @@ -17,7 +17,6 @@ const cairoAuthenticate = async (token) => { // Middleware const cairoAuthHandler = (req, res, next) => { if (!req.token) return res.status(401).send("Cairo auth required!"); - VERB("AUTH", `${MCL_CAIRO_URL}/api/user/info`); cairoAuthenticate(req.token) .then((authData) => (req.cairoId = authData.id)) .then(() => next()) diff --git a/lib/storage/s3-integration.js b/lib/storage/s3-integration.js deleted file mode 100644 index 34ed5d5..0000000 --- a/lib/storage/s3-integration.js +++ /dev/null @@ -1,34 +0,0 @@ -import multer from "multer"; -import multerS3 from "multer-s3"; -import AWS from "aws-sdk"; - -// Environment Variables -const { - MCL_S3_ENDPOINT: s3Endpoint, - MCL_S3_ACCESS_KEY_ID: s3KeyId, - MCL_S3_ACCESS_KEY: s3Key, -} = process.env; - -export const mcl = "mcl"; - -export const s3 = new AWS.S3({ - endpoint: s3Endpoint, - accessKeyId: s3KeyId, - secretAccessKey: s3Key, - sslEnabled: true, - s3ForcePathStyle: true, -}); - -const storage = multerS3({ - s3, - bucket, - contentType: multerS3.AUTO_CONTENT_TYPE, - metadata: (req, file, cb) => { - cb(null, { fieldName: file.fieldname }); - }, - key: (req, file, cb) => { - cb(null, Date.now().toString()); - }, -}); - -export const upload = multer({ storage }); diff --git a/package-lock.json b/package-lock.json index f506448..af76135 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "minecluster", - "version": "0.0.1-alpha.0", + "version": "0.0.1-alpha.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minecluster", - "version": "0.0.1-alpha.0", + "version": "0.0.1-alpha.1", "license": "LGPL-2.1", "dependencies": { "@kubernetes/client-node": "^0.20.0", - "aws-sdk": "^2.1514.0", + "aws-sdk": "^2.1555.0", "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", @@ -18,34 +18,35 @@ "express-bearer-token": "^2.4.0", "figlet": "^1.7.0", "js-yaml": "^4.1.0", - "moment": "^2.29.4", + "moment": "^2.30.1", "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", "pg-promise": "^11.5.4", "postgres-migrations": "^5.3.0", "rcon-client": "^4.2.4", - "socket.io": "^4.7.2", + "react-dropzone": "^14.2.3", + "socket.io": "^4.7.4", "uuid": "^9.0.1" }, "devDependencies": { - "@emotion/react": "^11.11.1", + "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.19", - "@mui/material": "^5.14.20", - "@tanstack/react-query": "^5.12.2", + "@mui/icons-material": "^5.15.9", + "@mui/material": "^5.15.9", + "@tanstack/react-query": "^5.20.1", "@vitejs/plugin-react": "^4.2.1", "chonky": "^2.3.2", "chonky-icon-fontawesome": "^2.3.2", "concurrently": "^8.2.2", - "nodemon": "^3.0.2", - "prettier": "^3.1.0", + "nodemon": "^3.0.3", + "prettier": "^3.2.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-quill": "^2.0.0", - "react-router-dom": "^6.20.1", - "react-toastify": "^9.1.3", - "socket.io-client": "^4.7.2", - "vite": "^5.0.7" + "react-router-dom": "^6.22.0", + "react-toastify": "^10.0.4", + "socket.io-client": "^4.7.4", + "vite": "^5.1.1" } }, "node_modules/@ampproject/remapping": { @@ -1293,10 +1294,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", - "dev": true, + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1407,15 +1407,15 @@ "dev": true }, "node_modules/@emotion/react": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", - "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", + "version": "11.11.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", + "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", "dev": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.2", + "@emotion/serialize": "^1.1.3", "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", "@emotion/utils": "^1.2.1", "@emotion/weak-memoize": "^0.3.1", @@ -1431,9 +1431,9 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", - "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", + "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", "dev": true, "dependencies": { "@emotion/hash": "^0.9.1", @@ -1505,246 +1505,6 @@ "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==", "dev": true }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz", - "integrity": "sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz", - "integrity": "sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.8.tgz", - "integrity": "sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz", - "integrity": "sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz", - "integrity": "sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz", - "integrity": "sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz", - "integrity": "sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz", - "integrity": "sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz", - "integrity": "sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz", - "integrity": "sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz", - "integrity": "sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz", - "integrity": "sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz", - "integrity": "sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz", - "integrity": "sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz", - "integrity": "sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.19.8", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz", @@ -1761,128 +1521,32 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz", - "integrity": "sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz", - "integrity": "sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz", - "integrity": "sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz", - "integrity": "sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz", - "integrity": "sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz", - "integrity": "sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@floating-ui/core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz", - "integrity": "sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", "dev": true, "dependencies": { - "@floating-ui/utils": "^0.1.3" + "@floating-ui/utils": "^0.2.1" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", + "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", "dev": true, "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.1" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", - "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", "dev": true, "dependencies": { - "@floating-ui/dom": "^1.5.1" + "@floating-ui/dom": "^1.6.1" }, "peerDependencies": { "react": ">=16.8.0", @@ -1890,9 +1554,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", - "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==", "dev": true }, "node_modules/@formatjs/ecma402-abstract": { @@ -2200,17 +1864,17 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.26", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", - "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", + "version": "5.0.0-beta.36", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.36.tgz", + "integrity": "sha512-6A8fYiXgjqTO6pgj31Hc8wm1M3rFYCxDRh09dBVk0L0W4cb2lnurRJa3cAyic6hHY+we1S58OdGYRbKmOsDpGQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4", - "@floating-ui/react-dom": "^2.0.4", - "@mui/types": "^7.2.10", - "@mui/utils": "^5.14.20", + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.9", "@popperjs/core": "^2.11.8", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { @@ -2232,9 +1896,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", - "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.9.tgz", + "integrity": "sha512-CSDpVevGaxsvMkiYBZ8ztki1z/eT0mM2MqUT21eCRiMz3DU4zQw5rXG5ML/yTuJF9Z2Wv9SliIeaRAuSR/9Nig==", "dev": true, "funding": { "type": "opencollective", @@ -2242,12 +1906,12 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.14.19", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.19.tgz", - "integrity": "sha512-yjP8nluXxZGe3Y7pS+yxBV+hWZSsSBampCxkZwaw+1l+feL+rfP74vbEFbMrX/Kil9I/Y1tWfy5bs/eNvwNpWw==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.9.tgz", + "integrity": "sha512-6tLQoM6RylQuDnHR6qQay0G0pJgKmrhn5MIm0IfrwtmSO8eV5iUFR+nNUTXsWa24gt7ZbIKnJ962UlYaeXa4bg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4" + "@babel/runtime": "^7.23.9" }, "engines": { "node": ">=12.0.0" @@ -2268,20 +1932,20 @@ } }, "node_modules/@mui/material": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", - "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.9.tgz", + "integrity": "sha512-kbHTZDcFmN8GHKzRpImUEl9AJfFWI/0Kl+DsYVT3kHzQWUuHiKm3uHXR1RCOqr7H8IgHFPdbxItmCSQ/mj7zgg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4", - "@mui/base": "5.0.0-beta.26", - "@mui/core-downloads-tracker": "^5.14.20", - "@mui/system": "^5.14.20", - "@mui/types": "^7.2.10", - "@mui/utils": "^5.14.20", - "@types/react-transition-group": "^4.4.9", - "clsx": "^2.0.0", - "csstype": "^3.1.2", + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.36", + "@mui/core-downloads-tracker": "^5.15.9", + "@mui/system": "^5.15.9", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.9", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1", "react-is": "^18.2.0", "react-transition-group": "^4.4.5" @@ -2313,13 +1977,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", - "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.9.tgz", + "integrity": "sha512-/aMJlDOxOTAXyp4F2rIukW1O0anodAMCkv1DfBh/z9vaKHY3bd5fFf42wmP+0GRmwMinC5aWPpNfHXOED1fEtg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4", - "@mui/utils": "^5.14.20", + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.9", "prop-types": "^15.8.1" }, "engines": { @@ -2340,14 +2004,14 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", - "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.9.tgz", + "integrity": "sha512-NRKtYkL5PZDH7dEmaLEIiipd3mxNnQSO+Yo8rFNBNptY8wzQnQ+VjayTq39qH7Sast5cwHKYFusUrQyD+SS4Og==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4", + "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", - "csstype": "^3.1.2", + "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { @@ -2372,18 +2036,18 @@ } }, "node_modules/@mui/system": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", - "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.9.tgz", + "integrity": "sha512-SxkaaZ8jsnIJ77bBXttfG//LUf6nTfOcaOuIgItqfHv60ZCQy/Hu7moaob35kBb+guxVJnoSZ+7vQJrA/E7pKg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4", - "@mui/private-theming": "^5.14.20", - "@mui/styled-engine": "^5.14.19", - "@mui/types": "^7.2.10", - "@mui/utils": "^5.14.20", - "clsx": "^2.0.0", - "csstype": "^3.1.2", + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.9", + "@mui/styled-engine": "^5.15.9", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.9", + "clsx": "^2.1.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { @@ -2412,9 +2076,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.10", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", - "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", "dev": true, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" @@ -2426,12 +2090,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.20", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", - "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", + "version": "5.15.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.9.tgz", + "integrity": "sha512-yDYfr61bCYUz1QtwvpqYy/3687Z8/nS4zv7lv/ih/6ZFGMl1iolEvxRmR84v2lOYxlds+kq1IVYbXxDKh8Z9sg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.23.4", + "@babel/runtime": "^7.23.9", "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -2476,10 +2140,9 @@ "dev": true }, "node_modules/@react-dnd/shallowequal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==", - "dev": true + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" }, "node_modules/@reduxjs/toolkit": { "version": "1.9.7", @@ -2506,118 +2169,14 @@ } }, "node_modules/@remix-run/router": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz", - "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.0.tgz", + "integrity": "sha512-HOil5aFtme37dVQTB6M34G95kPM3MMuqSmIRVCC52eKV+Y/tGSqw9P3rWhlAx6A+mz+MoX+XxsGsNJbaI5qCgQ==", "dev": true, "engines": { "node": ">=14.0.0" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.7.0.tgz", - "integrity": "sha512-rGku10pL1StFlFvXX5pEv88KdGW6DHUghsxyP/aRYb9eH+74jTGJ3U0S/rtlsQ4yYq1Hcc7AMkoJOb1xu29Fxw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.7.0.tgz", - "integrity": "sha512-/EBw0cuJ/KVHiU2qyVYUhogXz7W2vXxBzeE9xtVIMC+RyitlY2vvaoysMUqASpkUtoNIHlnKTu/l7mXOPgnKOA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.7.0.tgz", - "integrity": "sha512-4VXG1bgvClJdbEYYjQ85RkOtwN8sqI3uCxH0HC5w9fKdqzRzgG39K7GAehATGS8jghA7zNoS5CjSKkDEqWmNZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.7.0.tgz", - "integrity": "sha512-/ImhO+T/RWJ96hUbxiCn2yWI0/MeQZV/aeukQQfhxiSXuZJfyqtdHPUPrc84jxCfXTxbJLmg4q+GBETeb61aNw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.7.0.tgz", - "integrity": "sha512-zhye8POvTyUXlKbfPBVqoHy3t43gIgffY+7qBFqFxNqVtltQLtWeHNAbrMnXiLIfYmxcoL/feuLDote2tx+Qbg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.7.0.tgz", - "integrity": "sha512-RAdr3OJnUum6Vs83cQmKjxdTg31zJnLLTkjhcFt0auxM6jw00GD6IPFF42uasYPr/wGC6TRm7FsQiJyk0qIEfg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.7.0.tgz", - "integrity": "sha512-nhWwYsiJwZGq7SyR3afS3EekEOsEAlrNMpPC4ZDKn5ooYSEjDLe9W/xGvoIV8/F/+HNIY6jY8lIdXjjxfxopXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.7.0.tgz", - "integrity": "sha512-rlfy5RnQG1aop1BL/gjdH42M2geMUyVQqd52GJVirqYc787A/XVvl3kQ5NG/43KXgOgE9HXgCaEH05kzQ+hLoA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.7.0.tgz", @@ -2644,45 +2203,6 @@ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.7.0.tgz", - "integrity": "sha512-CPtgaQL1aaPc80m8SCVEoxFGHxKYIt3zQYC3AccL/SqqiWXblo3pgToHuBwR8eCP2Toa+X1WmTR/QKFMykws7g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.7.0.tgz", - "integrity": "sha512-pmioUlttNh9GXF5x2CzNa7Z8kmRTyhEzzAC+2WOOapjewMbl+3tGuAnxbwc5JyG8Jsz2+hf/QD/n5VjimOZ63g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.7.0.tgz", - "integrity": "sha512-SeZzC2QhhdBQUm3U0c8+c/P6UlRyBcLL2Xp5KX7z46WXZxzR8RJSIWL9wSUeBTgxog5LTPJuPj0WOT9lvrtP7Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@smithy/abort-controller": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.11.tgz", @@ -3327,9 +2847,9 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@tanstack/query-core": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.12.1.tgz", - "integrity": "sha512-WbZztNmKq0t6QjdNmHzezbi/uifYo9j6e2GLJkodsYaYUlzMbAp91RDyeHkIZrm7EfO4wa6Sm5sxJZm5SPlh6w==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.20.1.tgz", + "integrity": "sha512-OONHHYG5vzjob4An+EfzbW7TRyb+sCA0AEgHzUIMlV9NYlF7wIwbla3PUfB3ocnaK1gZyROf0Lux/CBSu0exBQ==", "dev": true, "funding": { "type": "github", @@ -3337,12 +2857,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.12.2", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.12.2.tgz", - "integrity": "sha512-BeWZu8zVFH20oRc+S/K9ADPgWjEzP/XQCGBNz5IbApUwPQAdwkQYbXODVL5AyAlWiSxhx+P2xlARPBApj2Yrog==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.20.1.tgz", + "integrity": "sha512-KRkOtJ47tv9B3EXfjHkbPkiFzOzYCOid8BrYBozk0rm9JpDB2xSf71q8w1PRudlQW6QUQIEDI9E6NIMh6AlLUw==", "dev": true, "dependencies": { - "@tanstack/query-core": "5.12.1" + "@tanstack/query-core": "5.20.1" }, "funding": { "type": "github", @@ -3431,7 +2951,7 @@ "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -3463,7 +2983,7 @@ "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true + "devOptional": true }, "node_modules/@types/quill": { "version": "1.3.10", @@ -3478,7 +2998,7 @@ "version": "17.0.73", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.73.tgz", "integrity": "sha512-6AcjgPIVsXTIsFDgsGW0iQhvg0xb2vt2qAWgXyncnVNRaW9ZXTTwAh7RQoh7PzK1AhjPoGDvUBkdAREih9n5oQ==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3545,7 +3065,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "devOptional": true }, "node_modules/@types/shortid": { "version": "0.0.29", @@ -3725,6 +3245,14 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -3737,9 +3265,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1514.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1514.0.tgz", - "integrity": "sha512-ZQE5kHhJozwBB+Zaa21Gglm2pSQVU+8fFZNOn4pr+Kc1scYPlmVBPR3a0w19Vc4HNXPzjApAk2G4xMvzZDktAw==", + "version": "2.1555.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1555.0.tgz", + "integrity": "sha512-hjYs1MQkJxdHnoZm8hypqGy4PQKWVUs19McdXRXWNXr97V0il4xcUpIfvjHQ9x9EjP0p/jyIx9/BtyrR68jnUQ==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -3750,7 +3278,7 @@ "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", - "xml2js": "0.5.0" + "xml2js": "0.6.2" }, "engines": { "node": ">= 10.0.0" @@ -4311,6 +3839,12 @@ "react-dom": "^16.8.0 || ^17.0.0" } }, + "node_modules/chonky/node_modules/@react-dnd/shallowequal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==", + "dev": true + }, "node_modules/chonky/node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -4326,6 +3860,22 @@ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", "dev": true }, + "node_modules/chonky/node_modules/react-dnd": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", + "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", + "dev": true, + "dependencies": { + "@react-dnd/shallowequal": "^2.0.0", + "@types/hoist-non-react-statics": "^3.3.1", + "dnd-core": "^11.1.3", + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "react": ">= 16.9.0", + "react-dom": ">= 16.9.0" + } + }, "node_modules/chonky/node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -4396,9 +3946,9 @@ } }, "node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "dev": true, "engines": { "node": ">=6" @@ -4704,10 +4254,10 @@ } }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true }, "node_modules/dashdash": { "version": "1.14.1", @@ -5195,6 +4745,17 @@ "node": ">= 0.4.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/file-type": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", @@ -5337,20 +4898,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5594,7 +5141,6 @@ "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" } @@ -5602,8 +5148,7 @@ "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 + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/hotkeys-js": { "version": "3.13.2", @@ -5950,8 +5495,7 @@ "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 + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -6218,7 +5762,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -6373,9 +5916,9 @@ } }, "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "engines": { "node": "*" } @@ -6487,9 +6030,9 @@ "dev": true }, "node_modules/nodemon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", - "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", + "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -6922,9 +6465,9 @@ "dev": true }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -7006,9 +6549,9 @@ } }, "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -7029,7 +6572,6 @@ "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", @@ -7039,8 +6581,7 @@ "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 + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -7177,7 +6718,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -7192,19 +6732,32 @@ "dev": true }, "node_modules/react-dnd": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", - "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", - "dev": true, + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", "dependencies": { - "@react-dnd/shallowequal": "^2.0.0", - "@types/hoist-non-react-statics": "^3.3.1", - "dnd-core": "^11.1.3", - "hoist-non-react-statics": "^3.3.0" + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" }, "peerDependencies": { - "react": ">= 16.9.0", - "react-dom": ">= 16.9.0" + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } } }, "node_modules/react-dnd-html5-backend": { @@ -7216,6 +6769,26 @@ "dnd-core": "^11.1.3" } }, + "node_modules/react-dnd/node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/react-dnd/node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/react-dnd/node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -7229,6 +6802,22 @@ "react": "^18.2.0" } }, + "node_modules/react-dropzone": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", + "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-intl": { "version": "5.25.1", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-5.25.1.tgz", @@ -7355,12 +6944,12 @@ } }, "node_modules/react-router": { - "version": "6.20.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.20.1.tgz", - "integrity": "sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.0.tgz", + "integrity": "sha512-q2yemJeg6gw/YixRlRnVx6IRJWZD6fonnfZhN1JIOhV2iJCPeRNSH3V1ISwHf+JWcESzLC3BOLD1T07tmO5dmg==", "dev": true, "dependencies": { - "@remix-run/router": "1.13.1" + "@remix-run/router": "1.15.0" }, "engines": { "node": ">=14.0.0" @@ -7370,13 +6959,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.20.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.20.1.tgz", - "integrity": "sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.0.tgz", + "integrity": "sha512-z2w+M4tH5wlcLmH3BMMOMdrtrJ9T3oJJNsAlBJbwk+8Syxd5WFJ7J5dxMEW0/GEXD1BBis4uXRrNIz3mORr0ag==", "dev": true, "dependencies": { - "@remix-run/router": "1.13.1", - "react-router": "6.20.1" + "@remix-run/router": "1.15.0", + "react-router": "6.22.0" }, "engines": { "node": ">=14.0.0" @@ -7387,27 +6976,18 @@ } }, "node_modules/react-toastify": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", - "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.4.tgz", + "integrity": "sha512-etR3RgueY8pe88SA67wLm8rJmL1h+CLqUGHuAoNsseW35oTGJEri6eBTyaXnFKNQ80v/eO10hBYLgz036XRGgA==", "dev": true, "dependencies": { - "clsx": "^1.1.1" + "clsx": "^2.1.0" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, - "node_modules/react-toastify/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/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -7480,7 +7060,6 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dev": true, "dependencies": { "@babel/runtime": "^7.9.2" } @@ -7506,8 +7085,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", @@ -7933,9 +7511,9 @@ "dev": true }, "node_modules/socket.io": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", - "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz", + "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -7958,9 +7536,9 @@ } }, "node_modules/socket.io-client": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", - "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz", + "integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==", "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -8488,13 +8066,13 @@ } }, "node_modules/vite": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.7.tgz", - "integrity": "sha512-B4T4rJCDPihrQo2B+h1MbeGL/k/GMAHzhQ8S0LjQ142s6/+l3hHTT095ORvsshj4QCkoWu3Xtmob5mazvakaOw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.1.tgz", + "integrity": "sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==", "dev": true, "dependencies": { "esbuild": "^0.19.3", - "postcss": "^8.4.32", + "postcss": "^8.4.35", "rollup": "^4.2.0" }, "bin": { @@ -8625,9 +8203,9 @@ } }, "node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" diff --git a/package.json b/package.json index 353c74d..74ce608 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minecluster", - "version": "0.0.1-alpha.0", + "version": "0.0.1-alpha.1", "description": "Minecraft Server management using Kubernetes", "type": "module", "scripts": { @@ -8,7 +8,7 @@ "start": "node dist/app.js", "dev:server": "nodemon dist/app.js", "dev:react": "vite", - "kub": "nodemon lib/k8s.js", + "lint": "npx prettier -w src lib vite.config.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", "start:dev:garden": "concurrently -k \"npm run dev:server\" \"npm run dev:react\" -n s,v -p -c green,yellow" }, @@ -24,9 +24,9 @@ "devDependencies": { "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.15.7", - "@mui/material": "^5.15.7", - "@tanstack/react-query": "^5.18.1", + "@mui/icons-material": "^5.15.9", + "@mui/material": "^5.15.9", + "@tanstack/react-query": "^5.20.1", "@vitejs/plugin-react": "^4.2.1", "chonky": "^2.3.2", "chonky-icon-fontawesome": "^2.3.2", @@ -39,11 +39,11 @@ "react-router-dom": "^6.22.0", "react-toastify": "^10.0.4", "socket.io-client": "^4.7.4", - "vite": "^5.0.12" + "vite": "^5.1.1" }, "dependencies": { "@kubernetes/client-node": "^0.20.0", - "aws-sdk": "^2.1550.0", + "aws-sdk": "^2.1555.0", "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", @@ -57,6 +57,7 @@ "pg-promise": "^11.5.4", "postgres-migrations": "^5.3.0", "rcon-client": "^4.2.4", + "react-dropzone": "^14.2.3", "socket.io": "^4.7.4", "uuid": "^9.0.1" } diff --git a/src/components/files/ChonkyStyledFileBrowser.jsx b/src/components/files/ChonkyStyledFileBrowser.jsx deleted file mode 100644 index 3273684..0000000 --- a/src/components/files/ChonkyStyledFileBrowser.jsx +++ /dev/null @@ -1,42 +0,0 @@ -// ChonkyFullFileBrowser.tsx -import { forwardRef, memo } from "react"; -import { - StylesProvider, - createGenerateClassName, -} from "@material-ui/core/styles"; - -import { - FileBrowser, - FileList, - FileContextMenu, - FileNavbar, - FileToolbar, - setChonkyDefaults, - FileBrowserHandle, - FileBrowserProps, -} from "chonky"; - -import { ChonkyIconFA } from "chonky-icon-fontawesome"; - -setChonkyDefaults({ iconComponent: ChonkyIconFA }); - -const muiJSSClassNameGenerator = createGenerateClassName({ - // Seed property is used to add a prefix classes generated by material ui. - seed: "chonky", -}); - -export default memo( - forwardRef((props, ref) => { - const { onScroll } = props; - return ( - - - - - - - - - ); - }), -); diff --git a/src/components/files/FilePreview.jsx b/src/components/files/FilePreview.jsx index 0241cf5..c6e1002 100644 --- a/src/components/files/FilePreview.jsx +++ b/src/components/files/FilePreview.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, memo } from "react"; +import { useState, useEffect } from "react"; import useMediaQuery from "@mui/material/useMediaQuery"; import { useTheme } from "@mui/material/styles"; import Button from "@mui/material/Button"; @@ -10,7 +10,17 @@ import Toolbar from "@mui/material/Toolbar"; import TextEditor from "./TextEditor.jsx"; import { cairoAuthHeader } from "@mcl/util/auth.js"; -const textFileTypes = ["properties", "txt", "yaml", "yml", "json", "env"]; +const textFileTypes = [ + "properties", + "txt", + "yaml", + "yml", + "json", + "env", + "toml", + "tml", + "text", +]; const imageFileTypes = ["png", "jpeg", "jpg"]; export const supportedFileTypes = [...textFileTypes, ...imageFileTypes]; @@ -44,6 +54,7 @@ export default function FilePreview(props) { } async function onSave() { + if (!isTextFile) return; const formData = new FormData(); const blob = new Blob([modifiedText], { type: "plain/text" }); formData.append("file", blob, name); @@ -77,7 +88,7 @@ export default function FilePreview(props) { {name} - + {isTextFile && } + )} {!(rcon && rcon.rconLive && !rcon.rconError) && ( diff --git a/src/css/rcon.css b/src/css/rcon.css index a6093ad..c4fb9e3 100644 --- a/src/css/rcon.css +++ b/src/css/rcon.css @@ -1,8 +1,7 @@ .rconLogsWrapper { overflow-y: scroll; - max-height: 20rem; + max-height: calc(100% - 6rem); word-wrap: break-word; - margin-bottom: 10px; } .rconActions { display: inline-flex; diff --git a/src/util/queries.js b/src/util/queries.js index 14a7035..f2d65b1 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -64,6 +64,13 @@ export const createServerFolder = async (serverId, path) => export const deleteServerItem = async (serverId, path, isDir) => fetchApiCore("/files/item", { id: serverId, path, isDir }, "DELETE"); +export const moveServerItems = async (serverId, files, destination, origin) => + fetchApiCore( + "/files/move", + { id: serverId, files, destination, origin }, + "POST", + ); + export async function previewServerItem(serverId, path) { const resp = await fetchApiCore("/files/item", { id: serverId, path }); if (resp.status !== 200) return console.log("AHHHH"); From fc60df27acf36080f82a1fb0b837e5cb138a59ae Mon Sep 17 00:00:00 2001 From: dunemask Date: Tue, 13 Feb 2024 05:09:18 +0000 Subject: [PATCH 36/56] [FEATURE] Live Modifications, Host Safety, Minor Tweaks (#19) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/19 --- dist/app.js | 2 +- lib/controllers/lifecycle-controller.js | 12 ++- lib/database/queries/server-queries.js | 76 ++++++++++++++----- lib/k8s/configs/server-svc.yml | 2 - lib/k8s/server-create.js | 6 +- lib/k8s/server-modify.js | 59 ++++++++++++++ .../server-options/ExtraPortsOption.jsx | 12 ++- src/components/server-options/HostOption.jsx | 10 ++- src/pages/EditCoreOptions.jsx | 6 +- 9 files changed, 154 insertions(+), 31 deletions(-) create mode 100644 lib/k8s/server-modify.js diff --git a/dist/app.js b/dist/app.js index 2f46e88..d87897e 100644 --- a/dist/app.js +++ b/dist/app.js @@ -8,4 +8,4 @@ const kc = new k8s.KubeConfig(); kc.loadFromDefault(); } -main().catch((e)=>{console.log(e)}); +main().catch((e)=>{console.error(e)}); diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index d5b9e3a..1916157 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -9,6 +9,8 @@ import { import ExpressClientError, { sendError } from "../util/ExpressClientError.js"; import { toggleServer } from "../k8s/k8s-server-control.js"; import { checkAuthorization } from "../database/queries/server-queries.js"; +import { WARN } from "../util/logging.js"; +import modifyServerResources from "../k8s/server-modify.js"; const dnsRegex = new RegExp( `^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`, @@ -69,6 +71,9 @@ function payloadFilter(req, res) { return res .status(400) .send("Extra ports must be a list of strings with length of 5!"); + if (host !== host.toLowerCase()) + WARN("CREATE", "Host automatically being lowercasified..."); + req.body.host = host.toLowerCase(); return "filtered"; } @@ -158,10 +163,15 @@ export async function getServer(req, res) { export async function modifyServer(req, res) { if (payloadFilter(req, res) !== "filtered") return; const serverSpec = req.body; + if (!!serverSpec.host) + WARN( + "MODIFY", + "Warning, hostname changing is not implimented yet! Please ask the developer if you'd like to see this added!", + ); try { await checkServerId(req.cairoId, serverSpec); const serverEntry = await modifyServerEntry(serverSpec); - // await createServerResources(serverEntry); + await modifyServerResources(serverEntry); res.sendStatus(200); } catch (e) { sendError(res)(e); diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index 326572b..a08d05b 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -165,7 +165,7 @@ export async function modifyServerEntry(serverSpec) { id, // ownerCairoId: owner_cairo_id, // DIsabled! If these becomes a reqest, please create a new function! name, - host, + // host, // TODO: Can only be updated if service name is generic and non descriptive version, serverType: server_type, cpu, // TODO: Ignored for now by the K8S manifests @@ -180,28 +180,66 @@ export async function modifyServerEntry(serverSpec) { backupInterval: backup_interval, } = serverSpec; - const q = updateWhereAllQuery( - table, - { + const q = + updateWhereAllQuery( + table, + { + name, + // host, // TODO: Can only be updated if service name is generic and non descriptive + version, + server_type, + cpu, // TODO: Ignored for now by the K8S manifests + memory, + // storage, // DO NOT INCLUDE THIS KEY, Not all storage providers in kubernetes allow for dynamically resizable PVCs + extra_ports, + backup_enabled, + backup_host, + backup_bucket_path, + backup_id, + backup_key, + backup_interval, + }, + { id }, + ) + ` RETURNING *;`; + try { + const entries = await pg.query(q); + const { name, - host, + host, // Should always read the database value + server_type: serverType, + storage, + extra_ports: extraPorts, + backup_enabled: backupEnabled, + backup_host: backupHost, + backup_bucket_path: backupPath, + backup_id: backupId, + backup_key: backupKey, + backup_interval: backupInterval, + } = entries[0]; + + const mclName = getMclName(host, id); + + return { + name, // Could change + mclName, // Shouldn't change + id, // Won't change + // host, // TODO: Can only be updated if service name is generic and non descriptive version, - server_type, + serverType, cpu, // TODO: Ignored for now by the K8S manifests memory, - // storage, // DO NOT INCLUDE THIS KEY, Not all storage providers in kubernetes allow for dynamically resizable PVCs - extra_ports, - backup_enabled, - backup_host, - backup_bucket_path, - backup_id, - backup_key, - backup_interval, - }, - { id }, - ); - - return pg.query(q); + storage, + extraPorts, + backupEnabled, + backupHost, + backupPath, + backupId, + backupKey, + backupInterval, + }; + } catch (e) { + asExpressClientError(e); + } } export async function getServerEntries() { diff --git a/lib/k8s/configs/server-svc.yml b/lib/k8s/configs/server-svc.yml index f21db9a..a6f520e 100644 --- a/lib/k8s/configs/server-svc.yml +++ b/lib/k8s/configs/server-svc.yml @@ -11,8 +11,6 @@ metadata: namespace: changeme-namespace spec: internalTrafficPolicy: Cluster - ipFamilies: - - IPv4 ipFamilyPolicy: SingleStack ports: # Programatically add all FTP ports. Port range includes 20, 21, 40000-40001 - name: minecraft diff --git a/lib/k8s/server-create.js b/lib/k8s/server-create.js index 30e21fa..7d09e61 100644 --- a/lib/k8s/server-create.js +++ b/lib/k8s/server-create.js @@ -18,7 +18,7 @@ const namespace = process.env.MCL_SERVER_NAMESPACE; const loadYaml = (f) => yaml.load(fs.readFileSync(path.resolve(f), "utf8")); -function createExtraService(serverSpec) { +export function createExtraService(serverSpec) { const { mclName, id, extraPorts } = serverSpec; if (!extraPorts) return; const serviceYaml = loadYaml("lib/k8s/configs/extra-svc.yml"); @@ -49,7 +49,7 @@ function createExtraService(serverSpec) { return serviceYaml; } -function createBackupSecret(serverSpec) { +export function createBackupSecret(serverSpec) { if (!serverSpec.backupEnabled) return; // If backup not defined, don't create RCLONE secret const { mclName, id, backupId, backupKey, backupHost } = serverSpec; const backupYaml = loadYaml("lib/k8s/configs/backup-secret.yml"); @@ -153,7 +153,7 @@ function createServerDeploy(serverSpec) { return deployYaml; } -function createServerService(serverSpec) { +export function createServerService(serverSpec) { const { mclName, host, id } = serverSpec; const serviceYaml = loadYaml("lib/k8s/configs/server-svc.yml"); serviceYaml.metadata.annotations["ingress.qumine.io/hostname"] = host; diff --git a/lib/k8s/server-modify.js b/lib/k8s/server-modify.js new file mode 100644 index 0000000..74a1428 --- /dev/null +++ b/lib/k8s/server-modify.js @@ -0,0 +1,59 @@ +import k8s from "@kubernetes/client-node"; +import { + createExtraService, + createBackupSecret, + createServerService, +} from "./server-create.js"; +import kc from "./k8s-config.js"; +import { getServerAssets } from "./k8s-server-control.js"; +const k8sCore = kc.makeApiClient(k8s.CoreV1Api); +const namespace = process.env.MCL_SERVER_NAMESPACE; + +export default async function modifyServerResources(modifySpec) { + const { id: serverId } = modifySpec; + const serverAssets = await getServerAssets(serverId); + const serverService = createServerService(modifySpec); + const extraService = createExtraService(modifySpec); + const backupSecret = createBackupSecret(modifySpec); + const serverResources = []; + + if (!!serverService) + // Will Always Exist + serverResources.push( + k8sCore.replaceNamespacedService( + serverAssets.service.metadata.name, + namespace, + serverService, + ), + ); + + if (!!extraService && !!serverAssets.extraService) + // Might not exist + serverResources.push( + k8sCore.replaceNamespacedService( + serverAssets.extraService.metadata.name, + namespace, + extraService, + ), + ); + else if (!!extraService) + serverResources.push( + k8sCore.createNamespacedService(namespace, extraService), + ); + + if (!!backupSecret && !!serverAssets.backupSecret) + // Might not exist + serverResources.push( + k8sCore.replaceNamespacedSecret( + serverAssets.backupSecret.metadata.name, + namespace, + backupSecret, + ), + ); + else if (!!backupSecret) + serverResources.push( + k8sCore.createNamespacedSecret(namespace, backupSecret), + ); + + return await Promise.all(serverResources); +} diff --git a/src/components/server-options/ExtraPortsOption.jsx b/src/components/server-options/ExtraPortsOption.jsx index c97b40b..893a067 100644 --- a/src/components/server-options/ExtraPortsOption.jsx +++ b/src/components/server-options/ExtraPortsOption.jsx @@ -3,7 +3,8 @@ import TextField from "@mui/material/TextField"; import Autocomplete from "@mui/material/Autocomplete"; import Chip from "@mui/material/Chip"; -const validatePort = (p) => p !== "25565" && p !== "25575" && p.length < 6; +const validatePort = (p) => + p !== "25565" && p !== "25575" && p.length < 6 && parseInt(p) < 60_000; export default function ExtraPortsOption(props) { const { extraPorts: initExtraPorts } = props; @@ -30,7 +31,14 @@ export default function ExtraPortsOption(props) { value={extraPorts} onChange={portChange} freeSolo - renderInput={(p) => } + renderInput={(p) => ( + + )} renderTags={(value, getTagProps) => value.map((option, index) => { const defaultChipProps = getTagProps({ index }); diff --git a/src/components/server-options/HostOption.jsx b/src/components/server-options/HostOption.jsx index d03d1db..15d14e9 100644 --- a/src/components/server-options/HostOption.jsx +++ b/src/components/server-options/HostOption.jsx @@ -1,15 +1,21 @@ import TextField from "@mui/material/TextField"; export default function HostOption(props) { - const { value, onChange } = props; + const { value, onChange, disabled } = props; + + function onTextChange(e) { + e.target.value = e.target.value.toLowerCase(); + onChange(e); + } return ( ); } diff --git a/src/pages/EditCoreOptions.jsx b/src/pages/EditCoreOptions.jsx index a098cb6..bda2c34 100644 --- a/src/pages/EditCoreOptions.jsx +++ b/src/pages/EditCoreOptions.jsx @@ -73,7 +73,11 @@ export default function EditCoreOptions(props) { > - + Date: Tue, 13 Feb 2024 09:37:48 -0700 Subject: [PATCH 37/56] [HOTFIX] Host return from database --- lib/database/queries/server-queries.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index a08d05b..feafec2 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -223,7 +223,7 @@ export async function modifyServerEntry(serverSpec) { name, // Could change mclName, // Shouldn't change id, // Won't change - // host, // TODO: Can only be updated if service name is generic and non descriptive + host, // TODO: Can only be updated if service name is generic and non descriptive, this returns the host from the database version, serverType, cpu, // TODO: Ignored for now by the K8S manifests From ace95a20c66a0c696cae7a798d892b21ac33c4d4 Mon Sep 17 00:00:00 2001 From: dunemask Date: Tue, 20 Feb 2024 09:30:56 +0000 Subject: [PATCH 38/56] [FEATURE] Workflow Overhaul (#20) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/20 --- .gitea/workflows/deploy-edge-proxy.yml | 38 ++++++++++++++++++-------- .gitea/workflows/deploy-edge.yml | 35 ++++++++++++++---------- .gitea/workflows/qa-api-tests.yml | 24 ++++++++++------ 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/.gitea/workflows/deploy-edge-proxy.yml b/.gitea/workflows/deploy-edge-proxy.yml index 3551003..e4dc61d 100644 --- a/.gitea/workflows/deploy-edge-proxy.yml +++ b/.gitea/workflows/deploy-edge-proxy.yml @@ -5,19 +5,35 @@ on: branches: [ master ] env: - GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} - KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_EDGE }} GARDEN_DEPLOY_ACTION: minecluster-proxy - jobs: deploy-edge: steps: - - name: Oasis Setup - uses: https://gitea.dunemask.dev/elysium/oasis-action@master - with: - gitea-token: ${{ env.GITEA_TOKEN }} - kubeconfig: ${{ env.KUBECONFIG_BASE64 }} - - name: Deploy to Edge env - run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge - working-directory: ${{ env.OASIS_WORKSPACE }} \ No newline at end of file + # Configure proper kubeconfig + - name: Get usw-mc deployment kubeconfig + uses: https://gitea.dunemask.dev/elysium/elysium-actions@infisical-env + with: + infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} + secret-envs: edge + secret-paths: /kubernetes + # Setup Oasis + - name: Oasis Setup + uses: https://gitea.dunemask.dev/elysium/elysium-actions@oasis-setup-auto + with: + deploy-env: edge + infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} + kubeconfig: ${{ env.KUBERNETES_CONFIG_USW_MC }} + # Deploy to Edge Cluster + - name: Deploy to Edge Cluster + run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge + working-directory: ${{ env.OASIS_WORKSPACE }} + # Alert via Discord + - name: Discord Alert + if: always() + uses: https://gitea.dunemask.dev/elysium/elysium-actions@discord-status + with: + status: ${{ job.status }} + channel: deployments + header: DEPLOY EDGE + additional-content: "Minecluster Proxy" \ No newline at end of file diff --git a/.gitea/workflows/deploy-edge.yml b/.gitea/workflows/deploy-edge.yml index fc9ed65..530be68 100644 --- a/.gitea/workflows/deploy-edge.yml +++ b/.gitea/workflows/deploy-edge.yml @@ -5,22 +5,29 @@ on: branches: [ master ] env: - GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} - KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_MC }} GARDEN_DEPLOY_ACTION: minecluster - # Additional Deploy Envars - POSTGRES_PROD_PASSWORD: ${{ secrets.POSTGRES_PROD_PASSWORD }} - MCL_KUBECONFIG: ${{ secrets.KUBECONFIG_USW_MC }} - jobs: deploy-edge: steps: - - name: Oasis Setup - uses: https://gitea.dunemask.dev/elysium/oasis-action@master - with: - gitea-token: ${{ env.GITEA_TOKEN }} - kubeconfig: ${{ env.KUBECONFIG_BASE64 }} - - name: Deploy to Edge env - run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-mc - working-directory: ${{ env.OASIS_WORKSPACE }} \ No newline at end of file + # Setup Oasis + - name: Oasis Setup + uses: https://gitea.dunemask.dev/elysium/elysium-actions@oasis-setup-auto + with: + deploy-env: edge + infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} + extra-secret-paths: /alexandria + extra-secret-envs: edge + # Deploy to Edge + - name: Deploy to Edge env + run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge + working-directory: ${{ env.OASIS_WORKSPACE }} + # Alert via Discord + - name: Discord Alert + if: always() + uses: https://gitea.dunemask.dev/elysium/elysium-actions@discord-status + with: + status: ${{ job.status }} + channel: deployments + header: DEPLOY MC + additional-content: "Minecluster Server Manager Deployment" \ No newline at end of file diff --git a/.gitea/workflows/qa-api-tests.yml b/.gitea/workflows/qa-api-tests.yml index 4014415..8222cdf 100644 --- a/.gitea/workflows/qa-api-tests.yml +++ b/.gitea/workflows/qa-api-tests.yml @@ -6,31 +6,37 @@ on: env: REPO_DIR: ${{ gitea.workspace }}/minecluster - KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_USW_DEV }} - GITEA_TOKEN: ${{ secrets.ELYSIUM_ORG_READ_TOKEN }} GARDEN_LINK_ACTION: build.minecluster-image jobs: qa-api-tests: steps: + # Setup Oasis - name: Oasis Setup - uses: https://gitea.dunemask.dev/elysium/oasis-action@master + uses: https://gitea.dunemask.dev/elysium/elysium-actions@oasis-setup-auto with: - gitea-token: ${{ env.GITEA_TOKEN }} - kubeconfig: ${{ env.KUBECONFIG_BASE64 }} + deploy-env: ci + infisical-token: ${{ secrets.INFISICAL_ELYSIUM_CI_READ_TOKEN }} # Test Code - name: Checkout repository uses: actions/checkout@v3 with: path: ${{ env.REPO_DIR }} - # Garden tests + # Garden link - name: Link Repo code to Garden run: garden link action $GARDEN_LINK_ACTION $REPO_DIR --env usw-ci --var cubit-projects=cairo,minecluster working-directory: ${{ env.OASIS_WORKSPACE }} # Cubit CI Tests - name: Run Cubit tests in CI env - run: garden workflow qa-api-tests --env usw-ci --var ci-ttl=25 + run: garden workflow qa-api-tests --env usw-ci --var ci-ttl=25m working-directory: ${{ env.OASIS_WORKSPACE }} - - name: Status Alert + # Discord Alert + - name: Discord Alert if: always() - run: echo "The Job ended with status ${{ job.status }}." \ No newline at end of file + uses: https://gitea.dunemask.dev/elysium/elysium-actions@discord-status + with: + status: ${{ job.status }} + channel: ci + header: QA API Tests + additional-content: "CI Namespace: `${{env.CI_NAMESPACE}}`" + \ No newline at end of file From c93c97b275bed21e96fdc04d6350878a5609142f Mon Sep 17 00:00:00 2001 From: Dunemask Date: Tue, 20 Feb 2024 02:35:16 -0700 Subject: [PATCH 39/56] [HOTFIX] Workflow Overhaul --- .gitea/workflows/deploy-edge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-edge.yml b/.gitea/workflows/deploy-edge.yml index 530be68..5ad9c1f 100644 --- a/.gitea/workflows/deploy-edge.yml +++ b/.gitea/workflows/deploy-edge.yml @@ -20,7 +20,7 @@ jobs: extra-secret-envs: edge # Deploy to Edge - name: Deploy to Edge env - run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge + run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-mc working-directory: ${{ env.OASIS_WORKSPACE }} # Alert via Discord - name: Discord Alert From e9bd043924ef8741c290bbef0d366fa009cd504d Mon Sep 17 00:00:00 2001 From: Dunemask Date: Tue, 20 Feb 2024 02:38:01 -0700 Subject: [PATCH 40/56] [HOTFIX] Workflow Overhaul --- .gitea/workflows/deploy-edge-proxy.yml | 8 -------- .gitea/workflows/deploy-edge.yml | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/deploy-edge-proxy.yml b/.gitea/workflows/deploy-edge-proxy.yml index e4dc61d..c961b21 100644 --- a/.gitea/workflows/deploy-edge-proxy.yml +++ b/.gitea/workflows/deploy-edge-proxy.yml @@ -10,20 +10,12 @@ env: jobs: deploy-edge: steps: - # Configure proper kubeconfig - - name: Get usw-mc deployment kubeconfig - uses: https://gitea.dunemask.dev/elysium/elysium-actions@infisical-env - with: - infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} - secret-envs: edge - secret-paths: /kubernetes # Setup Oasis - name: Oasis Setup uses: https://gitea.dunemask.dev/elysium/elysium-actions@oasis-setup-auto with: deploy-env: edge infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} - kubeconfig: ${{ env.KUBERNETES_CONFIG_USW_MC }} # Deploy to Edge Cluster - name: Deploy to Edge Cluster run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-edge diff --git a/.gitea/workflows/deploy-edge.yml b/.gitea/workflows/deploy-edge.yml index 5ad9c1f..a9386b4 100644 --- a/.gitea/workflows/deploy-edge.yml +++ b/.gitea/workflows/deploy-edge.yml @@ -10,6 +10,13 @@ env: jobs: deploy-edge: steps: + # Configure proper kubeconfig + - name: Get usw-mc deployment kubeconfig + uses: https://gitea.dunemask.dev/elysium/elysium-actions@infisical-env + with: + infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} + secret-envs: edge + secret-paths: /kubernetes # Setup Oasis - name: Oasis Setup uses: https://gitea.dunemask.dev/elysium/elysium-actions@oasis-setup-auto @@ -18,6 +25,7 @@ jobs: infisical-token: ${{ secrets.INFISICAL_ELYSIUM_EDGE_READ_TOKEN }} extra-secret-paths: /alexandria extra-secret-envs: edge + kubeconfig: ${{ env.KUBERNETES_CONFIG_USW_MC }} # Deploy to Edge - name: Deploy to Edge env run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-mc From b15f616adbfd361721b188db1eb0f41d2afae737 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Tue, 20 Feb 2024 02:44:52 -0700 Subject: [PATCH 41/56] [HOTFIX] Workflow Overhaul --- .gitea/workflows/deploy-edge.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitea/workflows/deploy-edge.yml b/.gitea/workflows/deploy-edge.yml index a9386b4..04be45d 100644 --- a/.gitea/workflows/deploy-edge.yml +++ b/.gitea/workflows/deploy-edge.yml @@ -30,6 +30,8 @@ jobs: - name: Deploy to Edge env run: garden deploy $GARDEN_DEPLOY_ACTION --force --force-build --env usw-mc working-directory: ${{ env.OASIS_WORKSPACE }} + env: + MCL_KUBECONFIG: ${{ secrets.KUBECONFIG_USW_MC }} # Alert via Discord - name: Discord Alert if: always() From 332f84972c7418d79c395c8fb04b51000f09d69d Mon Sep 17 00:00:00 2001 From: dunemask Date: Mon, 11 Mar 2024 19:32:11 +0000 Subject: [PATCH 42/56] [FEATURE] Allow folder uploads (#21) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/21 --- lib/k8s/server-files.js | 6 ++++-- src/components/files/MineclusterFiles.jsx | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/k8s/server-files.js b/lib/k8s/server-files.js index efa32d8..36dcd4a 100644 --- a/lib/k8s/server-files.js +++ b/lib/k8s/server-files.js @@ -2,7 +2,8 @@ import ftp from "basic-ftp"; import { ERR } from "../util/logging.js"; import { getServerAssets } from "./k8s-server-control.js"; import ExpressClientError from "../util/ExpressClientError.js"; -import { Readable, Writable, Transform } from "node:stream"; +import { Readable, Transform } from "node:stream"; +import { dirname, basename } from "node:path"; const namespace = process.env.MCL_SERVER_NAMESPACE; @@ -82,7 +83,8 @@ export async function uploadServerItem(serverSpec, file) { const { path } = serverSpec; pathSecurityCheck(path); await useServerFtp(serverSpec, async (c) => { - await c.uploadFrom(fileStream, path); + await c.ensureDir(dirname(path)); + await c.uploadFrom(fileStream, basename(path)); }).catch(handleError); } diff --git a/src/components/files/MineclusterFiles.jsx b/src/components/files/MineclusterFiles.jsx index 656af40..eb48283 100644 --- a/src/components/files/MineclusterFiles.jsx +++ b/src/components/files/MineclusterFiles.jsx @@ -111,10 +111,12 @@ export default function MineclusterFiles(props) { } async function uploadFile(file) { + const filePath = file.path.startsWith("/") ? file.path : `/${file.path}`; const formData = new FormData(); formData.append("file", file); formData.append("id", serverId); - formData.append("path", [...dirStack, file.name].join("/")); + const path = `${[...dirStack].join("/")}${filePath}`; + formData.append("path", path); await fetch("/api/files/upload", { method: "POST", body: formData, From 6efa50e86b7dd543de2edbc24a720fdde81b8b2d Mon Sep 17 00:00:00 2001 From: dunemask Date: Tue, 12 Mar 2024 01:58:25 +0000 Subject: [PATCH 43/56] [FEATURE] Backups View & Style fix (#22) Co-authored-by: Dunemask Reviewed-on: https://gitea.dunemask.dev/elysium/minecluster/pulls/22 --- lib/controllers/s3-controller.js | 84 ++ lib/routes/s3-route.js | 11 + lib/server/router.js | 2 + package-lock.json | 1674 ++++++++++------------ package.json | 3 +- src/components/servers/BackupsDialog.jsx | 88 ++ src/components/servers/RconView.jsx | 1 + src/components/servers/ServerCard.jsx | 11 +- src/pages/Home.jsx | 21 +- src/util/queries.js | 5 + 10 files changed, 969 insertions(+), 931 deletions(-) create mode 100644 lib/controllers/s3-controller.js create mode 100644 lib/routes/s3-route.js create mode 100644 src/components/servers/BackupsDialog.jsx diff --git a/lib/controllers/s3-controller.js b/lib/controllers/s3-controller.js new file mode 100644 index 0000000..43c6f7d --- /dev/null +++ b/lib/controllers/s3-controller.js @@ -0,0 +1,84 @@ +import { S3, GetObjectCommand } from "@aws-sdk/client-s3"; +import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; +import { basename } from "node:path"; +import { getServerEntry } from "../database/queries/server-queries.js"; +import { ERR } from "../util/logging.js"; +import { checkAuthorization } from "../database/queries/server-queries.js"; +const s3Region = "us-east-1"; + +async function getS3BackupData(serverId) { + const serverEntry = await getServerEntry(serverId); + if (!serverEntry?.backupHost) return undefined; + const s3Config = { + credentials: { + accessKeyId: serverEntry.backupId, + secretAccessKey: serverEntry.backupKey, + }, + endpoint: `https://${serverEntry.backupHost}`, + forcePathStyle: true, + region: s3Region, + }; + const pathParts = serverEntry.backupPath.split("/"); + if (pathParts[0] === "") pathParts.shift(); + const bucket = pathParts.shift(); + const backupPrefix = pathParts.join("/"); + return { s3Config, bucket, backupPrefix }; +} + +export async function listS3Backups(req, res) { + const serverSpec = req.body; + if (!serverSpec.id) return res.status(400).send("Server id missing!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) + return res + .status(403) + .send("You do not have permission to access that server!"); + const s3Data = await getS3BackupData(serverSpec.id); + if (!s3Data) return res.status(409).send("Backup not configured!"); + const { s3Config, bucket, backupPrefix } = s3Data; + const s3Client = new S3(s3Config); + try { + const listResponse = await s3Client.listObjectsV2({ + Bucket: bucket, + Prefix: backupPrefix, + }); + const files = + listResponse.Contents?.map((f) => ({ + name: basename(f.Key), + lastModified: f.LastModified, + path: f.Key, + size: f.Size, + })) ?? []; + res.json(files); + } catch (e) { + ERR("S3", e); + res.sendStatus(500); + } +} + +export async function getS3BackupUrl(req, res) { + const serverSpec = req.body; + if (!serverSpec.id) return res.status(400).send("Server id missing!"); + if (!serverSpec.backupPath) + return res.status(400).send("Backup path missing!"); + const authorized = await checkAuthorization(serverSpec.id, req.cairoId); + if (!authorized) + return res + .status(403) + .send("You do not have permission to access that server!"); + const s3Data = await getS3BackupData(serverSpec.id); + if (!s3Data) return res.status(409).send("Backup not configured!"); + const { s3Config, bucket } = s3Data; + const s3Client = new S3(s3Config); + try { + const command = new GetObjectCommand({ + Bucket: bucket, + Key: serverSpec.backupPath, + }); + const url = await getSignedUrl(s3Client, command, { expiresIn: 3600 }); + res.json({ url }); + } catch (e) { + ERR("S3", e); + res.sendStatus(500); + } +} diff --git a/lib/routes/s3-route.js b/lib/routes/s3-route.js new file mode 100644 index 0000000..c97afb0 --- /dev/null +++ b/lib/routes/s3-route.js @@ -0,0 +1,11 @@ +import { Router, json as jsonMiddleware } from "express"; +import { getS3BackupUrl, listS3Backups } from "../controllers/s3-controller.js"; +import cairoAuthMiddleware from "./middlewares/auth-middleware.js"; + +const router = Router(); +router.use([cairoAuthMiddleware, jsonMiddleware()]); + +router.post("/backups", listS3Backups); +router.post("/backup-url", getS3BackupUrl); + +export default router; diff --git a/lib/server/router.js b/lib/server/router.js index b4eb444..685dd1d 100644 --- a/lib/server/router.js +++ b/lib/server/router.js @@ -8,6 +8,7 @@ import systemRoute from "../routes/system-route.js"; import serverRoute from "../routes/server-route.js"; import filesRoute from "../routes/files-route.js"; import reactRoute from "../routes/react-route.js"; +import s3Route from "../routes/s3-route.js"; import { logErrors, clientErrorHandler, @@ -27,6 +28,7 @@ export default function buildRoutes(pg, skio) { router.use("/api/system", systemRoute); router.use("/api/server", serverRoute); router.use("/api/files", filesRoute); + router.use("/api/s3", s3Route); router.use(["/mcl", "/mcl/*"], reactRoute); // Static Build Route /*router.use(logErrors); router.use(clientErrorHandler); diff --git a/package-lock.json b/package-lock.json index af76135..cc9f68d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,9 @@ "version": "0.0.1-alpha.1", "license": "LGPL-2.1", "dependencies": { + "@aws-sdk/client-s3": "^3.529.1", + "@aws-sdk/s3-request-presigner": "^3.529.1", "@kubernetes/client-node": "^0.20.0", - "aws-sdk": "^2.1555.0", "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", @@ -66,7 +67,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", - "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -76,14 +76,12 @@ "node_modules/@aws-crypto/crc32/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/crc32c": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", - "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -93,14 +91,12 @@ "node_modules/@aws-crypto/crc32c/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/ie11-detection": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", - "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -108,14 +104,12 @@ "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/sha1-browser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", - "peer": true, "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/supports-web-crypto": "^3.0.0", @@ -129,14 +123,12 @@ "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/sha256-browser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "peer": true, "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -151,14 +143,12 @@ "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/sha256-js": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -168,14 +158,12 @@ "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/supports-web-crypto": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -183,14 +171,12 @@ "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-crypto/util": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "peer": true, "dependencies": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -200,69 +186,69 @@ "node_modules/@aws-crypto/util/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "peer": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-sdk/client-s3": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.427.0.tgz", - "integrity": "sha512-YKjJ9zgn0oE393HURKgvjNoX6lxUjb+dkTBE1GymFnGCPl6VxQbKXajXWNqUyN+oPPlZ2osEiljPaN0RserUjA==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.529.1.tgz", + "integrity": "sha512-ZpvyO4w3XWo/OjXLd3fm7CLcKUUYcyady9qzTnKKSnp8a2NqO7UvU/1zhYdm+yyy8TR/9t7sDy+q6AYd4Nsr8g==", "dependencies": { "@aws-crypto/sha1-browser": "3.0.0", "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.427.0", - "@aws-sdk/credential-provider-node": "3.427.0", - "@aws-sdk/middleware-bucket-endpoint": "3.425.0", - "@aws-sdk/middleware-expect-continue": "3.425.0", - "@aws-sdk/middleware-flexible-checksums": "3.425.0", - "@aws-sdk/middleware-host-header": "3.425.0", - "@aws-sdk/middleware-location-constraint": "3.425.0", - "@aws-sdk/middleware-logger": "3.425.0", - "@aws-sdk/middleware-recursion-detection": "3.425.0", - "@aws-sdk/middleware-sdk-s3": "3.427.0", - "@aws-sdk/middleware-signing": "3.425.0", - "@aws-sdk/middleware-ssec": "3.425.0", - "@aws-sdk/middleware-user-agent": "3.427.0", - "@aws-sdk/region-config-resolver": "3.425.0", - "@aws-sdk/signature-v4-multi-region": "3.425.0", - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-endpoints": "3.427.0", - "@aws-sdk/util-user-agent-browser": "3.425.0", - "@aws-sdk/util-user-agent-node": "3.425.0", - "@aws-sdk/xml-builder": "3.310.0", - "@smithy/config-resolver": "^2.0.11", - "@smithy/eventstream-serde-browser": "^2.0.10", - "@smithy/eventstream-serde-config-resolver": "^2.0.10", - "@smithy/eventstream-serde-node": "^2.0.10", - "@smithy/fetch-http-handler": "^2.2.1", - "@smithy/hash-blob-browser": "^2.0.10", - "@smithy/hash-node": "^2.0.10", - "@smithy/hash-stream-node": "^2.0.10", - "@smithy/invalid-dependency": "^2.0.10", - "@smithy/md5-js": "^2.0.10", - "@smithy/middleware-content-length": "^2.0.12", - "@smithy/middleware-endpoint": "^2.0.10", - "@smithy/middleware-retry": "^2.0.13", - "@smithy/middleware-serde": "^2.0.10", - "@smithy/middleware-stack": "^2.0.4", - "@smithy/node-config-provider": "^2.0.13", - "@smithy/node-http-handler": "^2.1.6", - "@smithy/protocol-http": "^3.0.6", - "@smithy/smithy-client": "^2.1.9", - "@smithy/types": "^2.3.4", - "@smithy/url-parser": "^2.0.10", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.13", - "@smithy/util-defaults-mode-node": "^2.0.15", - "@smithy/util-retry": "^2.0.3", - "@smithy/util-stream": "^2.0.14", - "@smithy/util-utf8": "^2.0.0", - "@smithy/util-waiter": "^2.0.10", - "fast-xml-parser": "4.2.5", + "@aws-sdk/client-sts": "3.529.1", + "@aws-sdk/core": "3.529.1", + "@aws-sdk/credential-provider-node": "3.529.1", + "@aws-sdk/middleware-bucket-endpoint": "3.525.0", + "@aws-sdk/middleware-expect-continue": "3.523.0", + "@aws-sdk/middleware-flexible-checksums": "3.523.0", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-location-constraint": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-sdk-s3": "3.525.0", + "@aws-sdk/middleware-signing": "3.523.0", + "@aws-sdk/middleware-ssec": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.525.0", + "@aws-sdk/region-config-resolver": "3.525.0", + "@aws-sdk/signature-v4-multi-region": "3.525.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.525.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.525.0", + "@aws-sdk/xml-builder": "3.523.0", + "@smithy/config-resolver": "^2.1.4", + "@smithy/core": "^1.3.5", + "@smithy/eventstream-serde-browser": "^2.1.3", + "@smithy/eventstream-serde-config-resolver": "^2.1.3", + "@smithy/eventstream-serde-node": "^2.1.3", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-blob-browser": "^2.1.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/hash-stream-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/md5-js": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/middleware-retry": "^2.1.4", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.4", + "@smithy/util-defaults-mode-node": "^2.2.3", + "@smithy/util-endpoints": "^1.1.4", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-stream": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "@smithy/util-waiter": "^2.1.3", "tslib": "^2.5.0" }, "engines": { @@ -270,92 +256,166 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.427.0.tgz", - "integrity": "sha512-sFVFEmsQ1rmgYO1SgrOTxE/MTKpeE4hpOkm1WqhLQK7Ij136vXpjCxjH1JYZiHiUzO1wr9t4ex4dlB5J3VS/Xg==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.529.1.tgz", + "integrity": "sha512-KT1U/ZNjDhVv2ZgjzaeAn9VM7l667yeSguMrRYC8qk5h91/61MbjZypi6eOuKuVM+0fsQvzKScTQz0Lio0eYag==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.425.0", - "@aws-sdk/middleware-logger": "3.425.0", - "@aws-sdk/middleware-recursion-detection": "3.425.0", - "@aws-sdk/middleware-user-agent": "3.427.0", - "@aws-sdk/region-config-resolver": "3.425.0", - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-endpoints": "3.427.0", - "@aws-sdk/util-user-agent-browser": "3.425.0", - "@aws-sdk/util-user-agent-node": "3.425.0", - "@smithy/config-resolver": "^2.0.11", - "@smithy/fetch-http-handler": "^2.2.1", - "@smithy/hash-node": "^2.0.10", - "@smithy/invalid-dependency": "^2.0.10", - "@smithy/middleware-content-length": "^2.0.12", - "@smithy/middleware-endpoint": "^2.0.10", - "@smithy/middleware-retry": "^2.0.13", - "@smithy/middleware-serde": "^2.0.10", - "@smithy/middleware-stack": "^2.0.4", - "@smithy/node-config-provider": "^2.0.13", - "@smithy/node-http-handler": "^2.1.6", - "@smithy/protocol-http": "^3.0.6", - "@smithy/smithy-client": "^2.1.9", - "@smithy/types": "^2.3.4", - "@smithy/url-parser": "^2.0.10", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.13", - "@smithy/util-defaults-mode-node": "^2.0.15", - "@smithy/util-retry": "^2.0.3", - "@smithy/util-utf8": "^2.0.0", + "@aws-sdk/core": "3.529.1", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.525.0", + "@aws-sdk/region-config-resolver": "3.525.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.525.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.525.0", + "@smithy/config-resolver": "^2.1.4", + "@smithy/core": "^1.3.5", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/middleware-retry": "^2.1.4", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.4", + "@smithy/util-defaults-mode-node": "^2.2.3", + "@smithy/util-endpoints": "^1.1.4", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.427.0.tgz", - "integrity": "sha512-le2wLJKILyWuRfPz2HbyaNtu5kEki+ojUkTqCU6FPDRrqUvEkaaCBH9Awo/2AtrCfRkiobop8RuTTj6cAnpiJg==", - "peer": true, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.529.1.tgz", + "integrity": "sha512-bimxCWAvRnVcluWEQeadXvHyzWlBWsuGVligsaVZaGF0TLSn0eLpzpN9B1EhHzTf7m0Kh/wGtPSH1JxO6PpB+A==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/credential-provider-node": "3.427.0", - "@aws-sdk/middleware-host-header": "3.425.0", - "@aws-sdk/middleware-logger": "3.425.0", - "@aws-sdk/middleware-recursion-detection": "3.425.0", - "@aws-sdk/middleware-sdk-sts": "3.425.0", - "@aws-sdk/middleware-signing": "3.425.0", - "@aws-sdk/middleware-user-agent": "3.427.0", - "@aws-sdk/region-config-resolver": "3.425.0", - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-endpoints": "3.427.0", - "@aws-sdk/util-user-agent-browser": "3.425.0", - "@aws-sdk/util-user-agent-node": "3.425.0", - "@smithy/config-resolver": "^2.0.11", - "@smithy/fetch-http-handler": "^2.2.1", - "@smithy/hash-node": "^2.0.10", - "@smithy/invalid-dependency": "^2.0.10", - "@smithy/middleware-content-length": "^2.0.12", - "@smithy/middleware-endpoint": "^2.0.10", - "@smithy/middleware-retry": "^2.0.13", - "@smithy/middleware-serde": "^2.0.10", - "@smithy/middleware-stack": "^2.0.4", - "@smithy/node-config-provider": "^2.0.13", - "@smithy/node-http-handler": "^2.1.6", - "@smithy/protocol-http": "^3.0.6", - "@smithy/smithy-client": "^2.1.9", - "@smithy/types": "^2.3.4", - "@smithy/url-parser": "^2.0.10", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.13", - "@smithy/util-defaults-mode-node": "^2.0.15", - "@smithy/util-retry": "^2.0.3", - "@smithy/util-utf8": "^2.0.0", + "@aws-sdk/client-sts": "3.529.1", + "@aws-sdk/core": "3.529.1", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.525.0", + "@aws-sdk/region-config-resolver": "3.525.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.525.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.525.0", + "@smithy/config-resolver": "^2.1.4", + "@smithy/core": "^1.3.5", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/middleware-retry": "^2.1.4", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.4", + "@smithy/util-defaults-mode-node": "^2.2.3", + "@smithy/util-endpoints": "^1.1.4", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-node": "^3.529.1" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.529.1.tgz", + "integrity": "sha512-Rvk2Sr3MACQTOtngUU+omlf4E17k47dRVXR7OFRD6Ow5iGgC9tkN2q/ExDPW/ktPOmM0lSgzWyQ6/PC/Zq3HUg==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.529.1", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.525.0", + "@aws-sdk/region-config-resolver": "3.525.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.525.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.525.0", + "@smithy/config-resolver": "^2.1.4", + "@smithy/core": "^1.3.5", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/middleware-retry": "^2.1.4", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.4", + "@smithy/util-defaults-mode-node": "^2.2.3", + "@smithy/util-endpoints": "^1.1.4", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-node": "^3.529.1" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.529.1.tgz", + "integrity": "sha512-Sj42sYPfaL9PHvvciMICxhyrDZjqnnvFbPKDmQL5aFKyXy122qx7RdVqUOQERDmMQfvJh6+0W1zQlLnre89q4Q==", + "dependencies": { + "@smithy/core": "^1.3.5", + "@smithy/protocol-http": "^3.2.1", + "@smithy/signature-v4": "^2.1.3", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", "fast-xml-parser": "4.2.5", "tslib": "^2.5.0" }, @@ -364,14 +424,32 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.425.0.tgz", - "integrity": "sha512-J20etnLvMKXRVi5FK4F8yOCNm2RTaQn5psQTGdDEPWJNGxohcSpzzls8U2KcMyUJ+vItlrThr4qwgpHG3i/N0w==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.523.0.tgz", + "integrity": "sha512-Y6DWdH6/OuMDoNKVzZlNeBc6f1Yjk1lYMjANKpIhMbkRCvLJw/PYZKOZa8WpXbTYdgg9XLjKybnLIb3ww3uuzA==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.525.0.tgz", + "integrity": "sha512-RNWQGuSBQZhl3iqklOslUEfQ4br1V3DCPboMpeqFtddUWJV3m2u2extFur9/4Uy+1EHVF120IwZUKtd8dF+ibw==", + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/property-provider": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/util-stream": "^2.1.3", "tslib": "^2.5.0" }, "engines": { @@ -379,20 +457,20 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.427.0.tgz", - "integrity": "sha512-NmH1cO/w98CKMltYec3IrJIIco19wRjATFNiw83c+FGXZ+InJwReqBnruxIOmKTx2KDzd6fwU1HOewS7UjaaaQ==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.529.1.tgz", + "integrity": "sha512-RjHsuTvHIwXG7a/3ERexemiD3c9riKMCZQzY2/b0Gg0ButEVbBcMfERtUzWmQ0V4ufe/PEZjP68MH1gupcoF9A==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.425.0", - "@aws-sdk/credential-provider-process": "3.425.0", - "@aws-sdk/credential-provider-sso": "3.427.0", - "@aws-sdk/credential-provider-web-identity": "3.425.0", - "@aws-sdk/types": "3.425.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/client-sts": "3.529.1", + "@aws-sdk/credential-provider-env": "3.523.0", + "@aws-sdk/credential-provider-process": "3.523.0", + "@aws-sdk/credential-provider-sso": "3.529.1", + "@aws-sdk/credential-provider-web-identity": "3.529.1", + "@aws-sdk/types": "3.523.0", + "@smithy/credential-provider-imds": "^2.2.3", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -400,21 +478,21 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.427.0.tgz", - "integrity": "sha512-wYYbQ57nKL8OfgRbl8k6uXcdnYml+p3LSSfDUAuUEp1HKlQ8lOXFJ3BdLr5qrk7LhpyppSRnWBmh2c3kWa7ANQ==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.529.1.tgz", + "integrity": "sha512-mvY7F3dMmk/0dZOCfl5sUI1bG0osureBjxhELGCF0KkJqhWI0hIzh8UnPkYytSg3vdc97CMv7pTcozxrdA3b0g==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.425.0", - "@aws-sdk/credential-provider-ini": "3.427.0", - "@aws-sdk/credential-provider-process": "3.425.0", - "@aws-sdk/credential-provider-sso": "3.427.0", - "@aws-sdk/credential-provider-web-identity": "3.425.0", - "@aws-sdk/types": "3.425.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/credential-provider-env": "3.523.0", + "@aws-sdk/credential-provider-http": "3.525.0", + "@aws-sdk/credential-provider-ini": "3.529.1", + "@aws-sdk/credential-provider-process": "3.523.0", + "@aws-sdk/credential-provider-sso": "3.529.1", + "@aws-sdk/credential-provider-web-identity": "3.529.1", + "@aws-sdk/types": "3.523.0", + "@smithy/credential-provider-imds": "^2.2.3", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -422,15 +500,14 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.425.0.tgz", - "integrity": "sha512-YY6tkLdvtb1Fgofp3b1UWO+5vwS14LJ/smGmuGpSba0V7gFJRdcrJ9bcb9vVgAGuMdjzRJ+bUKlLLtqXkaykEw==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.523.0.tgz", + "integrity": "sha512-f0LP9KlFmMvPWdKeUKYlZ6FkQAECUeZMmISsv6NKtvPCI9e4O4cLTeR09telwDK8P0HrgcRuZfXM7E30m8re0Q==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -438,17 +515,16 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.427.0.tgz", - "integrity": "sha512-c+tXyS/i49erHs4bAp6vKNYeYlyQ0VNMBgoco0LCn1rL0REtHbfhWMnqDLF6c2n3yIWDOTrQu0D73Idnpy16eA==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.529.1.tgz", + "integrity": "sha512-KFMKkaoTGDgSJG+o9Ii7AglWG5JQeF6IFw9cXLMwDdIrp3KUmRcUIqe0cjOoCqeQEDGy0VHsimHmKKJ3894i/A==", "dependencies": { - "@aws-sdk/client-sso": "3.427.0", - "@aws-sdk/token-providers": "3.427.0", - "@aws-sdk/types": "3.425.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/client-sso": "3.529.1", + "@aws-sdk/token-providers": "3.529.1", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -456,14 +532,14 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.425.0.tgz", - "integrity": "sha512-/0R65TgRzL01JU3SzloivWNwdkbIhr06uY/F5pBHf/DynQqaspKNfdHn6AiozgSVDfwRHFjKBTUy6wvf3QFkuA==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.529.1.tgz", + "integrity": "sha512-AGuZDOKN+AttjwTjrF47WLqzeEut2YynyxjkXZhxZF/xn8i5Y51kUAUdXsXw1bgR25pAeXQIdhsrQlRa1Pm5kw==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/client-sts": "3.529.1", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -508,17 +584,16 @@ } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.425.0.tgz", - "integrity": "sha512-7UTfA10fmDw9cgHLApxRUNPywZTG4S/1TNZgTxndO/1OM9ZHtIatw1iLbqJD35gHrpEYI8Vo14YvcnD2ITuiMw==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.525.0.tgz", + "integrity": "sha512-nYfQ2Xspfef7j8mZO7varUWLPH6HQlXateH7tBVtBNUAazyQE4UJEvC0fbQ+Y01e+FKlirim/m2umkdMXqAlTg==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-arn-parser": "3.310.0", - "@smithy/node-config-provider": "^2.0.13", - "@smithy/protocol-http": "^3.0.6", - "@smithy/types": "^2.3.4", - "@smithy/util-config-provider": "^2.0.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-arn-parser": "3.495.0", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "@smithy/util-config-provider": "^2.2.1", "tslib": "^2.5.0" }, "engines": { @@ -526,14 +601,13 @@ } }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.425.0.tgz", - "integrity": "sha512-CqAmnDST2o7+sKKw2/ffHKiYKE+jZb/Ce9U0P//ZYzqp9R1Wb016ID+W6DoxufyPJAS9dpRMcUDnAssmMIC/EA==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.523.0.tgz", + "integrity": "sha512-E5DyRAHU39VHaAlQLqXYS/IKpgk3vsryuU6kkOcIIK8Dgw0a2tjoh5AOCaNa8pD+KgAGrFp35JIMSX1zui5diA==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -541,18 +615,17 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.425.0.tgz", - "integrity": "sha512-BDwn2vVVsC/AzmHXQlaZhEpKXL7GfKFpH7ZFccZuwEQBcyn8lVCcwtfaRe5P1mEe2wklVzOXd1dw8bt0+BOUPA==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.523.0.tgz", + "integrity": "sha512-lIa1TdWY9q4zsDFarfSnYcdrwPR+nypaU4n6hb95i620/1F5M5s6H8P0hYtwTNNvx+slrR8F3VBML9pjBtzAHw==", "dependencies": { "@aws-crypto/crc32": "3.0.0", "@aws-crypto/crc32c": "3.0.0", - "@aws-sdk/types": "3.425.0", - "@smithy/is-array-buffer": "^2.0.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/types": "^2.3.4", - "@smithy/util-utf8": "^2.0.0", + "@aws-sdk/types": "3.523.0", + "@smithy/is-array-buffer": "^2.1.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "@smithy/util-utf8": "^2.1.1", "tslib": "^2.5.0" }, "engines": { @@ -560,14 +633,13 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.425.0.tgz", - "integrity": "sha512-E5Gt41LObQ+cr8QnLthwsH3MtVSNXy1AKJMowDr85h0vzqA/FHUkgHyOGntgozzjXT5M0MaSRYxS0xwTR5D4Ew==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.523.0.tgz", + "integrity": "sha512-4g3q7Ta9sdD9TMUuohBAkbx/e3I/juTqfKi7TPgP+8jxcYX72MOsgemAMHuP6CX27eyj4dpvjH+w4SIVDiDSmg==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -575,13 +647,12 @@ } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.425.0.tgz", - "integrity": "sha512-3rt0LpGmL1LCRFuEObS1yERd9OEV+AEIAvhY7b53M7u7SyrjWQtpntWkI365L/QljhgMXQBfps2qO4JtrhQnsA==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.523.0.tgz", + "integrity": "sha512-1QAUXX3U0jkARnU0yyjk81EO4Uw5dCeQOtvUY5s3bUOHatR3ThosQeIr6y9BCsbXHzNnDe1ytCjqAPyo8r/bYw==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -589,13 +660,12 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.425.0.tgz", - "integrity": "sha512-INE9XWRXx2f4a/r2vOU0tAmgctVp7nEaEasemNtVBYhqbKLZvr9ndLBSgKGgJ8LIcXAoISipaMuFiqIGkFsm7A==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.523.0.tgz", + "integrity": "sha512-PeDNJNhfiaZx54LBaLTXzUaJ9LXFwDFFIksipjqjvxMafnoVcQwKbkoPUWLe5ytT4nnL1LogD3s55mERFUsnwg==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -603,14 +673,13 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.425.0.tgz", - "integrity": "sha512-77gnzJ5b91bgD75L/ugpOyerx6lR3oyS4080X1YI58EzdyBMkDrHM4FbMcY2RynETi3lwXCFzLRyZjWXY1mRlw==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.523.0.tgz", + "integrity": "sha512-nZ3Vt7ehfSDYnrcg/aAfjjvpdE+61B3Zk68i6/hSUIegT3IH9H1vSW67NDKVp+50hcEfzWwM2HMPXxlzuyFyrw==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -618,31 +687,18 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.427.0.tgz", - "integrity": "sha512-virGCf9vsqYCLpmngLOZOVSYgVr2cCOCvTuRoT9vf5tD/63JwaC173jnbdoJO6CWI7ID5Iz0eNdgITXVQ2mpew==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.525.0.tgz", + "integrity": "sha512-ewFyyFM6wdFTOqCiId5GQNi7owDdLEonQhB4h8tF6r3HV52bRlDvZA4aDos+ft6N/XY2J6L0qlFTFq+/oiurXw==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-arn-parser": "3.310.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/smithy-client": "^2.1.9", - "@smithy/types": "^2.3.4", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-sts": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.425.0.tgz", - "integrity": "sha512-JFojrg76oKAoBknnr9EL5N2aJ1mRCtBqXoZYST58GSx8uYdFQ89qS65VNQ8JviBXzsrCNAn4vDhZ5Ch5E6TxGQ==", - "peer": true, - "dependencies": { - "@aws-sdk/middleware-signing": "3.425.0", - "@aws-sdk/types": "3.425.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-arn-parser": "3.495.0", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/protocol-http": "^3.2.1", + "@smithy/signature-v4": "^2.1.3", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/util-config-provider": "^2.2.1", "tslib": "^2.5.0" }, "engines": { @@ -650,17 +706,16 @@ } }, "node_modules/@aws-sdk/middleware-signing": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.425.0.tgz", - "integrity": "sha512-ZpOfgJHk7ovQ0sSwg3tU4NxFOnz53lJlkJRf7S+wxQALHM0P2MJ6LYBrZaFMVsKiJxNIdZBXD6jclgHg72ZW6Q==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.523.0.tgz", + "integrity": "sha512-pFXV4don6qcmew/OvEjLUr2foVjzoJ8o5k57Oz9yAHz8INx3RHK8MP/K4mVhHo6n0SquRcWrm4kY/Tw+89gkEA==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.3.4", - "@smithy/util-middleware": "^2.0.3", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/signature-v4": "^2.1.3", + "@smithy/types": "^2.10.1", + "@smithy/util-middleware": "^2.1.3", "tslib": "^2.5.0" }, "engines": { @@ -668,13 +723,12 @@ } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.425.0.tgz", - "integrity": "sha512-9HTuXnHYAZWkwPC8x9tElsQjFPxDT//orbIFauS7VF5HkLCKn9J6O6lW1wKMxrEnDwfN/Vi3nw479MoPj5Ss0Q==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.523.0.tgz", + "integrity": "sha512-FaqAZQeF5cQzZLOIboIJRaWVOQ2F2pJZAXGF5D7nJsxYNFChotA0O0iWimBRxU35RNn7yirVxz35zQzs20ddIw==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -682,15 +736,14 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.427.0.tgz", - "integrity": "sha512-y9HxYsNvnA3KqDl8w1jHeCwz4P9CuBEtu/G+KYffLeAMBsMZmh4SIkFFCO9wE/dyYg6+yo07rYcnnIfy7WA0bw==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.525.0.tgz", + "integrity": "sha512-4al/6uO+t/QIYXK2OgqzDKQzzLAYJza1vWFS+S0lJ3jLNGyLB5BMU5KqWjDzevYZ4eCnz2Nn7z0FveUTNz8YdQ==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-endpoints": "3.427.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.525.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -698,15 +751,33 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.425.0.tgz", - "integrity": "sha512-u7uv/iUOapIJdRgRkO3wnpYsUgV6ponsZJQgVg/8L+n+Vo5PQL5gAcIuAOwcYSKQPFaeK+KbmByI4SyOK203Vw==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.525.0.tgz", + "integrity": "sha512-8kFqXk6UyKgTMi7N7QlhA6qM4pGPWbiUXqEY2RgUWngtxqNFGeM9JTexZeuavQI+qLLe09VPShPNX71fEDcM6w==", "dependencies": { - "@smithy/node-config-provider": "^2.0.13", - "@smithy/types": "^2.3.4", - "@smithy/util-config-provider": "^2.0.0", - "@smithy/util-middleware": "^2.0.3", + "@aws-sdk/types": "3.523.0", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/types": "^2.10.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/s3-request-presigner": { + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.529.1.tgz", + "integrity": "sha512-54nNN/LjqlyUDTLO3U9D7xkYK4/UttcqfKoHQuPI6QabqZGT1hMFs5SzsyihNchgxci6ZTo4pqQQ3lGfE/HHOA==", + "dependencies": { + "@aws-sdk/signature-v4-multi-region": "3.525.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-format-url": "3.523.0", + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -714,15 +785,15 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.425.0.tgz", - "integrity": "sha512-7n2FRPE9rLaVa26xXQJ8TExrt53dWN824axQd1a0r5va0SmMQYG/iV5LBmwUlAntUSq46Lse4Q5YnbOVedGOmw==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.525.0.tgz", + "integrity": "sha512-j8gkdfiokaherRgokfZBl2azYBMHlegT7pOnR/3Y79TSz6G+bJeIkuNk8aUbJArr6R8nvAM1j4dt1rBM+efolQ==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/middleware-sdk-s3": "3.525.0", + "@aws-sdk/types": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/signature-v4": "^2.1.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -730,45 +801,15 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.427.0.tgz", - "integrity": "sha512-4E5E+4p8lJ69PBY400dJXF06LUHYx5lkKzBEsYqWWhoZcoftrvi24ltIhUDoGVLkrLcTHZIWSdFAWSos4hXqeg==", - "peer": true, + "version": "3.529.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.529.1.tgz", + "integrity": "sha512-NpgMjsfpqiugbxrYGXtta914N43Mx/H0niidqv8wKMTgWQEtsJvYtOni+kuLXB+LmpjaMFNlpadooFU/bK4buA==", "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.425.0", - "@aws-sdk/middleware-logger": "3.425.0", - "@aws-sdk/middleware-recursion-detection": "3.425.0", - "@aws-sdk/middleware-user-agent": "3.427.0", - "@aws-sdk/types": "3.425.0", - "@aws-sdk/util-endpoints": "3.427.0", - "@aws-sdk/util-user-agent-browser": "3.425.0", - "@aws-sdk/util-user-agent-node": "3.425.0", - "@smithy/config-resolver": "^2.0.11", - "@smithy/fetch-http-handler": "^2.2.1", - "@smithy/hash-node": "^2.0.10", - "@smithy/invalid-dependency": "^2.0.10", - "@smithy/middleware-content-length": "^2.0.12", - "@smithy/middleware-endpoint": "^2.0.10", - "@smithy/middleware-retry": "^2.0.13", - "@smithy/middleware-serde": "^2.0.10", - "@smithy/middleware-stack": "^2.0.4", - "@smithy/node-config-provider": "^2.0.13", - "@smithy/node-http-handler": "^2.1.6", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.6", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/smithy-client": "^2.1.9", - "@smithy/types": "^2.3.4", - "@smithy/url-parser": "^2.0.10", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.13", - "@smithy/util-defaults-mode-node": "^2.0.15", - "@smithy/util-retry": "^2.0.3", - "@smithy/util-utf8": "^2.0.0", + "@aws-sdk/client-sso-oidc": "3.529.1", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -776,12 +817,11 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.425.0.tgz", - "integrity": "sha512-6lqbmorwerN4v+J5dqbHPAsjynI0mkEF+blf+69QTaKKGaxBBVaXgqoqul9RXYcK5MMrrYRbQIMd0zYOoy90kA==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.523.0.tgz", + "integrity": "sha512-AqGIu4u+SxPiUuNBp2acCVcq80KDUFjxe6e3cMTvKWTzCbrVk1AXv0dAaJnCmdkWIha6zJDWxpIk/aL4EGhZ9A==", "dependencies": { - "@smithy/types": "^2.3.4", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -789,10 +829,9 @@ } }, "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz", - "integrity": "sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==", - "peer": true, + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.495.0.tgz", + "integrity": "sha512-hwdA3XAippSEUxs7jpznwD63YYFR+LtQvlEcebPTgWR9oQgG9TfS+39PUfbnEeje1ICuOrN3lrFqFbmP9uzbMg==", "dependencies": { "tslib": "^2.5.0" }, @@ -801,13 +840,27 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.427.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.427.0.tgz", - "integrity": "sha512-rSyiAIFF/EVvity/+LWUqoTMJ0a25RAc9iqx0WZ4tf1UjuEXRRXxZEb+jEZg1bk+pY84gdLdx9z5E+MSJCZxNQ==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.525.0.tgz", + "integrity": "sha512-DIW7WWU5tIGkeeKX6NJUyrEIdWMiqjLQG3XBzaUj+ufIENwNjdAHhlD8l2vX7Yr3JZRT6yN/84wBCj7Tw1xd1g==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/node-config-provider": "^2.0.13", + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", + "@smithy/util-endpoints": "^1.1.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-format-url": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.523.0.tgz", + "integrity": "sha512-OWi+8bsEfxG4DvHkWauxyWVZMbYrezC49DbGDEu1lJgk9eqQALlyGkZHt9O8KKfyT/mdqQbR8qbpkxqYcGuHVA==", + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/querystring-builder": "^2.1.3", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -818,7 +871,6 @@ "version": "3.310.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", - "peer": true, "dependencies": { "tslib": "^2.5.0" }, @@ -827,26 +879,24 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.425.0.tgz", - "integrity": "sha512-22Y9iMtjGcFjGILR6/xdp1qRezlHVLyXtnpEsbuPTiernRCPk6zfAnK/ATH77r02MUjU057tdxVkd5umUBTn9Q==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.523.0.tgz", + "integrity": "sha512-6ZRNdGHX6+HQFqTbIA5+i8RWzxFyxsZv8D3soRfpdyWIKkzhSz8IyRKXRciwKBJDaC7OX2jzGE90wxRQft27nA==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", "bowser": "^2.11.0", "tslib": "^2.5.0" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.425.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.425.0.tgz", - "integrity": "sha512-SIR4F5uQeeVAi8lv4OgRirtdtNi5zeyogTuQgGi9su8F/WP1N6JqxofcwpUY5f8/oJ2UlXr/tx1f09UHfJJzvA==", - "peer": true, + "version": "3.525.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.525.0.tgz", + "integrity": "sha512-88Wjt4efyUSBGcyIuh1dvoMqY1k15jpJc5A/3yi67clBQEFsu9QCodQCQPqmRjV3VRcMtBOk+jeCTiUzTY5dRQ==", "dependencies": { - "@aws-sdk/types": "3.425.0", - "@smithy/node-config-provider": "^2.0.13", - "@smithy/types": "^2.3.4", + "@aws-sdk/types": "3.523.0", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -865,17 +915,16 @@ "version": "3.259.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "peer": true, "dependencies": { "tslib": "^2.3.1" } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz", - "integrity": "sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==", - "peer": true, + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.523.0.tgz", + "integrity": "sha512-wfvyVymj2TUw7SuDor9IuFcAzJZvWRBZotvY/wQJOlYa3UP3Oezzecy64N4FWfBJEsZdrTN+HOZFl+IzTWWnUA==", "dependencies": { + "@smithy/types": "^2.10.1", "tslib": "^2.5.0" }, "engines": { @@ -1297,6 +1346,7 @@ "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2139,11 +2189,6 @@ "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==", "dev": true }, - "node_modules/@react-dnd/shallowequal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", - "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" - }, "node_modules/@reduxjs/toolkit": { "version": "1.9.7", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", @@ -2204,11 +2249,11 @@ ] }, "node_modules/@smithy/abort-controller": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.11.tgz", - "integrity": "sha512-MSzE1qR2JNyb7ot3blIOT3O3H0Jn06iNDEgHRaqZUwBgx5EG+VIx24Y21tlKofzYryIOcWpIohLrIIyocD6LMA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.4.tgz", + "integrity": "sha512-66HO817oIZ2otLIqy06R5muapqZjkgF1jfU0wyNko8cuqZNu8nbS9ljlhcRYw/M/uWRJzB9ih81DLSHhYbBLlQ==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2216,34 +2261,49 @@ } }, "node_modules/@smithy/chunked-blob-reader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz", - "integrity": "sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==", - "peer": true, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.1.1.tgz", + "integrity": "sha512-NjNFCKxC4jVvn+lUr3Yo4/PmUJj3tbyqH6GNHueyTGS5Q27vlEJ1MkNhUDV8QGxJI7Bodnc2pD18lU2zRfhHlQ==", "dependencies": { "tslib": "^2.5.0" } }, "node_modules/@smithy/chunked-blob-reader-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.0.tgz", - "integrity": "sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==", - "peer": true, + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.1.2.tgz", + "integrity": "sha512-KwR9fFc/t5jH9RQFbrA9DHSmI+URTmB4v+i7H08UNET9AcN6GGBTBMiDKpA56Crw6CN7cSaSDXaRS/AsfOuupQ==", "dependencies": { - "@smithy/util-base64": "^2.0.0", + "@smithy/util-base64": "^2.2.0", "tslib": "^2.5.0" } }, "node_modules/@smithy/config-resolver": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.14.tgz", - "integrity": "sha512-K1K+FuWQoy8j/G7lAmK85o03O89s2Vvh6kMFmzEmiHUoQCRH1rzbDtMnGNiaMHeSeYJ6y79IyTusdRG+LuWwtg==", - "peer": true, + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.1.5.tgz", + "integrity": "sha512-LcBB5JQC3Tx2ZExIJzfvWaajhFIwHrUNQeqxhred2r5nnqrdly9uoCrvM1sxOOdghYuWWm2Kr8tBCDOmxsgeTA==", "dependencies": { - "@smithy/node-config-provider": "^2.1.1", - "@smithy/types": "^2.3.5", - "@smithy/util-config-provider": "^2.0.0", - "@smithy/util-middleware": "^2.0.4", + "@smithy/node-config-provider": "^2.2.5", + "@smithy/types": "^2.11.0", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.7.tgz", + "integrity": "sha512-zHrrstOO78g+/rOJoHi4j3mGUBtsljRhcKNzloWPv1XIwgcFUi+F1YFKr2qPQ3z7Ls5dNc4L2SPrVarNFIQqog==", + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.6", + "@smithy/middleware-retry": "^2.1.6", + "@smithy/middleware-serde": "^2.2.1", + "@smithy/protocol-http": "^3.2.2", + "@smithy/smithy-client": "^2.4.4", + "@smithy/types": "^2.11.0", + "@smithy/util-middleware": "^2.1.4", "tslib": "^2.5.0" }, "engines": { @@ -2251,15 +2311,14 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.16.tgz", - "integrity": "sha512-tKa2xF+69TvGxJT+lnJpGrKxUuAZDLYXFhqnPEgnHz+psTpkpcB4QRjHj63+uj83KaeFJdTfW201eLZeRn6FfA==", - "peer": true, + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.2.6.tgz", + "integrity": "sha512-+xQe4Pite0kdk9qn0Vyw5BRVh0iSlj+T4TEKRXr4E1wZKtVgIzGlkCrfICSjiPVFkPxk4jMpVboMYdEiiA88/w==", "dependencies": { - "@smithy/node-config-provider": "^2.1.1", - "@smithy/property-provider": "^2.0.12", - "@smithy/types": "^2.3.5", - "@smithy/url-parser": "^2.0.11", + "@smithy/node-config-provider": "^2.2.5", + "@smithy/property-provider": "^2.1.4", + "@smithy/types": "^2.11.0", + "@smithy/url-parser": "^2.1.4", "tslib": "^2.5.0" }, "engines": { @@ -2267,25 +2326,23 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.11.tgz", - "integrity": "sha512-BQCTjxhCYRZIfXapa2LmZSaH8QUBGwMZw7XRN83hrdixbLjIcj+o549zjkedFS07Ve2TlvWUI6BTzP+nv7snBA==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.1.4.tgz", + "integrity": "sha512-UkiieTztP7adg8EuqZvB0Y4LewdleZCJU7Kgt9RDutMsRYqO32fMpWeQHeTHaIMosmzcRZUykMRrhwGJe9mP3A==", "dependencies": { "@aws-crypto/crc32": "3.0.0", - "@smithy/types": "^2.3.5", - "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/types": "^2.11.0", + "@smithy/util-hex-encoding": "^2.1.1", "tslib": "^2.5.0" } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.11.tgz", - "integrity": "sha512-p9IK4uvwT6B3pT1VGlODvcVBfPVikjBFHAcKpvvNF+7lAEI+YiC6d0SROPkpjnvCgVBYyGXa3ciqrWnFze6mwQ==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.1.4.tgz", + "integrity": "sha512-K0SyvrUu/vARKzNW+Wp9HImiC/cJ6K88/n7FTH1slY+MErdKoiSbRLaXbJ9qD6x1Hu28cplHMlhADwZelUx/Ww==", "dependencies": { - "@smithy/eventstream-serde-universal": "^2.0.11", - "@smithy/types": "^2.3.5", + "@smithy/eventstream-serde-universal": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2293,12 +2350,11 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.11.tgz", - "integrity": "sha512-vN32E8yExo0Z8L7kXhlU9KRURrhqOpPdLxQMp3MwfMThrjiqbr1Sk5srUXc1ed2Ygl/l0TEN9vwNG0bQHg6AjQ==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.1.4.tgz", + "integrity": "sha512-FH+2AwOwZ0kHPB9sciWJtUqx81V4vizfT3P6T9eslmIC2hi8ch/KFvQlF7jDmwR1aLlPlq6qqLKLqzK/71Ki4A==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2306,13 +2362,12 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.11.tgz", - "integrity": "sha512-Gjqbpg7UmD+YzkpgNShNcDNZcUpBWIkvX2XCGptz5PoxJU/UQbuF9eSc93ZlIb7j4aGjtFfqk23HUMW8Hopg2Q==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.1.4.tgz", + "integrity": "sha512-gsc5ZTvVcB9sleLQzsK/rOhgn52+AAsmhEr41WDwAcctccBjh429+b8gT9t+SU8QyajypfsLOZfJQu0+zE515Q==", "dependencies": { - "@smithy/eventstream-serde-universal": "^2.0.11", - "@smithy/types": "^2.3.5", + "@smithy/eventstream-serde-universal": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2320,13 +2375,12 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.11.tgz", - "integrity": "sha512-F8FsxLTbFN4+Esgpo+nNKcEajrgRZJ+pG9c8+MhLM4Odp5ejLHw2GMCXd81cGsgmfcbnzdDEXazPPVzOwj89MQ==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.1.4.tgz", + "integrity": "sha512-NKLAsYnZA5s+ntipJRKo1RrRbhYHrsEnmiUoz0EhVYrAih+UELY9sKR+A1ujGaFm3nKDs5fPfiozC2wpXq2zUA==", "dependencies": { - "@smithy/eventstream-codec": "^2.0.11", - "@smithy/types": "^2.3.5", + "@smithy/eventstream-codec": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2334,38 +2388,36 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.2.tgz", - "integrity": "sha512-K7aRtRuaBjzlk+jWWeyfDTLAmRRvmA4fU8eHUXtjsuEDgi3f356ZE32VD2ssxIH13RCLVZbXMt5h7wHzYiSuVA==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.4.4.tgz", + "integrity": "sha512-DSUtmsnIx26tPuyyrK49dk2DAhPgEw6xRW7V62nMHIB5dk3NqhGnwcKO2fMdt/l3NUVgia34ZsSJA8bD+3nh7g==", "dependencies": { - "@smithy/protocol-http": "^3.0.7", - "@smithy/querystring-builder": "^2.0.11", - "@smithy/types": "^2.3.5", - "@smithy/util-base64": "^2.0.0", + "@smithy/protocol-http": "^3.2.2", + "@smithy/querystring-builder": "^2.1.4", + "@smithy/types": "^2.11.0", + "@smithy/util-base64": "^2.2.0", "tslib": "^2.5.0" } }, "node_modules/@smithy/hash-blob-browser": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.11.tgz", - "integrity": "sha512-/6vq/NiH2EN3mWdwcLdjVohP+VCng+ZA1GnlUdx959egsfgIlLWQvCyjnB2ze9Hr6VHV5XEFLLpLQH2dHA6Sgw==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.1.4.tgz", + "integrity": "sha512-bDugS1DortnriGDdp0sqdq7dLI5if8CEOF9rKtpJa1ZYMq6fxOtTId//dlilS5QgUtUs6GHN5aMQVxEjhBzzQA==", "dependencies": { - "@smithy/chunked-blob-reader": "^2.0.0", - "@smithy/chunked-blob-reader-native": "^2.0.0", - "@smithy/types": "^2.3.5", + "@smithy/chunked-blob-reader": "^2.1.1", + "@smithy/chunked-blob-reader-native": "^2.1.2", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" } }, "node_modules/@smithy/hash-node": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.11.tgz", - "integrity": "sha512-PbleVugN2tbhl1ZoNWVrZ1oTFFas/Hq+s6zGO8B9bv4w/StTriTKA9W+xZJACOj9X7zwfoTLbscM+avCB1KqOQ==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.1.4.tgz", + "integrity": "sha512-uvCcpDLXaTTL0X/9ezF8T8sS77UglTfZVQaUOBiCvR0QydeSyio3t0Hj3QooVdyFsKTubR8gCk/ubLk3vAyDng==", "dependencies": { - "@smithy/types": "^2.3.5", - "@smithy/util-buffer-from": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", + "@smithy/types": "^2.11.0", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-utf8": "^2.2.0", "tslib": "^2.5.0" }, "engines": { @@ -2373,13 +2425,12 @@ } }, "node_modules/@smithy/hash-stream-node": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.0.11.tgz", - "integrity": "sha512-Jn2yl+Dn0kvwKvSavvR1/BFVYa2wIkaJKWeTH48kno89gqHAJxMh1hrtBN6SJ7F8VhodNZTiNOlQVqCSfLheNQ==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.1.4.tgz", + "integrity": "sha512-HcDQRs/Fcx7lwAd+/vSW/e7ltdh148D2Pq7XI61CEWcOoQdQ0W8aYBHDRC4zjtXv6hySdmWE+vo3dvdTt7aj8A==", "dependencies": { - "@smithy/types": "^2.3.5", - "@smithy/util-utf8": "^2.0.0", + "@smithy/types": "^2.11.0", + "@smithy/util-utf8": "^2.2.0", "tslib": "^2.5.0" }, "engines": { @@ -2387,19 +2438,18 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.11.tgz", - "integrity": "sha512-zazq99ujxYv/NOf9zh7xXbNgzoVLsqE0wle8P/1zU/XdhPi/0zohTPKWUzIxjGdqb5hkkwfBkNkl5H+LE0mvgw==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.1.4.tgz", + "integrity": "sha512-QzlNBl6jt3nb9jNnE51wTegReVvUdozyMMrFEyb/rc6AzPID1O+qMJYjAAoNw098y0CZVfCpEnoK2+mfBOd8XA==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" } }, "node_modules/@smithy/is-array-buffer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", - "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz", + "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==", "dependencies": { "tslib": "^2.5.0" }, @@ -2408,24 +2458,22 @@ } }, "node_modules/@smithy/md5-js": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.0.11.tgz", - "integrity": "sha512-YBIv+e95qeGvQA05ucwstmTeQ/bUzWgU+nO2Ffmif5awu6IzSR0Jfk3XLYh4mdy7f8DCgsn8qA63u7N9Lu0+5A==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.1.4.tgz", + "integrity": "sha512-WHTnnYJPKE7Sy49DogLuox42TnlwD3cQ6TObPD6WFWjKocWIdpEpIvdJHwWUfSFf0JIi8ON8z6ZEhsnyKVCcLQ==", "dependencies": { - "@smithy/types": "^2.3.5", - "@smithy/util-utf8": "^2.0.0", + "@smithy/types": "^2.11.0", + "@smithy/util-utf8": "^2.2.0", "tslib": "^2.5.0" } }, "node_modules/@smithy/middleware-content-length": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.13.tgz", - "integrity": "sha512-Md2kxWpaec3bXp1oERFPQPBhOXCkGSAF7uc1E+4rkwjgw3/tqAXRtbjbggu67HJdwaif76As8AV6XxbD1HzqTQ==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.1.4.tgz", + "integrity": "sha512-C6VRwfcr0w9qRFhDGCpWMVhlEIBFlmlPRP1aX9Cv9xDj9SUwlDrNvoV1oP1vjRYuLxCDgovBBynCwwcluS2wLw==", "dependencies": { - "@smithy/protocol-http": "^3.0.7", - "@smithy/types": "^2.3.5", + "@smithy/protocol-http": "^3.2.2", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2433,14 +2481,16 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.11.tgz", - "integrity": "sha512-mCugsvB15up6fqpzUEpMT4CuJmFkEI+KcozA7QMzYguXCaIilyMKsyxgamwmr+o7lo3QdjN0//XLQ9bWFL129g==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.4.6.tgz", + "integrity": "sha512-AsXtUXHPOAS0EGZUSFOsVJvc7p0KL29PGkLxLfycPOcFVLru/oinYB6yvyL73ZZPX2OB8sMYUMrj7eH2kI7V/w==", "dependencies": { - "@smithy/middleware-serde": "^2.0.11", - "@smithy/types": "^2.3.5", - "@smithy/url-parser": "^2.0.11", - "@smithy/util-middleware": "^2.0.4", + "@smithy/middleware-serde": "^2.2.1", + "@smithy/node-config-provider": "^2.2.5", + "@smithy/shared-ini-file-loader": "^2.3.5", + "@smithy/types": "^2.11.0", + "@smithy/url-parser": "^2.1.4", + "@smithy/util-middleware": "^2.1.4", "tslib": "^2.5.0" }, "engines": { @@ -2448,17 +2498,17 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.16.tgz", - "integrity": "sha512-Br5+0yoiMS0ugiOAfJxregzMMGIRCbX4PYo1kDHtLgvkA/d++aHbnHB819m5zOIAMPvPE7AThZgcsoK+WOsUTA==", - "peer": true, + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.1.6.tgz", + "integrity": "sha512-khpSV0NxqMHfa06kfG4WYv+978sVvfTFmn0hIFKKwOXtIxyYtPKiQWFT4nnwZD07fGdYGbtCBu3YALc8SsA5mA==", "dependencies": { - "@smithy/node-config-provider": "^2.1.1", - "@smithy/protocol-http": "^3.0.7", - "@smithy/service-error-classification": "^2.0.4", - "@smithy/types": "^2.3.5", - "@smithy/util-middleware": "^2.0.4", - "@smithy/util-retry": "^2.0.4", + "@smithy/node-config-provider": "^2.2.5", + "@smithy/protocol-http": "^3.2.2", + "@smithy/service-error-classification": "^2.1.4", + "@smithy/smithy-client": "^2.4.4", + "@smithy/types": "^2.11.0", + "@smithy/util-middleware": "^2.1.4", + "@smithy/util-retry": "^2.1.4", "tslib": "^2.5.0", "uuid": "^8.3.2" }, @@ -2470,17 +2520,16 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "peer": true, "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/@smithy/middleware-serde": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.11.tgz", - "integrity": "sha512-NuxnjMyf4zQqhwwdh0OTj5RqpnuT6HcH5Xg5GrPijPcKzc2REXVEVK4Yyk8ckj8ez1XSj/bCmJ+oNjmqB02GWA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.2.1.tgz", + "integrity": "sha512-VAWRWqnNjgccebndpyK94om4ZTYzXLQxUmNCXYzM/3O9MTfQjTNBgtFtQwyIIez6z7LWcCsXmnKVIOE9mLqAHQ==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2488,11 +2537,11 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.5.tgz", - "integrity": "sha512-bVQU/rZzBY7CbSxIrDTGZYnBWKtIw+PL/cRc9B7etZk1IKSOe0NvKMJyWllfhfhrTeMF6eleCzOihIQympAvPw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.1.4.tgz", + "integrity": "sha512-Qqs2ba8Ax1rGKOSGJS2JN23fhhox2WMdRuzx0NYHtXzhxbJOIMmz9uQY6Hf4PY8FPteBPp1+h0j5Fmr+oW12sg==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2500,14 +2549,13 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.1.tgz", - "integrity": "sha512-1lF6s1YWBi1LBu2O30tD3jyTgMtuvk/Z1twzXM4GPYe4dmZix4nNREPJIPOcfFikNU2o0eTYP80+izx5F2jIJA==", - "peer": true, + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.2.5.tgz", + "integrity": "sha512-CxPf2CXhjO79IypHJLBATB66Dw6suvr1Yc2ccY39hpR6wdse3pZ3E8RF83SODiNH0Wjmkd0ze4OF8exugEixgA==", "dependencies": { - "@smithy/property-provider": "^2.0.12", - "@smithy/shared-ini-file-loader": "^2.2.0", - "@smithy/types": "^2.3.5", + "@smithy/property-provider": "^2.1.4", + "@smithy/shared-ini-file-loader": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2515,14 +2563,14 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.7.tgz", - "integrity": "sha512-PQIKZXlp3awCDn/xNlCSTFE7aYG/5Tx33M05NfQmWYeB5yV1GZZOSz4dXpwiNJYTXb9jPqjl+ueXXkwtEluFFA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.4.2.tgz", + "integrity": "sha512-yrj3c1g145uiK5io+1UPbJAHo8BSGORkBzrmzvAsOmBKb+1p3jmM8ZwNLDH/HTTxVLm9iM5rMszx+iAh1HUC4Q==", "dependencies": { - "@smithy/abort-controller": "^2.0.11", - "@smithy/protocol-http": "^3.0.7", - "@smithy/querystring-builder": "^2.0.11", - "@smithy/types": "^2.3.5", + "@smithy/abort-controller": "^2.1.4", + "@smithy/protocol-http": "^3.2.2", + "@smithy/querystring-builder": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2530,12 +2578,11 @@ } }, "node_modules/@smithy/property-provider": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.12.tgz", - "integrity": "sha512-Un/OvvuQ1Kg8WYtoMCicfsFFuHb/TKL3pCA6ZIo/WvNTJTR94RtoRnL7mY4XkkUAoFMyf6KjcQJ76y1FX7S5rw==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.1.4.tgz", + "integrity": "sha512-nWaY/MImj1BiXZ9WY65h45dcxOx8pl06KYoHxwojDxDL+Q9yLU1YnZpgv8zsHhEftlj9KhePENjQTlNowWVyug==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2543,11 +2590,11 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.7.tgz", - "integrity": "sha512-HnZW8y+r66ntYueCDbLqKwWcMNWW8o3eVpSrHNluwtBJ/EUWfQHRKSiu6vZZtc6PGfPQWgVfucoCE/C3QufMAA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.2.2.tgz", + "integrity": "sha512-xYBlllOQcOuLoxzhF2u8kRHhIFGQpDeTQj/dBSnw4kfI29WMKL5RnW1m9YjnJAJ49miuIvrkJR+gW5bCQ+Mchw==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2555,12 +2602,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.11.tgz", - "integrity": "sha512-b4kEbVMxpmfv2VWUITn2otckTi7GlMteZQxi+jlwedoATOGEyrCJPfRcYQJjbCi3fZ2QTfh3PcORvB27+j38Yg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.4.tgz", + "integrity": "sha512-LXSL0J/nRWvGT+jIj+Fip3j0J1ZmHkUyBFRzg/4SmPNCLeDrtVu7ptKOnTboPsFZu5BxmpYok3kJuQzzRdrhbw==", "dependencies": { - "@smithy/types": "^2.3.5", - "@smithy/util-uri-escape": "^2.0.0", + "@smithy/types": "^2.11.0", + "@smithy/util-uri-escape": "^2.1.1", "tslib": "^2.5.0" }, "engines": { @@ -2568,11 +2615,11 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.11.tgz", - "integrity": "sha512-YXe7jhi7s3dQ0Fu9dLoY/gLu6NCyy8tBWJL/v2c9i7/RLpHgKT+uT96/OqZkHizCJ4kr0ZD46tzMjql/o60KLg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.1.4.tgz", + "integrity": "sha512-U2b8olKXgZAs0eRo7Op11jTNmmcC/sqYmsA7vN6A+jkGnDvJlEl7AetUegbBzU8q3D6WzC5rhR/joIy8tXPzIg==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2580,24 +2627,22 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.4.tgz", - "integrity": "sha512-77506l12I5gxTZqBkx3Wb0RqMG81bMYLaVQ+EqIWFwQDJRs5UFeXogKxSKojCmz1wLUziHZQXm03MBzPQiumQw==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.4.tgz", + "integrity": "sha512-JW2Hthy21evnvDmYYk1kItOmbp3X5XI5iqorXgFEunb6hQfSDZ7O1g0Clyxg7k/Pcr9pfLk5xDIR2To/IohlsQ==", "dependencies": { - "@smithy/types": "^2.3.5" + "@smithy/types": "^2.11.0" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.0.tgz", - "integrity": "sha512-xFXqs4vAb5BdkzHSRrTapFoaqS4/3m/CGZzdw46fBjYZ0paYuLAoMY60ICCn1FfGirG+PiJ3eWcqJNe4/SkfyA==", - "peer": true, + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.3.5.tgz", + "integrity": "sha512-oI99+hOvsM8oAJtxAGmoL/YCcGXtbP0fjPseYGaNmJ4X5xOFTer0KPk7AIH3AL6c5AlYErivEi1X/X78HgTVIw==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2605,18 +2650,17 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.11.tgz", - "integrity": "sha512-EFVU1dT+2s8xi227l1A9O27edT/GNKvyAK6lZnIZ0zhIHq/jSLznvkk15aonGAM1kmhmZBVGpI7Tt0odueZK9A==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.1.4.tgz", + "integrity": "sha512-gnu9gCn0qQ8IdhNjs6o3QVCXzUs33znSDYwVMWo3nX4dM6j7z9u6FC302ShYyVWfO4MkVMuGCCJ6nl3PcH7V1Q==", "dependencies": { - "@smithy/eventstream-codec": "^2.0.11", - "@smithy/is-array-buffer": "^2.0.0", - "@smithy/types": "^2.3.5", - "@smithy/util-hex-encoding": "^2.0.0", - "@smithy/util-middleware": "^2.0.4", - "@smithy/util-uri-escape": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", + "@smithy/eventstream-codec": "^2.1.4", + "@smithy/is-array-buffer": "^2.1.1", + "@smithy/types": "^2.11.0", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-middleware": "^2.1.4", + "@smithy/util-uri-escape": "^2.1.1", + "@smithy/util-utf8": "^2.2.0", "tslib": "^2.5.0" }, "engines": { @@ -2624,13 +2668,15 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.10.tgz", - "integrity": "sha512-2OEmZDiW1Z196QHuQZ5M6cBE8FCSG0H2HADP1G+DY8P3agsvb0YJyfhyKuJbxIQy15tr3eDAK6FOrlbxgKOOew==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.4.4.tgz", + "integrity": "sha512-SNE17wjycPZIJ2P5sv6wMTteV/vQVPdaqQkoK1KeGoWHXx79t3iLhQXj1uqRdlkMUS9pXJrLOAS+VvUSOYwQKw==", "dependencies": { - "@smithy/middleware-stack": "^2.0.5", - "@smithy/types": "^2.3.5", - "@smithy/util-stream": "^2.0.15", + "@smithy/middleware-endpoint": "^2.4.6", + "@smithy/middleware-stack": "^2.1.4", + "@smithy/protocol-http": "^3.2.2", + "@smithy/types": "^2.11.0", + "@smithy/util-stream": "^2.1.4", "tslib": "^2.5.0" }, "engines": { @@ -2638,9 +2684,9 @@ } }, "node_modules/@smithy/types": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.5.tgz", - "integrity": "sha512-ehyDt8M9hehyxrLQGoA1BGPou8Js1Ocoh5M0ngDhJMqbFmNK5N6Xhr9/ZExWkyIW8XcGkiMPq3ZUEE0ScrhbuQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.11.0.tgz", + "integrity": "sha512-AR0SXO7FuAskfNhyGfSTThpLRntDI5bOrU0xrpVYU0rZyjl3LBXInZFMTP/NNSd7IS6Ksdtar0QvnrPRIhVrLQ==", "dependencies": { "tslib": "^2.5.0" }, @@ -2649,21 +2695,22 @@ } }, "node_modules/@smithy/url-parser": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.11.tgz", - "integrity": "sha512-h89yXMCCF+S5k9XIoKltMIWTYj+FcEkU/IIFZ6RtE222fskOTL4Iak6ZRG+ehSvZDt8yKEcxqheTDq7JvvtK3g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.1.4.tgz", + "integrity": "sha512-1hTy6UYRYqOZlHKH2/2NzdNQ4NNmW2Lp0sYYvztKy+dEQuLvZL9w88zCzFQqqFer3DMcscYOshImxkJTGdV+rg==", "dependencies": { - "@smithy/querystring-parser": "^2.0.11", - "@smithy/types": "^2.3.5", + "@smithy/querystring-parser": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" } }, "node_modules/@smithy/util-base64": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", - "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.2.0.tgz", + "integrity": "sha512-RiQI/Txu0SxCR38Ky5BMEVaFfkNTBjpbxlr2UhhxggSmnsHDQPZJWMtPoXs7TWZaseslIlAWMiHmqRT3AV/P2w==", "dependencies": { - "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-utf8": "^2.2.0", "tslib": "^2.5.0" }, "engines": { @@ -2671,19 +2718,17 @@ } }, "node_modules/@smithy/util-body-length-browser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", - "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", - "peer": true, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.1.1.tgz", + "integrity": "sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==", "dependencies": { "tslib": "^2.5.0" } }, "node_modules/@smithy/util-body-length-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", - "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", - "peer": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.2.1.tgz", + "integrity": "sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==", "dependencies": { "tslib": "^2.5.0" }, @@ -2692,11 +2737,11 @@ } }, "node_modules/@smithy/util-buffer-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", - "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz", + "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==", "dependencies": { - "@smithy/is-array-buffer": "^2.0.0", + "@smithy/is-array-buffer": "^2.1.1", "tslib": "^2.5.0" }, "engines": { @@ -2704,10 +2749,9 @@ } }, "node_modules/@smithy/util-config-provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", - "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", - "peer": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.2.1.tgz", + "integrity": "sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==", "dependencies": { "tslib": "^2.5.0" }, @@ -2716,14 +2760,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.14.tgz", - "integrity": "sha512-NupG7SWUucm3vJrvlpt9jG1XeoPJphjcivgcUUXhDJbUPy4F04LhlTiAhWSzwlCNcF8OJsMvZ/DWbpYD3pselw==", - "peer": true, + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.1.6.tgz", + "integrity": "sha512-lM2JMYCilrejfGf8WWnVfrKly3vf+mc5x9TrTpT++qIKP452uWfLqlaUxbz1TkSfhqm8RjrlY22589B9aI8A9w==", "dependencies": { - "@smithy/property-provider": "^2.0.12", - "@smithy/smithy-client": "^2.1.10", - "@smithy/types": "^2.3.5", + "@smithy/property-provider": "^2.1.4", + "@smithy/smithy-client": "^2.4.4", + "@smithy/types": "^2.11.0", "bowser": "^2.11.0", "tslib": "^2.5.0" }, @@ -2732,27 +2775,39 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.18.tgz", - "integrity": "sha512-+3jMom/b/Cdp21tDnY4vKu249Al+G/P0HbRbct7/aSZDlROzv1tksaYukon6UUv7uoHn+/McqnsvqZHLlqvQ0g==", - "peer": true, + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.2.6.tgz", + "integrity": "sha512-UmUbPHbkBJCXRFbq+FPLpVwiFPHj1oPWXJS2f2sy23PtXM94c9X5EceI6JKuKdBty+tzhrAs5JbmPM/HvmDB8Q==", "dependencies": { - "@smithy/config-resolver": "^2.0.14", - "@smithy/credential-provider-imds": "^2.0.16", - "@smithy/node-config-provider": "^2.1.1", - "@smithy/property-provider": "^2.0.12", - "@smithy/smithy-client": "^2.1.10", - "@smithy/types": "^2.3.5", + "@smithy/config-resolver": "^2.1.5", + "@smithy/credential-provider-imds": "^2.2.6", + "@smithy/node-config-provider": "^2.2.5", + "@smithy/property-provider": "^2.1.4", + "@smithy/smithy-client": "^2.4.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { "node": ">= 10.0.0" } }, + "node_modules/@smithy/util-endpoints": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.1.5.tgz", + "integrity": "sha512-tgDpaUNsUtRvNiBulKU1VnpoXU1GINMfZZXunRhUXOTBEAufG1Wp79uDXLau2gg1RZ4dpAR6lXCkrmddihCGUg==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.5", + "@smithy/types": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/@smithy/util-hex-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", - "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.1.1.tgz", + "integrity": "sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==", "dependencies": { "tslib": "^2.5.0" }, @@ -2761,11 +2816,11 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.4.tgz", - "integrity": "sha512-Pbu6P4MBwRcjrLgdTR1O4Y3c0sTZn2JdOiJNcgL7EcIStcQodj+6ZTXtbyU/WTEU3MV2NMA10LxFc3AWHZ3+4A==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.1.4.tgz", + "integrity": "sha512-5yYNOgCN0DL0OplME0pthoUR/sCfipnROkbTO7m872o0GHCVNJj5xOFJ143rvHNA54+pIPMLum4z2DhPC2pVGA==", "dependencies": { - "@smithy/types": "^2.3.5", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2773,13 +2828,12 @@ } }, "node_modules/@smithy/util-retry": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.4.tgz", - "integrity": "sha512-b+n1jBBKc77C1E/zfBe1Zo7S9OXGBiGn55N0apfhZHxPUP/fMH5AhFUUcWaJh7NAnah284M5lGkBKuhnr3yK5w==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.1.4.tgz", + "integrity": "sha512-JRZwhA3fhkdenSEYIWatC8oLwt4Bdf2LhHbNQApqb7yFoIGMl4twcYI3BcJZ7YIBZrACA9jGveW6tuCd836XzQ==", "dependencies": { - "@smithy/service-error-classification": "^2.0.4", - "@smithy/types": "^2.3.5", + "@smithy/service-error-classification": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2787,17 +2841,17 @@ } }, "node_modules/@smithy/util-stream": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.15.tgz", - "integrity": "sha512-A/hkYJPH2N5MCWYvky4tTpQihpYAEzqnUfxDyG3L/yMndy/2sLvxnyQal9Opuj1e9FiKSTeMyjnU9xxZGs0mRw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.1.4.tgz", + "integrity": "sha512-CiWaFPXstoR7v/PGHddFckovkhJb28wgQR7LwIt6RsQCJeRIHvUTVWhXw/Pco6Jm6nz/vfzN9FFdj/JN7RTkxQ==", "dependencies": { - "@smithy/fetch-http-handler": "^2.2.2", - "@smithy/node-http-handler": "^2.1.7", - "@smithy/types": "^2.3.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-buffer-from": "^2.0.0", - "@smithy/util-hex-encoding": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", + "@smithy/fetch-http-handler": "^2.4.4", + "@smithy/node-http-handler": "^2.4.2", + "@smithy/types": "^2.11.0", + "@smithy/util-base64": "^2.2.0", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-utf8": "^2.2.0", "tslib": "^2.5.0" }, "engines": { @@ -2805,9 +2859,9 @@ } }, "node_modules/@smithy/util-uri-escape": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", - "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", + "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", "dependencies": { "tslib": "^2.5.0" }, @@ -2816,11 +2870,11 @@ } }, "node_modules/@smithy/util-utf8": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", - "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.2.0.tgz", + "integrity": "sha512-hBsKr5BqrDrKS8qy+YcV7/htmMGxriA1PREOf/8AGBhHIZnfilVv1Waf1OyKhSbFW15U/8+gcMUQ9/Kk5qwpHQ==", "dependencies": { - "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-buffer-from": "^2.1.1", "tslib": "^2.5.0" }, "engines": { @@ -2828,13 +2882,12 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.11.tgz", - "integrity": "sha512-8SJWUl9O1YhjC77EccgltI3q4XZQp3vp9DGEW6o0OdkUcwqm/H4qOLnMkA2n+NDojuM5Iia2jWoCdbluIiG7TA==", - "peer": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.1.4.tgz", + "integrity": "sha512-AK17WaC0hx1wR9juAOsQkJ6DjDxBGEf5TrKhpXtNFEn+cVto9Li3MVsdpAO97AF7bhFXSyC8tJA3F4ThhqwCdg==", "dependencies": { - "@smithy/abort-controller": "^2.0.11", - "@smithy/types": "^2.3.5", + "@smithy/abort-controller": "^2.1.4", + "@smithy/types": "^2.11.0", "tslib": "^2.5.0" }, "engines": { @@ -2951,7 +3004,7 @@ "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "devOptional": true, + "dev": true, "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -2983,7 +3036,7 @@ "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "devOptional": true + "dev": true }, "node_modules/@types/quill": { "version": "1.3.10", @@ -2998,7 +3051,7 @@ "version": "17.0.73", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.73.tgz", "integrity": "sha512-6AcjgPIVsXTIsFDgsGW0iQhvg0xb2vt2qAWgXyncnVNRaW9ZXTTwAh7RQoh7PzK1AhjPoGDvUBkdAREih9n5oQ==", - "devOptional": true, + "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3065,7 +3118,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "devOptional": true + "dev": true }, "node_modules/@types/shortid": { "version": "0.0.29", @@ -3253,45 +3306,6 @@ "node": ">=4" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sdk": { - "version": "2.1555.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1555.0.tgz", - "integrity": "sha512-hjYs1MQkJxdHnoZm8hypqGy4PQKWVUs19McdXRXWNXr97V0il4xcUpIfvjHQ9x9EjP0p/jyIx9/BtyrR68jnUQ==", - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -3445,8 +3459,7 @@ "node_modules/bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "peer": true + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -3501,16 +3514,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4257,7 +4260,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "dev": true }, "node_modules/dashdash": { "version": "1.14.1", @@ -4589,14 +4592,6 @@ "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==", "dev": true }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/exact-trie": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/exact-trie/-/exact-trie-1.0.13.tgz", @@ -4726,7 +4721,6 @@ "url": "https://github.com/sponsors/NaturalIntelligence" } ], - "peer": true, "dependencies": { "strnum": "^1.0.5" }, @@ -4821,14 +4815,6 @@ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -5024,6 +5010,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -5111,6 +5098,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -5141,6 +5129,7 @@ "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" } @@ -5148,7 +5137,8 @@ "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==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "node_modules/hotkeys-js": { "version": "3.13.2", @@ -5297,6 +5287,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5326,17 +5317,6 @@ "node": ">=8" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-core-module": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", @@ -5381,20 +5361,6 @@ "node": ">=8" } }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -5438,20 +5404,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -5475,14 +5427,6 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, - "node_modules/jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/jose": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", @@ -6628,15 +6572,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6731,35 +6666,6 @@ "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==", "dev": true }, - "node_modules/react-dnd": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", - "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", - "dependencies": { - "@react-dnd/invariant": "^4.0.1", - "@react-dnd/shallowequal": "^4.0.1", - "dnd-core": "^16.0.1", - "fast-deep-equal": "^3.1.3", - "hoist-non-react-statics": "^3.3.2" - }, - "peerDependencies": { - "@types/hoist-non-react-statics": ">= 3.3.1", - "@types/node": ">= 12", - "@types/react": ">= 16", - "react": ">= 16.14" - }, - "peerDependenciesMeta": { - "@types/hoist-non-react-statics": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, "node_modules/react-dnd-html5-backend": { "version": "11.1.3", "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz", @@ -6769,26 +6675,6 @@ "dnd-core": "^11.1.3" } }, - "node_modules/react-dnd/node_modules/@react-dnd/asap": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", - "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" - }, - "node_modules/react-dnd/node_modules/@react-dnd/invariant": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", - "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" - }, - "node_modules/react-dnd/node_modules/dnd-core": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", - "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", - "dependencies": { - "@react-dnd/asap": "^5.0.1", - "@react-dnd/invariant": "^4.0.1", - "redux": "^4.2.0" - } - }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -7060,6 +6946,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dev": true, "dependencies": { "@babel/runtime": "^7.9.2" } @@ -7085,7 +6972,8 @@ "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", @@ -7309,11 +7197,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -7702,8 +7585,7 @@ "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "peer": true + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, "node_modules/styled-components": { "version": "5.3.11", @@ -7993,32 +7875,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -8134,24 +7990,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -8202,26 +8040,6 @@ } } }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", diff --git a/package.json b/package.json index 74ce608..3332706 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,9 @@ "vite": "^5.1.1" }, "dependencies": { + "@aws-sdk/client-s3": "^3.529.1", + "@aws-sdk/s3-request-presigner": "^3.529.1", "@kubernetes/client-node": "^0.20.0", - "aws-sdk": "^2.1555.0", "basic-ftp": "^5.0.4", "bcrypt": "^5.1.1", "chalk": "^5.3.0", diff --git a/src/components/servers/BackupsDialog.jsx b/src/components/servers/BackupsDialog.jsx new file mode 100644 index 0000000..dff558b --- /dev/null +++ b/src/components/servers/BackupsDialog.jsx @@ -0,0 +1,88 @@ +import { useEffect, 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 IconButton from "@mui/material/IconButton"; +import Toolbar from "@mui/material/Toolbar"; +import Typography from "@mui/material/Typography"; +import Stack from "@mui/material/Stack"; +import DownloadIcon from "@mui/icons-material/Download"; +import { getBackupUrl, getServerBackups } from "../../util/queries"; + +export function useBackupDialog(isOpen = false) { + const [open, setOpen] = useState(isOpen); + const dialogToggle = () => setOpen(!open); + return [open, dialogToggle]; +} + +export default function BackupDialog(props) { + const { serverId, open, dialogToggle } = props; + const theme = useTheme(); + const fullScreen = useMediaQuery(theme.breakpoints.down("md")); + const [backups, setBackups] = useState([]); + + function refreshUpdateList() { + getServerBackups(serverId).then(setBackups); + } + useEffect(() => { + if (!serverId) return; + refreshUpdateList(); + }, [serverId, open]); + + function normalizeLastModified(lastModified) { + const d = new Date(Date.parse(lastModified)); + return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()} ${d.getHours()}:${d.getMinutes()}`; + } + + const downloadBackup = (backup) => + async function openBackupLink() { + const { url } = await getBackupUrl(serverId, backup.path); + window.open(url, "_blank").focus(); + }; + + const normalizedSize = (size) => `${(size / Math.pow(1024, 3)).toFixed(2)}GB`; + + return ( + + + Backups + + {backups.map((backup, i) => ( + + + {backup.name} + + + {normalizeLastModified(backup.lastModified)} + + + {normalizedSize(backup.size)} + + + + + + + ))} + + + + + + ); +} diff --git a/src/components/servers/RconView.jsx b/src/components/servers/RconView.jsx index 8bbccbd..1eafe22 100644 --- a/src/components/servers/RconView.jsx +++ b/src/components/servers/RconView.jsx @@ -61,6 +61,7 @@ export default function RconView(props) { color: "white", borderRadius: "4px", width: "100%", + height: "100%", }} > {logs.length === 0 && diff --git a/src/components/servers/ServerCard.jsx b/src/components/servers/ServerCard.jsx index ac0ffd0..0b6f724 100644 --- a/src/components/servers/ServerCard.jsx +++ b/src/components/servers/ServerCard.jsx @@ -14,10 +14,11 @@ import PlayArrowIcon from "@mui/icons-material/PlayArrow"; import DeleteForeverIcon from "@mui/icons-material/DeleteForever"; import EditIcon from "@mui/icons-material/Edit"; import FolderIcon from "@mui/icons-material/Folder"; +import BackupIcon from "@mui/icons-material/Backup"; import { Link } from "react-router-dom"; export default function ServerCard(props) { - const { server, openRcon } = props; + const { server, openRcon, openBackups } = props; const { name, id, metrics, ftpAvailable, serverAvailable, services } = server; const startServer = useStartServer(id); const stopServer = useStopServer(id); @@ -117,6 +118,14 @@ export default function ServerCard(props) { > + + + { @@ -31,6 +35,11 @@ export default function Home() { rconToggle(); }; + const openBackups = (s) => () => { + setServer(s); + backupsToggle(); + }; + return ( @@ -51,10 +60,20 @@ export default function Home() { {!isLoading && servers.map((s, k) => ( - + ))} +