diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index af33bdf..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,145 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-.pnpm-debug.log*
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-web_modules/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Microbundle cache
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variable files
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
-
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-.parcel-cache
-
-# Next.js build output
-.next
-out
-
-# Nuxt.js build / generate output
-.nuxt
-dist
-
-# Gatsby files
-.cache/
-# Comment in the public line in if your project uses Gatsby and not Next.js
-# https://nextjs.org/blog/next-9-1#public-directory-support
-# public
-
-# vuepress build output
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-.temp
-.cache
-
-# vitepress build output
-**/.vitepress/dist
-
-# vitepress cache directory
-**/.vitepress/cache
-
-# Docusaurus cache and generated files
-.docusaurus
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# TernJS port file
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-.vscode-test
-
-# yarn v2
-.yarn/cache
-.yarn/unplugged
-.yarn/build-state.yml
-.yarn/install-state.gz
-.pnp.*
-
-# Vscode files
-.vscode
-
-# Data
-data/*
-
-# Temporary
-tests/
\ No newline at end of file
diff --git a/README.md b/README.md
index 39629d9..f37f6ac 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ First make sure you have the following dependencies installed:
- **Node.js**
- **pnpm**
-Then download all needed packages using
+Then, for each of frontend and backend, download all needed packages using
```sh
pnpm install
```
@@ -28,7 +28,7 @@ node server.js
## 🔧 Configuration
-All settings are located in [config/config.json](config/config.json). For more explainations and possible values, give a look to the documentation (incomming).
+All settings are located in [backend/config/config.json](backend/config/config.json). For more explainations and possible values, give a look to the documentation (incomming).
## 🔗 Documentation
diff --git a/config/config.json b/config/config.json
deleted file mode 100644
index a060d02..0000000
--- a/config/config.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "port": 8000,
-
- "users": {
- "admin": {
- "username": "admin",
- "password": "admin"
- }
- },
-
- "database": {
- "type": "sqlite"
- },
-
- "auth": {
- "JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY",
- "tokenExpiry": "1h"
- }
-}
\ No newline at end of file
diff --git a/frontend/.gitignore b/frontend/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/frontend/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..ae54c6f
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Preact
+
+
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..18b808f
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "wf-radio-frontend",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "preact": "^10.26.5"
+ },
+ "devDependencies": {
+ "@preact/preset-vite": "^2.10.1",
+ "vite": "^6.3.5"
+ }
+}
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
new file mode 100644
index 0000000..891187e
--- /dev/null
+++ b/frontend/pnpm-lock.yaml
@@ -0,0 +1,1188 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ preact:
+ specifier: ^10.26.5
+ version: 10.26.6
+ devDependencies:
+ '@preact/preset-vite':
+ specifier: ^2.10.1
+ version: 2.10.1(@babel/core@7.27.1)(preact@10.26.6)(vite@6.3.5)
+ vite:
+ specifier: ^6.3.5
+ version: 6.3.5
+
+packages:
+
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.27.2':
+ resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.27.1':
+ resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.27.1':
+ resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-annotate-as-pure@7.27.1':
+ resolution: {integrity: sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.27.1':
+ resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.27.1':
+ resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.27.2':
+ resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-syntax-jsx@7.27.1':
+ resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-development@7.27.1':
+ resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx@7.27.1':
+ resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.27.1':
+ resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.27.1':
+ resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@esbuild/aix-ppc64@0.25.4':
+ resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.4':
+ resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.4':
+ resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.4':
+ resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.4':
+ resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.4':
+ resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.4':
+ resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.4':
+ resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.4':
+ resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.4':
+ resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.4':
+ resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.4':
+ resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.4':
+ resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.4':
+ resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.4':
+ resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.4':
+ resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.4':
+ resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.4':
+ resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.4':
+ resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.4':
+ resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.4':
+ resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.25.4':
+ resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.4':
+ resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.4':
+ resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.4':
+ resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/gen-mapping@0.3.8':
+ resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+ '@preact/preset-vite@2.10.1':
+ resolution: {integrity: sha512-59lyGBXNfZIr5OOuBUB4/IB8AqF/ULbvYnyItgK/2BJnsGJqaeaJobRVtMp1129obHQuj8oZ/dVxB9inmH8Xig==}
+ peerDependencies:
+ '@babel/core': 7.x
+ vite: 2.x || 3.x || 4.x || 5.x || 6.x
+
+ '@prefresh/babel-plugin@0.5.1':
+ resolution: {integrity: sha512-uG3jGEAysxWoyG3XkYfjYHgaySFrSsaEb4GagLzYaxlydbuREtaX+FTxuIidp241RaLl85XoHg9Ej6E4+V1pcg==}
+
+ '@prefresh/core@1.5.3':
+ resolution: {integrity: sha512-nDzxj0tA1/M6APNAWqaxkZ+3sTdPHESa+gol4+Bw7rMc2btWdkLoNH7j9rGhUb8SThC0Vz0VoXtq+U+9azGLHg==}
+ peerDependencies:
+ preact: ^10.0.0
+
+ '@prefresh/utils@1.2.0':
+ resolution: {integrity: sha512-KtC/fZw+oqtwOLUFM9UtiitB0JsVX0zLKNyRTA332sqREqSALIIQQxdUCS1P3xR/jT1e2e8/5rwH6gdcMLEmsQ==}
+
+ '@prefresh/vite@2.4.7':
+ resolution: {integrity: sha512-zmCEDWSFHl5A7PciXa/fe+OUjoGi4iiCQclpWfpIg7LjxwWrtlUT4DfxDBcQwHfTyipS/XDm8x7WYrkiTW0q+w==}
+ peerDependencies:
+ preact: ^10.4.0
+ vite: '>=2.0.0'
+
+ '@rollup/pluginutils@4.2.1':
+ resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
+ engines: {node: '>= 8.0.0'}
+
+ '@rollup/rollup-android-arm-eabi@4.40.2':
+ resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.40.2':
+ resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.40.2':
+ resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.40.2':
+ resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.40.2':
+ resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.40.2':
+ resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.2':
+ resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.40.2':
+ resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.40.2':
+ resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.40.2':
+ resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
+ resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
+ resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.40.2':
+ resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.40.2':
+ resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.2':
+ resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.40.2':
+ resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.40.2':
+ resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.40.2':
+ resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.40.2':
+ resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.40.2':
+ resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+
+ babel-plugin-transform-hook-names@1.0.2:
+ resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==}
+ peerDependencies:
+ '@babel/core': ^7.12.10
+
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+ browserslist@4.24.5:
+ resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ caniuse-lite@1.0.30001717:
+ resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ css-select@5.1.0:
+ resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+
+ css-what@6.1.0:
+ resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+ engines: {node: '>= 6'}
+
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
+ electron-to-chromium@1.5.151:
+ resolution: {integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ esbuild@0.25.4:
+ resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ fdir@6.4.4:
+ resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+
+ he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ kolorist@1.8.0:
+ resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ magic-string@0.30.17:
+ resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-html-parser@6.1.13:
+ resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==}
+
+ node-releases@2.0.19:
+ resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.2:
+ resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.3:
+ resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ preact@10.26.6:
+ resolution: {integrity: sha512-5SRRBinwpwkaD+OqlBDeITlRgvd8I8QlxHJw9AxSdMNV6O+LodN9nUyYGpSF7sadHjs6RzeFShMexC6DbtWr9g==}
+
+ rollup@4.40.2:
+ resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ simple-code-frame@1.3.0:
+ resolution: {integrity: sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.7.4:
+ resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
+ engines: {node: '>= 8'}
+
+ stack-trace@1.0.0-pre2:
+ resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==}
+ engines: {node: '>=16'}
+
+ tinyglobby@0.2.13:
+ resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
+ engines: {node: '>=12.0.0'}
+
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ vite-prerender-plugin@0.5.10:
+ resolution: {integrity: sha512-m4i0G5oc3LPLA02uW2XsFZmYNxZdyryz5Ksi78O9puj/ao5c8dBUW06caGwoM1TmYknTBBUyKhtqajUpoP+z8Q==}
+ peerDependencies:
+ vite: 5.x || 6.x
+
+ vite@6.3.5:
+ resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+snapshots:
+
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.27.2': {}
+
+ '@babel/core@7.27.1':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.1
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1)
+ '@babel/helpers': 7.27.1
+ '@babel/parser': 7.27.2
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.27.1
+ '@babel/types': 7.27.1
+ convert-source-map: 2.0.0
+ debug: 4.4.0
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.27.1':
+ dependencies:
+ '@babel/parser': 7.27.2
+ '@babel/types': 7.27.1
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.1.0
+
+ '@babel/helper-annotate-as-pure@7.27.1':
+ dependencies:
+ '@babel/types': 7.27.1
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.27.2
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.24.5
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.27.1
+ '@babel/types': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.27.1':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.1
+
+ '@babel/parser@7.27.2':
+ dependencies:
+ '@babel/types': 7.27.1
+
+ '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.27.1)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.27.1)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/helper-annotate-as-pure': 7.27.1
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-plugin-utils': 7.27.1
+ '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1)
+ '@babel/types': 7.27.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.27.2
+ '@babel/types': 7.27.1
+
+ '@babel/traverse@7.27.1':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.1
+ '@babel/parser': 7.27.2
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.1
+ debug: 4.4.0
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.27.1':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@esbuild/aix-ppc64@0.25.4':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/android-arm@0.25.4':
+ optional: true
+
+ '@esbuild/android-x64@0.25.4':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.4':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.4':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.4':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.4':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.4':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.4':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.4':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.4':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.4':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.4':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.4':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.4':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.4':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.8':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ '@preact/preset-vite@2.10.1(@babel/core@7.27.1)(preact@10.26.6)(vite@6.3.5)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.27.1)
+ '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.27.1)
+ '@prefresh/vite': 2.4.7(preact@10.26.6)(vite@6.3.5)
+ '@rollup/pluginutils': 4.2.1
+ babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.27.1)
+ debug: 4.4.0
+ kolorist: 1.8.0
+ vite: 6.3.5
+ vite-prerender-plugin: 0.5.10(vite@6.3.5)
+ transitivePeerDependencies:
+ - preact
+ - supports-color
+
+ '@prefresh/babel-plugin@0.5.1': {}
+
+ '@prefresh/core@1.5.3(preact@10.26.6)':
+ dependencies:
+ preact: 10.26.6
+
+ '@prefresh/utils@1.2.0': {}
+
+ '@prefresh/vite@2.4.7(preact@10.26.6)(vite@6.3.5)':
+ dependencies:
+ '@babel/core': 7.27.1
+ '@prefresh/babel-plugin': 0.5.1
+ '@prefresh/core': 1.5.3(preact@10.26.6)
+ '@prefresh/utils': 1.2.0
+ '@rollup/pluginutils': 4.2.1
+ preact: 10.26.6
+ vite: 6.3.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@rollup/pluginutils@4.2.1':
+ dependencies:
+ estree-walker: 2.0.2
+ picomatch: 2.3.1
+
+ '@rollup/rollup-android-arm-eabi@4.40.2':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.40.2':
+ optional: true
+
+ '@types/estree@1.0.7': {}
+
+ babel-plugin-transform-hook-names@1.0.2(@babel/core@7.27.1):
+ dependencies:
+ '@babel/core': 7.27.1
+
+ boolbase@1.0.0: {}
+
+ browserslist@4.24.5:
+ dependencies:
+ caniuse-lite: 1.0.30001717
+ electron-to-chromium: 1.5.151
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.3(browserslist@4.24.5)
+
+ caniuse-lite@1.0.30001717: {}
+
+ convert-source-map@2.0.0: {}
+
+ css-select@5.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.1.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ nth-check: 2.1.1
+
+ css-what@6.1.0: {}
+
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
+ electron-to-chromium@1.5.151: {}
+
+ entities@4.5.0: {}
+
+ esbuild@0.25.4:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.4
+ '@esbuild/android-arm': 0.25.4
+ '@esbuild/android-arm64': 0.25.4
+ '@esbuild/android-x64': 0.25.4
+ '@esbuild/darwin-arm64': 0.25.4
+ '@esbuild/darwin-x64': 0.25.4
+ '@esbuild/freebsd-arm64': 0.25.4
+ '@esbuild/freebsd-x64': 0.25.4
+ '@esbuild/linux-arm': 0.25.4
+ '@esbuild/linux-arm64': 0.25.4
+ '@esbuild/linux-ia32': 0.25.4
+ '@esbuild/linux-loong64': 0.25.4
+ '@esbuild/linux-mips64el': 0.25.4
+ '@esbuild/linux-ppc64': 0.25.4
+ '@esbuild/linux-riscv64': 0.25.4
+ '@esbuild/linux-s390x': 0.25.4
+ '@esbuild/linux-x64': 0.25.4
+ '@esbuild/netbsd-arm64': 0.25.4
+ '@esbuild/netbsd-x64': 0.25.4
+ '@esbuild/openbsd-arm64': 0.25.4
+ '@esbuild/openbsd-x64': 0.25.4
+ '@esbuild/sunos-x64': 0.25.4
+ '@esbuild/win32-arm64': 0.25.4
+ '@esbuild/win32-ia32': 0.25.4
+ '@esbuild/win32-x64': 0.25.4
+
+ escalade@3.2.0: {}
+
+ estree-walker@2.0.2: {}
+
+ fdir@6.4.4(picomatch@4.0.2):
+ optionalDependencies:
+ picomatch: 4.0.2
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ globals@11.12.0: {}
+
+ he@1.2.0: {}
+
+ js-tokens@4.0.0: {}
+
+ jsesc@3.1.0: {}
+
+ json5@2.2.3: {}
+
+ kolorist@1.8.0: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ magic-string@0.30.17:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ node-html-parser@6.1.13:
+ dependencies:
+ css-select: 5.1.0
+ he: 1.2.0
+
+ node-releases@2.0.19: {}
+
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ picomatch@4.0.2: {}
+
+ postcss@8.5.3:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ preact@10.26.6: {}
+
+ rollup@4.40.2:
+ dependencies:
+ '@types/estree': 1.0.7
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.40.2
+ '@rollup/rollup-android-arm64': 4.40.2
+ '@rollup/rollup-darwin-arm64': 4.40.2
+ '@rollup/rollup-darwin-x64': 4.40.2
+ '@rollup/rollup-freebsd-arm64': 4.40.2
+ '@rollup/rollup-freebsd-x64': 4.40.2
+ '@rollup/rollup-linux-arm-gnueabihf': 4.40.2
+ '@rollup/rollup-linux-arm-musleabihf': 4.40.2
+ '@rollup/rollup-linux-arm64-gnu': 4.40.2
+ '@rollup/rollup-linux-arm64-musl': 4.40.2
+ '@rollup/rollup-linux-loongarch64-gnu': 4.40.2
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2
+ '@rollup/rollup-linux-riscv64-gnu': 4.40.2
+ '@rollup/rollup-linux-riscv64-musl': 4.40.2
+ '@rollup/rollup-linux-s390x-gnu': 4.40.2
+ '@rollup/rollup-linux-x64-gnu': 4.40.2
+ '@rollup/rollup-linux-x64-musl': 4.40.2
+ '@rollup/rollup-win32-arm64-msvc': 4.40.2
+ '@rollup/rollup-win32-ia32-msvc': 4.40.2
+ '@rollup/rollup-win32-x64-msvc': 4.40.2
+ fsevents: 2.3.3
+
+ semver@6.3.1: {}
+
+ simple-code-frame@1.3.0:
+ dependencies:
+ kolorist: 1.8.0
+
+ source-map-js@1.2.1: {}
+
+ source-map@0.7.4: {}
+
+ stack-trace@1.0.0-pre2: {}
+
+ tinyglobby@0.2.13:
+ dependencies:
+ fdir: 6.4.4(picomatch@4.0.2)
+ picomatch: 4.0.2
+
+ update-browserslist-db@1.1.3(browserslist@4.24.5):
+ dependencies:
+ browserslist: 4.24.5
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ vite-prerender-plugin@0.5.10(vite@6.3.5):
+ dependencies:
+ kolorist: 1.8.0
+ magic-string: 0.30.17
+ node-html-parser: 6.1.13
+ simple-code-frame: 1.3.0
+ source-map: 0.7.4
+ stack-trace: 1.0.0-pre2
+ vite: 6.3.5
+
+ vite@6.3.5:
+ dependencies:
+ esbuild: 0.25.4
+ fdir: 6.4.4(picomatch@4.0.2)
+ picomatch: 4.0.2
+ postcss: 8.5.3
+ rollup: 4.40.2
+ tinyglobby: 0.2.13
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ yallist@3.1.1: {}
diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml
new file mode 100644
index 0000000..efc037a
--- /dev/null
+++ b/frontend/pnpm-workspace.yaml
@@ -0,0 +1,2 @@
+onlyBuiltDependencies:
+ - esbuild
diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/frontend/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/app.jsx b/frontend/src/app.jsx
new file mode 100644
index 0000000..9efff17
--- /dev/null
+++ b/frontend/src/app.jsx
@@ -0,0 +1,43 @@
+import { useState } from 'preact/hooks'
+import preactLogo from './assets/preact.svg'
+import viteLogo from '/vite.svg'
+import './styles/app.css'
+
+export function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+ <>
+
+ Vite + Preact
+
+
+
+ Edit src/app.jsx
and save to test HMR
+
+
+
+ Check out{' '}
+
+ create-preact
+
+ , the official Preact + Vite starter
+
+
+ Click on the Vite and Preact logos to learn more
+
+ >
+ )
+}
diff --git a/frontend/src/assets/preact.svg b/frontend/src/assets/preact.svg
new file mode 100644
index 0000000..908f17d
--- /dev/null
+++ b/frontend/src/assets/preact.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
new file mode 100644
index 0000000..008c962
--- /dev/null
+++ b/frontend/src/main.jsx
@@ -0,0 +1,5 @@
+import { render } from 'preact'
+import './styles/index.css'
+import { App } from './app.jsx'
+
+render(, document.getElementById('app'))
diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css
new file mode 100644
index 0000000..088ed3a
--- /dev/null
+++ b/frontend/src/styles/app.css
@@ -0,0 +1,25 @@
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.preact:hover {
+ filter: drop-shadow(0 0 2em #673ab8aa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/frontend/src/styles/index.css b/frontend/src/styles/index.css
new file mode 100644
index 0000000..08a3ac9
--- /dev/null
+++ b/frontend/src/styles/index.css
@@ -0,0 +1,68 @@
+:root {
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
new file mode 100644
index 0000000..b995c32
--- /dev/null
+++ b/frontend/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [preact()],
+})
diff --git a/package.json b/package.json
deleted file mode 100644
index 1facd76..0000000
--- a/package.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "name": "wf-radio",
- "version": "1.0.0",
- "description": "",
- "main": "server.js",
- "scripts": {
- "start": "node server.js",
- "start-auto": "pnpx nodemon server.js",
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "packageManager": "pnpm@10.5.2",
- "dependencies": {
- "ajv": "^8.17.1",
- "bcrypt": "^5.1.1",
- "better-sqlite3": "^11.9.1",
- "dompurify": "^3.2.4",
- "express": "^5.1.0",
- "jsdom": "^26.0.0",
- "jsonwebtoken": "^9.0.2",
- "marked": "^15.0.7",
- "mysql": "^2.18.1"
- },
- "pnpm": {
- "onlyBuiltDependencies": [
- "bcrypt",
- "better-sqlite3"
- ]
- },
- "devDependencies": {
- "nodemon": "^3.1.9"
- }
-}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
deleted file mode 100644
index d1d6f0f..0000000
--- a/pnpm-lock.yaml
+++ /dev/null
@@ -1,1884 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- ajv:
- specifier: ^8.17.1
- version: 8.17.1
- bcrypt:
- specifier: ^5.1.1
- version: 5.1.1
- better-sqlite3:
- specifier: ^11.9.1
- version: 11.9.1
- dompurify:
- specifier: ^3.2.4
- version: 3.2.5
- express:
- specifier: ^5.1.0
- version: 5.1.0
- jsdom:
- specifier: ^26.0.0
- version: 26.1.0
- jsonwebtoken:
- specifier: ^9.0.2
- version: 9.0.2
- marked:
- specifier: ^15.0.7
- version: 15.0.10
- mysql:
- specifier: ^2.18.1
- version: 2.18.1
- devDependencies:
- nodemon:
- specifier: ^3.1.9
- version: 3.1.10
-
-packages:
-
- '@asamuzakjp/css-color@3.1.4':
- resolution: {integrity: sha512-SeuBV4rnjpFNjI8HSgKUwteuFdkHwkboq31HWzznuqgySQir+jSTczoWVVL4jvOjKjuH80fMDG0Fvg1Sb+OJsA==}
-
- '@csstools/color-helpers@5.0.2':
- resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
- engines: {node: '>=18'}
-
- '@csstools/css-calc@2.1.3':
- resolution: {integrity: sha512-XBG3talrhid44BY1x3MHzUx/aTG8+x/Zi57M4aTKK9RFB4aLlF3TTSzfzn8nWVHWL3FgAXAxmupmDd6VWww+pw==}
- engines: {node: '>=18'}
- peerDependencies:
- '@csstools/css-parser-algorithms': ^3.0.4
- '@csstools/css-tokenizer': ^3.0.3
-
- '@csstools/css-color-parser@3.0.9':
- resolution: {integrity: sha512-wILs5Zk7BU86UArYBJTPy/FMPPKVKHMj1ycCEyf3VUptol0JNRLFU/BZsJ4aiIHJEbSLiizzRrw8Pc1uAEDrXw==}
- engines: {node: '>=18'}
- peerDependencies:
- '@csstools/css-parser-algorithms': ^3.0.4
- '@csstools/css-tokenizer': ^3.0.3
-
- '@csstools/css-parser-algorithms@3.0.4':
- resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==}
- engines: {node: '>=18'}
- peerDependencies:
- '@csstools/css-tokenizer': ^3.0.3
-
- '@csstools/css-tokenizer@3.0.3':
- resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==}
- engines: {node: '>=18'}
-
- '@mapbox/node-pre-gyp@1.0.11':
- resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
- hasBin: true
-
- '@types/trusted-types@2.0.7':
- resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
-
- abbrev@1.1.1:
- resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
-
- accepts@2.0.0:
- resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
- engines: {node: '>= 0.6'}
-
- agent-base@6.0.2:
- resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
- engines: {node: '>= 6.0.0'}
-
- agent-base@7.1.3:
- resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
- engines: {node: '>= 14'}
-
- ajv@8.17.1:
- resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
-
- ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
-
- anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
-
- aproba@2.0.0:
- resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
-
- are-we-there-yet@2.0.0:
- resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
- engines: {node: '>=10'}
- deprecated: This package is no longer supported.
-
- balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
- base64-js@1.5.1:
- resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
-
- bcrypt@5.1.1:
- resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==}
- engines: {node: '>= 10.0.0'}
-
- better-sqlite3@11.9.1:
- resolution: {integrity: sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==}
-
- bignumber.js@9.0.0:
- resolution: {integrity: sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==}
-
- binary-extensions@2.3.0:
- resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
- engines: {node: '>=8'}
-
- bindings@1.5.0:
- resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
-
- bl@4.1.0:
- resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
-
- body-parser@2.2.0:
- resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
- engines: {node: '>=18'}
-
- brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
-
- braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
-
- buffer-equal-constant-time@1.0.1:
- resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
-
- buffer@5.7.1:
- resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
-
- bytes@3.1.2:
- resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
- engines: {node: '>= 0.8'}
-
- call-bind-apply-helpers@1.0.2:
- resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
- engines: {node: '>= 0.4'}
-
- call-bound@1.0.4:
- resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
- engines: {node: '>= 0.4'}
-
- chokidar@3.6.0:
- resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
- engines: {node: '>= 8.10.0'}
-
- chownr@1.1.4:
- resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
-
- chownr@2.0.0:
- resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
- engines: {node: '>=10'}
-
- color-support@1.1.3:
- resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
- hasBin: true
-
- concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
- console-control-strings@1.1.0:
- resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
-
- content-disposition@1.0.0:
- resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
- engines: {node: '>= 0.6'}
-
- content-type@1.0.5:
- resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
- engines: {node: '>= 0.6'}
-
- cookie-signature@1.2.2:
- resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
- engines: {node: '>=6.6.0'}
-
- cookie@0.7.2:
- resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
- engines: {node: '>= 0.6'}
-
- core-util-is@1.0.3:
- resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
-
- cssstyle@4.3.1:
- resolution: {integrity: sha512-ZgW+Jgdd7i52AaLYCriF8Mxqft0gD/R9i9wi6RWBhs1pqdPEzPjym7rvRKi397WmQFf3SlyUsszhw+VVCbx79Q==}
- engines: {node: '>=18'}
-
- data-urls@5.0.0:
- resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
- engines: {node: '>=18'}
-
- debug@4.4.0:
- resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
-
- decimal.js@10.5.0:
- resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
-
- decompress-response@6.0.0:
- resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
- engines: {node: '>=10'}
-
- deep-extend@0.6.0:
- resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
- engines: {node: '>=4.0.0'}
-
- delegates@1.0.0:
- resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
-
- depd@2.0.0:
- resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
- engines: {node: '>= 0.8'}
-
- detect-libc@2.0.4:
- resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
- engines: {node: '>=8'}
-
- dompurify@3.2.5:
- resolution: {integrity: sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==}
-
- dunder-proto@1.0.1:
- resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
- engines: {node: '>= 0.4'}
-
- ecdsa-sig-formatter@1.0.11:
- resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
-
- ee-first@1.1.1:
- resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
-
- emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
-
- encodeurl@2.0.0:
- resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
- engines: {node: '>= 0.8'}
-
- end-of-stream@1.4.4:
- resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
-
- entities@6.0.0:
- resolution: {integrity: sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==}
- engines: {node: '>=0.12'}
-
- es-define-property@1.0.1:
- resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
- engines: {node: '>= 0.4'}
-
- es-errors@1.3.0:
- resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
- engines: {node: '>= 0.4'}
-
- es-object-atoms@1.1.1:
- resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
- engines: {node: '>= 0.4'}
-
- escape-html@1.0.3:
- resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
-
- etag@1.8.1:
- resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
- engines: {node: '>= 0.6'}
-
- expand-template@2.0.3:
- resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
- engines: {node: '>=6'}
-
- express@5.1.0:
- resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
- engines: {node: '>= 18'}
-
- fast-deep-equal@3.1.3:
- resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-
- fast-uri@3.0.6:
- resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
-
- file-uri-to-path@1.0.0:
- resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
-
- fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
-
- finalhandler@2.1.0:
- resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
- engines: {node: '>= 0.8'}
-
- forwarded@0.2.0:
- resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
- engines: {node: '>= 0.6'}
-
- fresh@2.0.0:
- resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
- engines: {node: '>= 0.8'}
-
- fs-constants@1.0.0:
- resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
-
- fs-minipass@2.1.0:
- resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
- engines: {node: '>= 8'}
-
- fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
-
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
-
- function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
-
- gauge@3.0.2:
- resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
- engines: {node: '>=10'}
- deprecated: This package is no longer supported.
-
- get-intrinsic@1.3.0:
- resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
- engines: {node: '>= 0.4'}
-
- get-proto@1.0.1:
- resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
- engines: {node: '>= 0.4'}
-
- github-from-package@0.0.0:
- resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
-
- glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
-
- glob@7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- deprecated: Glob versions prior to v9 are no longer supported
-
- gopd@1.2.0:
- resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
- engines: {node: '>= 0.4'}
-
- has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
-
- has-symbols@1.1.0:
- resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
- engines: {node: '>= 0.4'}
-
- has-unicode@2.0.1:
- resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
-
- hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
-
- html-encoding-sniffer@4.0.0:
- resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
- engines: {node: '>=18'}
-
- http-errors@2.0.0:
- resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
- engines: {node: '>= 0.8'}
-
- http-proxy-agent@7.0.2:
- resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
- engines: {node: '>= 14'}
-
- https-proxy-agent@5.0.1:
- resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
- engines: {node: '>= 6'}
-
- https-proxy-agent@7.0.6:
- resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
- engines: {node: '>= 14'}
-
- iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
-
- ieee754@1.2.1:
- resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
-
- ignore-by-default@1.0.1:
- resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
-
- inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
-
- inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-
- ini@1.3.8:
- resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
-
- ipaddr.js@1.9.1:
- resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
- engines: {node: '>= 0.10'}
-
- is-binary-path@2.1.0:
- resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
- engines: {node: '>=8'}
-
- is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
-
- is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
-
- is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
-
- is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
-
- is-potential-custom-element-name@1.0.1:
- resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
-
- is-promise@4.0.0:
- resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
-
- isarray@1.0.0:
- resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
-
- jsdom@26.1.0:
- resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==}
- engines: {node: '>=18'}
- peerDependencies:
- canvas: ^3.0.0
- peerDependenciesMeta:
- canvas:
- optional: true
-
- json-schema-traverse@1.0.0:
- resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
-
- jsonwebtoken@9.0.2:
- resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
- engines: {node: '>=12', npm: '>=6'}
-
- jwa@1.4.1:
- resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
-
- jws@3.2.2:
- resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
-
- lodash.includes@4.3.0:
- resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
-
- lodash.isboolean@3.0.3:
- resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
-
- lodash.isinteger@4.0.4:
- resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
-
- lodash.isnumber@3.0.3:
- resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
-
- lodash.isplainobject@4.0.6:
- resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
-
- lodash.isstring@4.0.1:
- resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
-
- lodash.once@4.1.1:
- resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
-
- lru-cache@10.4.3:
- resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
-
- make-dir@3.1.0:
- resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
- engines: {node: '>=8'}
-
- marked@15.0.10:
- resolution: {integrity: sha512-BXzsfFiR2UqXFKRwpugWuCYi9mWd1aX/Yns/X52xWfvfen9lnGEDbJw9ZEjjvLZVqntqT2gX45eYvqb2dIokDw==}
- engines: {node: '>= 18'}
- hasBin: true
-
- math-intrinsics@1.1.0:
- resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
- engines: {node: '>= 0.4'}
-
- media-typer@1.1.0:
- resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
- engines: {node: '>= 0.8'}
-
- merge-descriptors@2.0.0:
- resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
- engines: {node: '>=18'}
-
- mime-db@1.54.0:
- resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
- engines: {node: '>= 0.6'}
-
- mime-types@3.0.1:
- resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
- engines: {node: '>= 0.6'}
-
- mimic-response@3.1.0:
- resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
- engines: {node: '>=10'}
-
- minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
-
- minimist@1.2.8:
- resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
-
- minipass@3.3.6:
- resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
- engines: {node: '>=8'}
-
- minipass@5.0.0:
- resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
- engines: {node: '>=8'}
-
- minizlib@2.1.2:
- resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
- engines: {node: '>= 8'}
-
- mkdirp-classic@0.5.3:
- resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
-
- mkdirp@1.0.4:
- resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
- engines: {node: '>=10'}
- hasBin: true
-
- ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-
- mysql@2.18.1:
- resolution: {integrity: sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==}
- engines: {node: '>= 0.6'}
-
- napi-build-utils@2.0.0:
- resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
-
- negotiator@1.0.0:
- resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
- engines: {node: '>= 0.6'}
-
- node-abi@3.74.0:
- resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==}
- engines: {node: '>=10'}
-
- node-addon-api@5.1.0:
- resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
-
- node-fetch@2.7.0:
- resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
- engines: {node: 4.x || >=6.0.0}
- peerDependencies:
- encoding: ^0.1.0
- peerDependenciesMeta:
- encoding:
- optional: true
-
- nodemon@3.1.10:
- resolution: {integrity: sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==}
- engines: {node: '>=10'}
- hasBin: true
-
- nopt@5.0.0:
- resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
- engines: {node: '>=6'}
- hasBin: true
-
- normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
-
- npmlog@5.0.1:
- resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
- deprecated: This package is no longer supported.
-
- nwsapi@2.2.20:
- resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==}
-
- object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
-
- object-inspect@1.13.4:
- resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
- engines: {node: '>= 0.4'}
-
- on-finished@2.4.1:
- resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
- engines: {node: '>= 0.8'}
-
- once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
-
- parse5@7.3.0:
- resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
-
- parseurl@1.3.3:
- resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
- engines: {node: '>= 0.8'}
-
- path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
-
- path-to-regexp@8.2.0:
- resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
- engines: {node: '>=16'}
-
- picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
-
- prebuild-install@7.1.3:
- resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
- engines: {node: '>=10'}
- hasBin: true
-
- process-nextick-args@2.0.1:
- resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
-
- proxy-addr@2.0.7:
- resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
- engines: {node: '>= 0.10'}
-
- pstree.remy@1.1.8:
- resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
-
- pump@3.0.2:
- resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
-
- punycode@2.3.1:
- resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
- engines: {node: '>=6'}
-
- qs@6.14.0:
- resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
- engines: {node: '>=0.6'}
-
- range-parser@1.2.1:
- resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
- engines: {node: '>= 0.6'}
-
- raw-body@3.0.0:
- resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
- engines: {node: '>= 0.8'}
-
- rc@1.2.8:
- resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
- hasBin: true
-
- readable-stream@2.3.7:
- resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==}
-
- readable-stream@3.6.2:
- resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
- engines: {node: '>= 6'}
-
- readdirp@3.6.0:
- resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
- engines: {node: '>=8.10.0'}
-
- require-from-string@2.0.2:
- resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
- engines: {node: '>=0.10.0'}
-
- rimraf@3.0.2:
- resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
- deprecated: Rimraf versions prior to v4 are no longer supported
- hasBin: true
-
- router@2.2.0:
- resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
- engines: {node: '>= 18'}
-
- rrweb-cssom@0.8.0:
- resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
-
- safe-buffer@5.1.2:
- resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
-
- safe-buffer@5.2.1:
- resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
-
- safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
-
- saxes@6.0.0:
- resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
- engines: {node: '>=v12.22.7'}
-
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
- semver@7.7.1:
- resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
- engines: {node: '>=10'}
- hasBin: true
-
- send@1.2.0:
- resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
- engines: {node: '>= 18'}
-
- serve-static@2.2.0:
- resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
- engines: {node: '>= 18'}
-
- set-blocking@2.0.0:
- resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
-
- setprototypeof@1.2.0:
- resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
-
- side-channel-list@1.0.0:
- resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
- engines: {node: '>= 0.4'}
-
- side-channel-map@1.0.1:
- resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
- engines: {node: '>= 0.4'}
-
- side-channel-weakmap@1.0.2:
- resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
- engines: {node: '>= 0.4'}
-
- side-channel@1.1.0:
- resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
- engines: {node: '>= 0.4'}
-
- signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
-
- simple-concat@1.0.1:
- resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
-
- simple-get@4.0.1:
- resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
-
- simple-update-notifier@2.0.0:
- resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
- engines: {node: '>=10'}
-
- sqlstring@2.3.1:
- resolution: {integrity: sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==}
- engines: {node: '>= 0.6'}
-
- statuses@2.0.1:
- resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
- engines: {node: '>= 0.8'}
-
- string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
-
- string_decoder@1.1.1:
- resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
-
- string_decoder@1.3.0:
- resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
-
- strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
-
- strip-json-comments@2.0.1:
- resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
- engines: {node: '>=0.10.0'}
-
- supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
-
- symbol-tree@3.2.4:
- resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
-
- tar-fs@2.1.2:
- resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==}
-
- tar-stream@2.2.0:
- resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
- engines: {node: '>=6'}
-
- tar@6.2.1:
- resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
- engines: {node: '>=10'}
-
- tldts-core@6.1.86:
- resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
-
- tldts@6.1.86:
- resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==}
- hasBin: true
-
- to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
-
- toidentifier@1.0.1:
- resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
- engines: {node: '>=0.6'}
-
- touch@3.1.1:
- resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
- hasBin: true
-
- tough-cookie@5.1.2:
- resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
- engines: {node: '>=16'}
-
- tr46@0.0.3:
- resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
-
- tr46@5.1.1:
- resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
- engines: {node: '>=18'}
-
- tunnel-agent@0.6.0:
- resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
-
- type-is@2.0.1:
- resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
- engines: {node: '>= 0.6'}
-
- undefsafe@2.0.5:
- resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
-
- unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
-
- util-deprecate@1.0.2:
- resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
-
- vary@1.1.2:
- resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
- engines: {node: '>= 0.8'}
-
- w3c-xmlserializer@5.0.0:
- resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
- engines: {node: '>=18'}
-
- webidl-conversions@3.0.1:
- resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
-
- webidl-conversions@7.0.0:
- resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
- engines: {node: '>=12'}
-
- whatwg-encoding@3.1.1:
- resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
- engines: {node: '>=18'}
-
- whatwg-mimetype@4.0.0:
- resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
- engines: {node: '>=18'}
-
- whatwg-url@14.2.0:
- resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
- engines: {node: '>=18'}
-
- whatwg-url@5.0.0:
- resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
-
- wide-align@1.1.5:
- resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
-
- wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
-
- ws@8.18.1:
- resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==}
- engines: {node: '>=10.0.0'}
- peerDependencies:
- bufferutil: ^4.0.1
- utf-8-validate: '>=5.0.2'
- peerDependenciesMeta:
- bufferutil:
- optional: true
- utf-8-validate:
- optional: true
-
- xml-name-validator@5.0.0:
- resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
- engines: {node: '>=18'}
-
- xmlchars@2.2.0:
- resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
-
- yallist@4.0.0:
- resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
-
-snapshots:
-
- '@asamuzakjp/css-color@3.1.4':
- dependencies:
- '@csstools/css-calc': 2.1.3(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
- '@csstools/css-color-parser': 3.0.9(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
- '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
- '@csstools/css-tokenizer': 3.0.3
- lru-cache: 10.4.3
-
- '@csstools/color-helpers@5.0.2': {}
-
- '@csstools/css-calc@2.1.3(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
- dependencies:
- '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
- '@csstools/css-tokenizer': 3.0.3
-
- '@csstools/css-color-parser@3.0.9(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
- dependencies:
- '@csstools/color-helpers': 5.0.2
- '@csstools/css-calc': 2.1.3(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
- '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
- '@csstools/css-tokenizer': 3.0.3
-
- '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)':
- dependencies:
- '@csstools/css-tokenizer': 3.0.3
-
- '@csstools/css-tokenizer@3.0.3': {}
-
- '@mapbox/node-pre-gyp@1.0.11':
- dependencies:
- detect-libc: 2.0.4
- https-proxy-agent: 5.0.1
- make-dir: 3.1.0
- node-fetch: 2.7.0
- nopt: 5.0.0
- npmlog: 5.0.1
- rimraf: 3.0.2
- semver: 7.7.1
- tar: 6.2.1
- transitivePeerDependencies:
- - encoding
- - supports-color
-
- '@types/trusted-types@2.0.7':
- optional: true
-
- abbrev@1.1.1: {}
-
- accepts@2.0.0:
- dependencies:
- mime-types: 3.0.1
- negotiator: 1.0.0
-
- agent-base@6.0.2:
- dependencies:
- debug: 4.4.0(supports-color@5.5.0)
- transitivePeerDependencies:
- - supports-color
-
- agent-base@7.1.3: {}
-
- ajv@8.17.1:
- dependencies:
- fast-deep-equal: 3.1.3
- fast-uri: 3.0.6
- json-schema-traverse: 1.0.0
- require-from-string: 2.0.2
-
- ansi-regex@5.0.1: {}
-
- anymatch@3.1.3:
- dependencies:
- normalize-path: 3.0.0
- picomatch: 2.3.1
-
- aproba@2.0.0: {}
-
- are-we-there-yet@2.0.0:
- dependencies:
- delegates: 1.0.0
- readable-stream: 3.6.2
-
- balanced-match@1.0.2: {}
-
- base64-js@1.5.1: {}
-
- bcrypt@5.1.1:
- dependencies:
- '@mapbox/node-pre-gyp': 1.0.11
- node-addon-api: 5.1.0
- transitivePeerDependencies:
- - encoding
- - supports-color
-
- better-sqlite3@11.9.1:
- dependencies:
- bindings: 1.5.0
- prebuild-install: 7.1.3
-
- bignumber.js@9.0.0: {}
-
- binary-extensions@2.3.0: {}
-
- bindings@1.5.0:
- dependencies:
- file-uri-to-path: 1.0.0
-
- bl@4.1.0:
- dependencies:
- buffer: 5.7.1
- inherits: 2.0.4
- readable-stream: 3.6.2
-
- body-parser@2.2.0:
- dependencies:
- bytes: 3.1.2
- content-type: 1.0.5
- debug: 4.4.0(supports-color@5.5.0)
- http-errors: 2.0.0
- iconv-lite: 0.6.3
- on-finished: 2.4.1
- qs: 6.14.0
- raw-body: 3.0.0
- type-is: 2.0.1
- transitivePeerDependencies:
- - supports-color
-
- brace-expansion@1.1.11:
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
-
- braces@3.0.3:
- dependencies:
- fill-range: 7.1.1
-
- buffer-equal-constant-time@1.0.1: {}
-
- buffer@5.7.1:
- dependencies:
- base64-js: 1.5.1
- ieee754: 1.2.1
-
- bytes@3.1.2: {}
-
- call-bind-apply-helpers@1.0.2:
- dependencies:
- es-errors: 1.3.0
- function-bind: 1.1.2
-
- call-bound@1.0.4:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- get-intrinsic: 1.3.0
-
- chokidar@3.6.0:
- dependencies:
- anymatch: 3.1.3
- braces: 3.0.3
- glob-parent: 5.1.2
- is-binary-path: 2.1.0
- is-glob: 4.0.3
- normalize-path: 3.0.0
- readdirp: 3.6.0
- optionalDependencies:
- fsevents: 2.3.3
-
- chownr@1.1.4: {}
-
- chownr@2.0.0: {}
-
- color-support@1.1.3: {}
-
- concat-map@0.0.1: {}
-
- console-control-strings@1.1.0: {}
-
- content-disposition@1.0.0:
- dependencies:
- safe-buffer: 5.2.1
-
- content-type@1.0.5: {}
-
- cookie-signature@1.2.2: {}
-
- cookie@0.7.2: {}
-
- core-util-is@1.0.3: {}
-
- cssstyle@4.3.1:
- dependencies:
- '@asamuzakjp/css-color': 3.1.4
- rrweb-cssom: 0.8.0
-
- data-urls@5.0.0:
- dependencies:
- whatwg-mimetype: 4.0.0
- whatwg-url: 14.2.0
-
- debug@4.4.0(supports-color@5.5.0):
- dependencies:
- ms: 2.1.3
- optionalDependencies:
- supports-color: 5.5.0
-
- decimal.js@10.5.0: {}
-
- decompress-response@6.0.0:
- dependencies:
- mimic-response: 3.1.0
-
- deep-extend@0.6.0: {}
-
- delegates@1.0.0: {}
-
- depd@2.0.0: {}
-
- detect-libc@2.0.4: {}
-
- dompurify@3.2.5:
- optionalDependencies:
- '@types/trusted-types': 2.0.7
-
- dunder-proto@1.0.1:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- es-errors: 1.3.0
- gopd: 1.2.0
-
- ecdsa-sig-formatter@1.0.11:
- dependencies:
- safe-buffer: 5.2.1
-
- ee-first@1.1.1: {}
-
- emoji-regex@8.0.0: {}
-
- encodeurl@2.0.0: {}
-
- end-of-stream@1.4.4:
- dependencies:
- once: 1.4.0
-
- entities@6.0.0: {}
-
- es-define-property@1.0.1: {}
-
- es-errors@1.3.0: {}
-
- es-object-atoms@1.1.1:
- dependencies:
- es-errors: 1.3.0
-
- escape-html@1.0.3: {}
-
- etag@1.8.1: {}
-
- expand-template@2.0.3: {}
-
- express@5.1.0:
- dependencies:
- accepts: 2.0.0
- body-parser: 2.2.0
- content-disposition: 1.0.0
- content-type: 1.0.5
- cookie: 0.7.2
- cookie-signature: 1.2.2
- debug: 4.4.0(supports-color@5.5.0)
- encodeurl: 2.0.0
- escape-html: 1.0.3
- etag: 1.8.1
- finalhandler: 2.1.0
- fresh: 2.0.0
- http-errors: 2.0.0
- merge-descriptors: 2.0.0
- mime-types: 3.0.1
- on-finished: 2.4.1
- once: 1.4.0
- parseurl: 1.3.3
- proxy-addr: 2.0.7
- qs: 6.14.0
- range-parser: 1.2.1
- router: 2.2.0
- send: 1.2.0
- serve-static: 2.2.0
- statuses: 2.0.1
- type-is: 2.0.1
- vary: 1.1.2
- transitivePeerDependencies:
- - supports-color
-
- fast-deep-equal@3.1.3: {}
-
- fast-uri@3.0.6: {}
-
- file-uri-to-path@1.0.0: {}
-
- fill-range@7.1.1:
- dependencies:
- to-regex-range: 5.0.1
-
- finalhandler@2.1.0:
- dependencies:
- debug: 4.4.0(supports-color@5.5.0)
- encodeurl: 2.0.0
- escape-html: 1.0.3
- on-finished: 2.4.1
- parseurl: 1.3.3
- statuses: 2.0.1
- transitivePeerDependencies:
- - supports-color
-
- forwarded@0.2.0: {}
-
- fresh@2.0.0: {}
-
- fs-constants@1.0.0: {}
-
- fs-minipass@2.1.0:
- dependencies:
- minipass: 3.3.6
-
- fs.realpath@1.0.0: {}
-
- fsevents@2.3.3:
- optional: true
-
- function-bind@1.1.2: {}
-
- gauge@3.0.2:
- dependencies:
- aproba: 2.0.0
- color-support: 1.1.3
- console-control-strings: 1.1.0
- has-unicode: 2.0.1
- object-assign: 4.1.1
- signal-exit: 3.0.7
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wide-align: 1.1.5
-
- get-intrinsic@1.3.0:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- es-define-property: 1.0.1
- es-errors: 1.3.0
- es-object-atoms: 1.1.1
- function-bind: 1.1.2
- get-proto: 1.0.1
- gopd: 1.2.0
- has-symbols: 1.1.0
- hasown: 2.0.2
- math-intrinsics: 1.1.0
-
- get-proto@1.0.1:
- dependencies:
- dunder-proto: 1.0.1
- es-object-atoms: 1.1.1
-
- github-from-package@0.0.0: {}
-
- glob-parent@5.1.2:
- dependencies:
- is-glob: 4.0.3
-
- glob@7.2.3:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
-
- gopd@1.2.0: {}
-
- has-flag@3.0.0: {}
-
- has-symbols@1.1.0: {}
-
- has-unicode@2.0.1: {}
-
- hasown@2.0.2:
- dependencies:
- function-bind: 1.1.2
-
- html-encoding-sniffer@4.0.0:
- dependencies:
- whatwg-encoding: 3.1.1
-
- http-errors@2.0.0:
- dependencies:
- depd: 2.0.0
- inherits: 2.0.4
- setprototypeof: 1.2.0
- statuses: 2.0.1
- toidentifier: 1.0.1
-
- http-proxy-agent@7.0.2:
- dependencies:
- agent-base: 7.1.3
- debug: 4.4.0(supports-color@5.5.0)
- transitivePeerDependencies:
- - supports-color
-
- https-proxy-agent@5.0.1:
- dependencies:
- agent-base: 6.0.2
- debug: 4.4.0(supports-color@5.5.0)
- transitivePeerDependencies:
- - supports-color
-
- https-proxy-agent@7.0.6:
- dependencies:
- agent-base: 7.1.3
- debug: 4.4.0(supports-color@5.5.0)
- transitivePeerDependencies:
- - supports-color
-
- iconv-lite@0.6.3:
- dependencies:
- safer-buffer: 2.1.2
-
- ieee754@1.2.1: {}
-
- ignore-by-default@1.0.1: {}
-
- inflight@1.0.6:
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
-
- inherits@2.0.4: {}
-
- ini@1.3.8: {}
-
- ipaddr.js@1.9.1: {}
-
- is-binary-path@2.1.0:
- dependencies:
- binary-extensions: 2.3.0
-
- is-extglob@2.1.1: {}
-
- is-fullwidth-code-point@3.0.0: {}
-
- is-glob@4.0.3:
- dependencies:
- is-extglob: 2.1.1
-
- is-number@7.0.0: {}
-
- is-potential-custom-element-name@1.0.1: {}
-
- is-promise@4.0.0: {}
-
- isarray@1.0.0: {}
-
- jsdom@26.1.0:
- dependencies:
- cssstyle: 4.3.1
- data-urls: 5.0.0
- decimal.js: 10.5.0
- html-encoding-sniffer: 4.0.0
- http-proxy-agent: 7.0.2
- https-proxy-agent: 7.0.6
- is-potential-custom-element-name: 1.0.1
- nwsapi: 2.2.20
- parse5: 7.3.0
- rrweb-cssom: 0.8.0
- saxes: 6.0.0
- symbol-tree: 3.2.4
- tough-cookie: 5.1.2
- w3c-xmlserializer: 5.0.0
- webidl-conversions: 7.0.0
- whatwg-encoding: 3.1.1
- whatwg-mimetype: 4.0.0
- whatwg-url: 14.2.0
- ws: 8.18.1
- xml-name-validator: 5.0.0
- transitivePeerDependencies:
- - bufferutil
- - supports-color
- - utf-8-validate
-
- json-schema-traverse@1.0.0: {}
-
- jsonwebtoken@9.0.2:
- dependencies:
- jws: 3.2.2
- lodash.includes: 4.3.0
- lodash.isboolean: 3.0.3
- lodash.isinteger: 4.0.4
- lodash.isnumber: 3.0.3
- lodash.isplainobject: 4.0.6
- lodash.isstring: 4.0.1
- lodash.once: 4.1.1
- ms: 2.1.3
- semver: 7.7.1
-
- jwa@1.4.1:
- dependencies:
- buffer-equal-constant-time: 1.0.1
- ecdsa-sig-formatter: 1.0.11
- safe-buffer: 5.2.1
-
- jws@3.2.2:
- dependencies:
- jwa: 1.4.1
- safe-buffer: 5.2.1
-
- lodash.includes@4.3.0: {}
-
- lodash.isboolean@3.0.3: {}
-
- lodash.isinteger@4.0.4: {}
-
- lodash.isnumber@3.0.3: {}
-
- lodash.isplainobject@4.0.6: {}
-
- lodash.isstring@4.0.1: {}
-
- lodash.once@4.1.1: {}
-
- lru-cache@10.4.3: {}
-
- make-dir@3.1.0:
- dependencies:
- semver: 6.3.1
-
- marked@15.0.10: {}
-
- math-intrinsics@1.1.0: {}
-
- media-typer@1.1.0: {}
-
- merge-descriptors@2.0.0: {}
-
- mime-db@1.54.0: {}
-
- mime-types@3.0.1:
- dependencies:
- mime-db: 1.54.0
-
- mimic-response@3.1.0: {}
-
- minimatch@3.1.2:
- dependencies:
- brace-expansion: 1.1.11
-
- minimist@1.2.8: {}
-
- minipass@3.3.6:
- dependencies:
- yallist: 4.0.0
-
- minipass@5.0.0: {}
-
- minizlib@2.1.2:
- dependencies:
- minipass: 3.3.6
- yallist: 4.0.0
-
- mkdirp-classic@0.5.3: {}
-
- mkdirp@1.0.4: {}
-
- ms@2.1.3: {}
-
- mysql@2.18.1:
- dependencies:
- bignumber.js: 9.0.0
- readable-stream: 2.3.7
- safe-buffer: 5.1.2
- sqlstring: 2.3.1
-
- napi-build-utils@2.0.0: {}
-
- negotiator@1.0.0: {}
-
- node-abi@3.74.0:
- dependencies:
- semver: 7.7.1
-
- node-addon-api@5.1.0: {}
-
- node-fetch@2.7.0:
- dependencies:
- whatwg-url: 5.0.0
-
- nodemon@3.1.10:
- dependencies:
- chokidar: 3.6.0
- debug: 4.4.0(supports-color@5.5.0)
- ignore-by-default: 1.0.1
- minimatch: 3.1.2
- pstree.remy: 1.1.8
- semver: 7.7.1
- simple-update-notifier: 2.0.0
- supports-color: 5.5.0
- touch: 3.1.1
- undefsafe: 2.0.5
-
- nopt@5.0.0:
- dependencies:
- abbrev: 1.1.1
-
- normalize-path@3.0.0: {}
-
- npmlog@5.0.1:
- dependencies:
- are-we-there-yet: 2.0.0
- console-control-strings: 1.1.0
- gauge: 3.0.2
- set-blocking: 2.0.0
-
- nwsapi@2.2.20: {}
-
- object-assign@4.1.1: {}
-
- object-inspect@1.13.4: {}
-
- on-finished@2.4.1:
- dependencies:
- ee-first: 1.1.1
-
- once@1.4.0:
- dependencies:
- wrappy: 1.0.2
-
- parse5@7.3.0:
- dependencies:
- entities: 6.0.0
-
- parseurl@1.3.3: {}
-
- path-is-absolute@1.0.1: {}
-
- path-to-regexp@8.2.0: {}
-
- picomatch@2.3.1: {}
-
- prebuild-install@7.1.3:
- dependencies:
- detect-libc: 2.0.4
- expand-template: 2.0.3
- github-from-package: 0.0.0
- minimist: 1.2.8
- mkdirp-classic: 0.5.3
- napi-build-utils: 2.0.0
- node-abi: 3.74.0
- pump: 3.0.2
- rc: 1.2.8
- simple-get: 4.0.1
- tar-fs: 2.1.2
- tunnel-agent: 0.6.0
-
- process-nextick-args@2.0.1: {}
-
- proxy-addr@2.0.7:
- dependencies:
- forwarded: 0.2.0
- ipaddr.js: 1.9.1
-
- pstree.remy@1.1.8: {}
-
- pump@3.0.2:
- dependencies:
- end-of-stream: 1.4.4
- once: 1.4.0
-
- punycode@2.3.1: {}
-
- qs@6.14.0:
- dependencies:
- side-channel: 1.1.0
-
- range-parser@1.2.1: {}
-
- raw-body@3.0.0:
- dependencies:
- bytes: 3.1.2
- http-errors: 2.0.0
- iconv-lite: 0.6.3
- unpipe: 1.0.0
-
- rc@1.2.8:
- dependencies:
- deep-extend: 0.6.0
- ini: 1.3.8
- minimist: 1.2.8
- strip-json-comments: 2.0.1
-
- readable-stream@2.3.7:
- dependencies:
- core-util-is: 1.0.3
- inherits: 2.0.4
- isarray: 1.0.0
- process-nextick-args: 2.0.1
- safe-buffer: 5.1.2
- string_decoder: 1.1.1
- util-deprecate: 1.0.2
-
- readable-stream@3.6.2:
- dependencies:
- inherits: 2.0.4
- string_decoder: 1.3.0
- util-deprecate: 1.0.2
-
- readdirp@3.6.0:
- dependencies:
- picomatch: 2.3.1
-
- require-from-string@2.0.2: {}
-
- rimraf@3.0.2:
- dependencies:
- glob: 7.2.3
-
- router@2.2.0:
- dependencies:
- debug: 4.4.0(supports-color@5.5.0)
- depd: 2.0.0
- is-promise: 4.0.0
- parseurl: 1.3.3
- path-to-regexp: 8.2.0
- transitivePeerDependencies:
- - supports-color
-
- rrweb-cssom@0.8.0: {}
-
- safe-buffer@5.1.2: {}
-
- safe-buffer@5.2.1: {}
-
- safer-buffer@2.1.2: {}
-
- saxes@6.0.0:
- dependencies:
- xmlchars: 2.2.0
-
- semver@6.3.1: {}
-
- semver@7.7.1: {}
-
- send@1.2.0:
- dependencies:
- debug: 4.4.0(supports-color@5.5.0)
- encodeurl: 2.0.0
- escape-html: 1.0.3
- etag: 1.8.1
- fresh: 2.0.0
- http-errors: 2.0.0
- mime-types: 3.0.1
- ms: 2.1.3
- on-finished: 2.4.1
- range-parser: 1.2.1
- statuses: 2.0.1
- transitivePeerDependencies:
- - supports-color
-
- serve-static@2.2.0:
- dependencies:
- encodeurl: 2.0.0
- escape-html: 1.0.3
- parseurl: 1.3.3
- send: 1.2.0
- transitivePeerDependencies:
- - supports-color
-
- set-blocking@2.0.0: {}
-
- setprototypeof@1.2.0: {}
-
- side-channel-list@1.0.0:
- dependencies:
- es-errors: 1.3.0
- object-inspect: 1.13.4
-
- side-channel-map@1.0.1:
- dependencies:
- call-bound: 1.0.4
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
- object-inspect: 1.13.4
-
- side-channel-weakmap@1.0.2:
- dependencies:
- call-bound: 1.0.4
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
- object-inspect: 1.13.4
- side-channel-map: 1.0.1
-
- side-channel@1.1.0:
- dependencies:
- es-errors: 1.3.0
- object-inspect: 1.13.4
- side-channel-list: 1.0.0
- side-channel-map: 1.0.1
- side-channel-weakmap: 1.0.2
-
- signal-exit@3.0.7: {}
-
- simple-concat@1.0.1: {}
-
- simple-get@4.0.1:
- dependencies:
- decompress-response: 6.0.0
- once: 1.4.0
- simple-concat: 1.0.1
-
- simple-update-notifier@2.0.0:
- dependencies:
- semver: 7.7.1
-
- sqlstring@2.3.1: {}
-
- statuses@2.0.1: {}
-
- string-width@4.2.3:
- dependencies:
- emoji-regex: 8.0.0
- is-fullwidth-code-point: 3.0.0
- strip-ansi: 6.0.1
-
- string_decoder@1.1.1:
- dependencies:
- safe-buffer: 5.1.2
-
- string_decoder@1.3.0:
- dependencies:
- safe-buffer: 5.2.1
-
- strip-ansi@6.0.1:
- dependencies:
- ansi-regex: 5.0.1
-
- strip-json-comments@2.0.1: {}
-
- supports-color@5.5.0:
- dependencies:
- has-flag: 3.0.0
-
- symbol-tree@3.2.4: {}
-
- tar-fs@2.1.2:
- dependencies:
- chownr: 1.1.4
- mkdirp-classic: 0.5.3
- pump: 3.0.2
- tar-stream: 2.2.0
-
- tar-stream@2.2.0:
- dependencies:
- bl: 4.1.0
- end-of-stream: 1.4.4
- fs-constants: 1.0.0
- inherits: 2.0.4
- readable-stream: 3.6.2
-
- tar@6.2.1:
- dependencies:
- chownr: 2.0.0
- fs-minipass: 2.1.0
- minipass: 5.0.0
- minizlib: 2.1.2
- mkdirp: 1.0.4
- yallist: 4.0.0
-
- tldts-core@6.1.86: {}
-
- tldts@6.1.86:
- dependencies:
- tldts-core: 6.1.86
-
- to-regex-range@5.0.1:
- dependencies:
- is-number: 7.0.0
-
- toidentifier@1.0.1: {}
-
- touch@3.1.1: {}
-
- tough-cookie@5.1.2:
- dependencies:
- tldts: 6.1.86
-
- tr46@0.0.3: {}
-
- tr46@5.1.1:
- dependencies:
- punycode: 2.3.1
-
- tunnel-agent@0.6.0:
- dependencies:
- safe-buffer: 5.2.1
-
- type-is@2.0.1:
- dependencies:
- content-type: 1.0.5
- media-typer: 1.1.0
- mime-types: 3.0.1
-
- undefsafe@2.0.5: {}
-
- unpipe@1.0.0: {}
-
- util-deprecate@1.0.2: {}
-
- vary@1.1.2: {}
-
- w3c-xmlserializer@5.0.0:
- dependencies:
- xml-name-validator: 5.0.0
-
- webidl-conversions@3.0.1: {}
-
- webidl-conversions@7.0.0: {}
-
- whatwg-encoding@3.1.1:
- dependencies:
- iconv-lite: 0.6.3
-
- whatwg-mimetype@4.0.0: {}
-
- whatwg-url@14.2.0:
- dependencies:
- tr46: 5.1.1
- webidl-conversions: 7.0.0
-
- whatwg-url@5.0.0:
- dependencies:
- tr46: 0.0.3
- webidl-conversions: 3.0.1
-
- wide-align@1.1.5:
- dependencies:
- string-width: 4.2.3
-
- wrappy@1.0.2: {}
-
- ws@8.18.1: {}
-
- xml-name-validator@5.0.0: {}
-
- xmlchars@2.2.0: {}
-
- yallist@4.0.0: {}
diff --git a/server.js b/server.js
deleted file mode 100644
index 33b1df6..0000000
--- a/server.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// --- Imports ---
-
-const express = require("express");
-const app = express();
-const configManager = require("./src/utils/configManager");
-const { connectDatabase, initDatabase } = require('./src/database/index');
-
-
-// --- Load configuration ---
-const config = configManager.loadConfig();
-
-// --- Body parsing ---
-app.use(express.json()); // Necessary to parse JSON bodies
-
-// Database connection
-(async () => {
-
-
- // --- Database connection ---
- await connectDatabase();
- await initDatabase();
-
- // --- Routing ---
- app.use("/", require("./src/routes/index"));
- app.use("/mods", require("./src/routes/mods"));
- app.use("/users", require("./src/routes/users"));
- app.use("/list", require("./src/routes/list"));
- app.use("/login", require("./src/routes/login"));
-
-})();
-
-
-// --- Launch ---
-
-const port = config.port;
-app.listen(port, () => {
- console.log("Server listening on port " + port + "...");
-})
\ No newline at end of file
diff --git a/src/controllers/auth.js b/src/controllers/auth.js
deleted file mode 100644
index 7bd6571..0000000
--- a/src/controllers/auth.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const handleError = require("../middleware/errors");
-const authService = require("../services/authService");
-
-async function login(req, res) {
- try {
- const username = req.body.username;
- const email = req.body.email;
- const password = req.body.password
- const token = await authService.login(username, email, password);
- res.json({ token });
- } catch (err) {
- handleError(err, res);
- }
-
-}
-
-module.exports = { login };
\ No newline at end of file
diff --git a/src/controllers/index.js b/src/controllers/index.js
deleted file mode 100644
index 3580e6b..0000000
--- a/src/controllers/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const index_service = require("../services/indexService");
-const handleError = require("../middleware/errors");
-
-
-async function getVersion(req, res) {
- try {
- const query_result = await index_service.getVersion();
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-module.exports = { getVersion };
\ No newline at end of file
diff --git a/src/controllers/modpacks.js b/src/controllers/modpacks.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/controllers/mods.js b/src/controllers/mods.js
deleted file mode 100644
index d1f36dc..0000000
--- a/src/controllers/mods.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const handleError = require("../middleware/errors");
-const mod_service = require("../services/modService");
-const { authorizeModModification, authenticateToken } = require("../middleware/auth");
-
-async function listMods(req, res) {
- try {
- // Query
- const query_result = await mod_service.getAllMods();
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function createMod(req, res) {
- try {
- // Authenticate
- await authenticateToken(req);
- // Query
- const mod_data = req.body;
- const user = req.token_infos.username;
- const query_result = await mod_service.createMod(mod_data, user);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function modifyMod(req, res) {
- try {
- // Authorize
- authorizeModModification(req);
- // Query
- const mod_data = req.body;
- const query_result = await mod_service.modifyMod(mod_data);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function getModByName(req, res) {
- try {
- // Query
- const name = req.params.name
- const query_result = await mod_service.getModByName(name);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function deleteMod(req, res) {
- try {
- // Authorize
- authorizeModModification(req);
- // Query
- const name = req.params.name
- const query_result = await mod_service.deleteMod(name);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-
-
-module.exports = { listMods, getModByName, createMod, modifyMod, deleteMod };
\ No newline at end of file
diff --git a/src/controllers/users.js b/src/controllers/users.js
deleted file mode 100644
index 71e475f..0000000
--- a/src/controllers/users.js
+++ /dev/null
@@ -1,63 +0,0 @@
-const handleError = require("../middleware/errors");
-const user_service = require("../services/userService")
-const { authorizeUserModification } = require("../middleware/auth");
-
-
-async function listUsers(req, res) {
- try {
- // Query
- const query_result = await user_service.getAllUsers();
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function getUserByName(req, res) {
- try {
- // Query
- const query_result = await user_service.getUserByName(req.params.name);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function createUser(req, res) {
- try {
- // Query
- const query_result = await user_service.createUser(req.body);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function modifyUser(req, res) {
- try {
- // Query
- const diff_data = req.body;
- const query_result = await user_service.modifyUser(diff_data);
- res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-async function deleteUser(req, res) {
- try {
- // Authenticate
- await authorizeUserModification(req);
- // Query
- const user = req.params.name;
- const token_user = req.token_infos
- const query_result = await user_service.deleteUser(user, token_user);
- return res.json(query_result);
- } catch (error) {
- handleError(error, res);
- }
-}
-
-
-
-module.exports = { listUsers, getUserByName, createUser, modifyUser, deleteUser };
\ No newline at end of file
diff --git a/src/database/index.js b/src/database/index.js
deleted file mode 100644
index 1399795..0000000
--- a/src/database/index.js
+++ /dev/null
@@ -1,112 +0,0 @@
-const MySQLDatabase = require("./mysql");
-const SQLiteDatabase = require("./sqlite");
-const { getConfig } = require("../utils/configManager");
-
-let db;
-
-async function connectDatabase() {
-
- // Get config
- const config = await getConfig();
-
- // Choose database type
- if (config.database.type === "mysql") {
- db = new MySQLDatabase(config.database);
- } else if (config.database.type === "sqlite") {
- db = new SQLiteDatabase(config.database);
- } else {
- throw new Error("Invalid database type: ", config.database.type);
- }
-
- // Connect
- await db.connect();
- return db;
-}
-
-
-// Setups the database by creating the tables and the default objects
-async function initDatabase() {
-
- if (!db) {
- throw new Error("Database is not connected");
- }
-
- // --- Users ---
-
- // Uers table
- db.exec(`CREATE TABLE IF NOT EXISTS Users (
- username TINYTEXT PRIMARY KEY,
- display_name TINYTEXT NOT NULL,
- email TINYTEXT NOT NULL,
- password TINYTEXT NOT NULL,
- profile_picture LONGTEXT,
- role TINYTEXT NOT NULL,
- settings LONGTEXT
- );`);
-
- // --- Mods ---
-
- // Mods table
- db.exec(`CREATE TABLE IF NOT EXISTS Mods (
- name TINYTEXT PRIMARY KEY,
- display_name TINYTEXT NOT NULL,
- author TINYTEXT NOT NULL,
- description TINYTEXT NOT NULL,
-
- FOREIGN KEY (author) REFERENCES Users(username)
- );`);
-
- // Mods complementary infos
- db.exec(`CREATE TABLE IF NOT EXISTS ModInfos (
- mod TINYTEXT PRIMARY KEY,
- full_description TEXT NOT NULL,
- license TINYTEXT,
- custom_license TEXT,
- links TEXT,
- creation_date TINYTEXT NOT NULL,
- downloads_count INT NOT NULL,
-
- FOREIGN KEY (mod) REFERENCES Mods(name)
- );`);
-
- // Mods tags
- db.exec(`CREATE TABLE IF NOT EXISTS ModTags (
- mod TINYTEXT NOT NULL,
- tag TINYTEXT NOT NULL,
-
- FOREIGN KEY (mod) REFERENCES Mods(name)
- );`);
-
- // Mods versions
- db.exec(`CREATE TABLE IF NOT EXISTS ModVersions (
- mod TINYTEXT NOT NULL,
- version_number TINYTEXT NOT NULL,
- channel TINYTEXT NOT NULL,
- changelog TEXT NOT NULL,
- release_date TINYTEXT NOT NULL,
- game_version TINYTEXT NOT NULL,
- platform TINYTEXT NOT NULL,
- environment TINYTEXT NOT NULL,
- url TINYTEXT NOT NULL,
-
- FOREIGN KEY (mod) REFERENCES Mods(name)
- );`);
-
- // User favorites (mods)
- db.exec(`CREATE TABLE IF NOT EXISTS UserFavoriteMods (
- username TINYTEXT NOT NULL,
- mod TINYTEXT NOT NULL,
-
- FOREIGN KEY (username) REFERENCES Users(username),
- FOREIGN KEY (mod) REFERENCES Mods(name)
- );`);
-
-}
-
-
-function getDatabase() {
- return db;
-}
-
-
-module.exports = { getDatabase, connectDatabase, initDatabase };
\ No newline at end of file
diff --git a/src/database/mysql.js b/src/database/mysql.js
deleted file mode 100644
index df96f30..0000000
--- a/src/database/mysql.js
+++ /dev/null
@@ -1,30 +0,0 @@
-class MySQLDatabase {
- constructor(config) {
- const mysql = require("mysql2/promise");
- this.config = config;
- }
-
-
- async connect() {
- this.db = await mysql.createConnection({
- host: this.config.host,
- user: this.config.user,
- password: this.config.password,
- database: this.config.database,
- });
- console.log("Connected to MySQL");
- }
-
- async close() {
- await this.db.end();
- }
-
- async query(sql, params) {
- throw new Error("Not implemented"); //TODO
- const [results] = await this.db.execute(sql, params);
- return results;
- }
-}
-
-
-module.exports = MySQLDatabase;
\ No newline at end of file
diff --git a/src/database/sqlite.js b/src/database/sqlite.js
deleted file mode 100644
index b81e219..0000000
--- a/src/database/sqlite.js
+++ /dev/null
@@ -1,70 +0,0 @@
-const sqlite = require("better-sqlite3");
-
-class SQLiteDatabase {
-
- constructor(config) {
- this.config = config;
- this.db = null;
- }
-
- async connect() {
- try {
- this.db = new sqlite("./data/sqlite.db");
- // this.db.pragma("journal_mode = WAL");
- console.log("Connected to SQLite");
- } catch (err) {
- console.error("Error connecting to SQLite database: ", err);
- process.exit(1);
- }
- }
-
- async close() {
- if (this.db && this.db.open) {
- this.db.close();
- console.debug("Closed database connection");
- }
- }
-
- async query(sql, params = []) {
- try {
- if (params.length > 0) {
- return this.db.prepare(sql).all(params);
- } else {
- return this.db.prepare(sql).all();
- }
- } catch (err) {
- console.error("Error executing prepared query:", err);
- throw err;
- }
- }
-
- async exec(sql) {
- try {
- return this.db.exec(sql);
- } catch (err) {
- console.error("Error executing statement:", err)}
-
- }
-
- async prepare(sql, params = []) {
- try {
- if (params.length > 0) {
- return this.db.prepare(sql).run(params);
- } else {
- return this.db.prepare(sql);
- }
- } catch (err) {
- console.error("Error executing prepared statement:", err)}
- }
-
- async exists(table, attribute, value) {
- try {
- return this.db.prepare(`SELECT COUNT(*) FROM ${table} WHERE ${attribute} = ?`).get(value)['COUNT(*)'] > 0;
- } catch (err) {
- console.error("Error checking item existence");
- }
- }
-
-}
-
-module.exports = SQLiteDatabase;
\ No newline at end of file
diff --git a/src/middleware/auth.js b/src/middleware/auth.js
deleted file mode 100644
index d43e385..0000000
--- a/src/middleware/auth.js
+++ /dev/null
@@ -1,85 +0,0 @@
-const { getModByName } = require("../services/modService");
-const { getModpackByName } = require("../services/modpackService");
-const { getUserByName } = require("../services/userService");
-const { verifyToken } = require("../utils/crypto");
-const AppError = require("../utils/appError");
-
-
-async function authenticateToken(req) {
-
- const token = req.header("Authorization");
-
- if (!token) {
- throw new AppError(401, "Missing authorization header", "Unauthorized");
- }
-
- try {
- req.token_infos = await verifyToken(token);
- console.debug("Authorizing token from", req.token_infos);
- } catch (err) {
- throw new AppError(403, "Forbidden: Error verifying the authorization token");
- }
-
- return req.token_infos;
-}
-
-
-async function authorizeModModification(req) {
-
- // Auth token
- await authenticateToken(req);
- // Get mod infos
- if (!req.params || !req.params.name) {
- throw new AppError(400, "No mod name was scpecified", "Bad request");
- }
- const mod_name = req.params.name;
- const mod = await getModByName(mod_name);
- if (!mod) {
- throw new AppError(404, "No mod was found with this name", "Not found");
- }
- // Authorize
- if ( mod.author != req.token_infos.username) {
- throw new AppError(401, "Mod author differs from current user", "Unauthorized");
- }
-}
-
-async function authorizeModpackModification(req) {
-
- // Auth token
- await authenticateToken(req);
- // Get mod infos
- if (!req.params || !req.params.name) {
- throw new AppError(400, "No mod name was scpecified", "Bad request");
- }
- const modpack_name = req.params.name;
- const modpack = await getModpackByName(modpack_name);
- if (!modpack) {
- throw new AppError(404, "No mod was found with this name", "Not found");
- }
- // Authorize
- if ( modpack.author != req.token_infos.username) {
- throw new AppError(401, "Mod author differs from current user", "Unauthorized");
- }
-}
-
-async function authorizeUserModification(req) {
-
- // Auth token
- await authenticateToken(req);
- // Get mod infos
- if (!req.params || !req.params.name) {
- throw new AppError(400, "No mod name was scpecified", "Bad request");
- }
- const user_name = req.params.name;
- const user = await getUserByName(user_name);
- if (!user) {
- throw new AppError(404, "No user was found with this name", "Not found");
- }
- // Authorize
- if ( user.username != req.token_infos.username) {
- throw new AppError(401, "User to modify differs from current user", "Unauthorized");
- }
-}
-
-
-module.exports = { authenticateToken, authorizeModModification, authorizeModpackModification, authorizeUserModification };
\ No newline at end of file
diff --git a/src/middleware/errors.js b/src/middleware/errors.js
deleted file mode 100644
index f51e57a..0000000
--- a/src/middleware/errors.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const AppError = require("../utils/appError");
-
-const handleError = (err, res) => {
-
- // Send error infos
- if (err instanceof AppError) {
-
- // Log
- if (err.statusCode == 500) {
- console.error("Error:", err.message);
- if (err.debugMsg) {
- console.debug(" >", err.debugMsg);
- }
- }
-
- // Response
- return res.status(err.statusCode).json({
- status: err.status,
- message: err.message
- });
- }
-
- // Default error
- console.error("Error:", err.message);
- res.status(500).json({
- message: 'Internal server error',
- status: 500
- });
-}
-
-module.exports = handleError;
\ No newline at end of file
diff --git a/src/models/index.js b/src/models/index.js
deleted file mode 100644
index 7b8c71c..0000000
--- a/src/models/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const configManager = require("../utils/configManager");
-
-async function getVersion() {
-
- const version = await configManager.getVersion();
- const res = {
- version: version
- };
- return res;
-}
-
-module.exports = { getVersion }
\ No newline at end of file
diff --git a/src/models/mod.js b/src/models/mod.js
deleted file mode 100644
index f7abfd9..0000000
--- a/src/models/mod.js
+++ /dev/null
@@ -1,192 +0,0 @@
-const { getDatabase } = require('../database/index');
-const AppError = require('../utils/appError');
-const db = getDatabase();
-
-
-// --- Get ---
-
-async function getAllMods() {
- return await db.query("SELECT name, display_name, author, description FROM Mods");
-}
-
-async function getModByName(name) {
- return await db.query("SELECT name, display_name, author FROM Mods WHERE name = ?;", [name]);
-
-}
-
-async function getModFullInfos(name) {
-
- // Query
- const base_infos = db.query(`SELECT * FROM Mods WHERE name = ?`, [name]);
- const other_infos = db.query(`SELECT full_description, license, links, creation_date, downloads_count
- FROM ModInfos WHERE name = ?`, [name]);
- const tags = getModTags(name);
-
- // Merge
- const res = {...await base_infos, ...await other_infos, ...tags};
-
- return res;
-}
-
-async function listVersions(mod_name) {
- return await db.query("SELECT * FROM ModVersions WHERE mod = ?", [mod_name]);
-}
-
-async function getVersionByNumber(mod_name, version_number) {
- return await db.query(`SELECT * FROM ModVersions
- WHERE mod = ?
- AND version_number = ?;`,
- [mod_name, version_number]);
-}
-
-async function getVersion(mod_name, version_number, game_version, platform, environment) {
- return await db.query(`SELECT * FROM ModVersions
- WHERE mod = ?
- AND version_number = ?
- AND game_version = ?
- AND platform = ?
- AND environment = ?;`,
- [mod_name, version_number, game_version, platform, environment]);
-}
-
-// --- Create ---
-
-async function createMod(name, display_name, author, description, mod_infos) {
-
- // Extract infos
- const { full_description, license, links, creation_date, tags } = mod_infos;
-
- // Mods table
- await db.prepare("INSERT INTO Mods (name, display_name, author, description) \
- VALUES (?, ?, ?, ?)",
- [name, display_name, author, description]);
-
- // ModInfos table
- await db.prepare(`INSERT INTO ModInfos (mod, full_description, license, links, creation_date, downloads_count)
- VALUES (?, ?, ?, ?, ?, ?)`,
- [name, full_description, license.type, links.toString(), creation_date, 0]);
-
- // Tags
- if (tags) {
- const tags_proc = addTags(name, tags, []);
- }
-
-
- // License
- if (license.type == "custom") {
- await db.prepare(`UPDATE ModInfos SET custom_license = ?
- WHERE mod = ?`,
- [license.content, name]);
- }
-
- // Await
- if (tags) {
- await tags_proc;
- }
-
- return;
-}
-
-async function addVersion(mod, version_number, channel, changelog, release_date, game_version, platform, environment, url) {
-
- await db.prepare(`INSERT INTO ModVersions (mod, version_number, channel, changelog, release_date, game_version, environment, platform, url)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);`,
- [mod, version_number, channel, changelog, release_date, game_version, environment, platform, url]);
- return;
-}
-
-async function addTags(mod, tags) {
- // Add asynchronously
- const promises = tags.map(async (tag) => {
- db.query(`INSERT INTO ModTags (mod, tag)
- VALUES (?, ?);`,
- [mod, tag]);
- });
- await Promise.all(promises);
-
- return;
-}
-
-
-// --- Update ---
-
-async function updateMod(name, display_name, author, description) {
-
- if (display_name) {
- await updateModAttributes(name, "display_name", display_name);
- }
-
- if (author) {
- await updateModAttribute(nale, "author", author);
- }
-
- if (description) {
- await updateModAttribute(name, "description", description)
- }
-}
-
-
-// --- Delete ---
-
-async function deleteMod(name) {
- await db.prepare("DELETE FROM Mods WHERE name = ?", [name]);
- return;
-}
-
-async function deleteVersion(name, version_number, game_version, platform, environment) {
- await db.prepare(`DELETE FROM ModVersions WHERE mod = ?
- AND version_number = ?
- AND game_version = ?
- AND platform = ?
- AND environment = ?;`,
- [name, version_number, game_version, platform, environment]);
- return;
-}
-
-async function deleteTags(mod, tags) {
- // Remove asynchronously
- const promises = tags.map(async (tag) => {
- db.query(`DELETE FROM ModTags
- WHERE mod = ? AND tag = ?;`, [mod, tag]);
- });
- await Promise.all(promises);
-
- return;
-}
-
-
-// --- Utils ---
-
-async function updateModAttribute(name, attribute, value) {
- await db.prepare(`UPDATE Mods SET ${attribute} = ? WHERE name = ?`, [value, name]);
- return;
-}
-
-async function updateModInfosAttribute(name, attribute, value) {
- await db.prepare(`UPDATE ModInfos SET ${attribute} = ? WHERE name = ?`, [value, name]);
- return;
-}
-
-async function exists(name) {
- return db.exists("Mods", "name", name);
-}
-
-async function containsVersion(name, version_number, game_version, platform, environment) {
- throw new AppError(501, "Not implemented");
- // return db.exists("Mods", "name", name);
-}
-
-async function containsTag(name, tag) {
- throw new AppError(501, "Not implemented");
- // return db.exists("Mods", "name", name);
-}
-
-
-// --- Exports ---
-
-module.exports = { getAllMods, getModByName, getModFullInfos,
- listVersions, getVersionByNumber, getVersion,
- createMod, addVersion, addTags,
- updateMod,
- deleteMod, deleteVersion, deleteTags,
- exists };
\ No newline at end of file
diff --git a/src/models/modpack.js b/src/models/modpack.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/models/user.js b/src/models/user.js
deleted file mode 100644
index fc66eda..0000000
--- a/src/models/user.js
+++ /dev/null
@@ -1,125 +0,0 @@
-const { getDatabase } = require('../database/index');
-const AppError = require('../utils/appError');
-const db = getDatabase();
-
-
-// --- Get ---
-
-async function getAllUsers() {
- return db.query("SELECT username, display_name, email, profile_picture FROM Users");
-}
-
-async function getUserByName(name) {
- return await db.query("SELECT username, display_name, profile_picture, role FROM Users WHERE username = ?;", [name]);
-}
-
-async function getUserByEmail(email) {
- return await db.query("SELECT email, username FROM Users WHERE email = ?;", [email]);
-}
-
-async function getFullUserInfos(name) {
- return await db.query("SELECT username, display_name, email, profile_picture, role, settings FROM Users WHERE username = ?;", [name]);
-}
-
-async function getUserPassword(name) {
- return await db.query("SELECT username, password FROM Users WHERE username = ?;", [name]);
-}
-
-async function exists(name) {
- return await db.exists("Users", "username", name);
-}
-
-
-// --- Create ---
-
-async function createUser( username, email, password, displayName, profilePicture, settings ) {
-
- // Create user
- await db.prepare(`INSERT INTO Users (username, email, password, display_name, role )
- VALUES (?, ?, ?, ?, ? )`,
- [username, email, password, displayName, "user"]);
-
- // Handle nullable fields
- if (profilePicture) {
- await updateUserAttribute(username, "profile_picture", profilePicture);
- }
-
- if (settings) {
- await updateUserAttribute(username, "settings", settings);
- }
- return;
-}
-
-async function addFavoriteMods(username, favs) {
-
- const promises = favs.map(async (mod) => {
- db.query(`INSERT INTO UserFavoriteMods
- (username, mod) VALUES (?, ?);`,
- [username, mod]);
-
- });
- await Promise.all(promises);
-
- return;
-}
-
-
-// --- Update ---
-
-async function updateUser(username, display_name, email, profile_picture, settings) {
-
- if (display_name) {
- await updateUserAttribute(username, "display_name", display_name);
- }
-
- if (email) {
- await updateUserAttribute(username, "email", email);
- }
-
- if (profile_picture) {
- await updateUserAttribute(username, "profile_picture", profile_picture)
- }
-
- if (settings) {
- await updateUserAttribute(username, "settings", settings);
- }
-}
-
-async function updateUserPassword(username, password) {
- await db.prepare(`UPDATE Users SET password = ? WHERE username = ?`, [password, username]);
-}
-
-async function updateUserAttribute(username, attribute, value) {
- await db.prepare(`UPDATE Users SET ${attribute} = ? WHERE username = ?`, [value, username]);
- return;
-}
-
-
-// --- Delete ---
-
-async function deleteUser(username) {
- await db.prepare("DELETE FROM Users WHERE username = ?", [username]);
- return;
-}
-
-async function deleteFavoriteMods(username, favs) {
-
- const promises = favs.map(async (mod) => {
- db.query(`DELETE FROM UserFavoriteMods
- WHERE username = ? AND mod = ?;`, [username, mod]);
- });
-
- // Await
- await Promise.all(promises);
-
- return;
-}
-
-
-// --- Exports ---
-
-module.exports = { getAllUsers, getUserByName, getUserByEmail, getFullUserInfos, getUserPassword,
- createUser, addFavoriteMods,
- updateUser,
- deleteUser, deleteFavoriteMods,
- exists }
\ No newline at end of file
diff --git a/src/routes/index.js b/src/routes/index.js
deleted file mode 100644
index 36880b8..0000000
--- a/src/routes/index.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const express = require("express");
-const controller = require("../controllers/index");
-
-const router = express.Router();
-
-
-router.get('/version', async (res, req) => {
- controller.getVersion(res, req);
-});
-
-module.exports = router;
\ No newline at end of file
diff --git a/src/routes/list.js b/src/routes/list.js
deleted file mode 100644
index 2829954..0000000
--- a/src/routes/list.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const express = require("express");
-const { listMods } = require("../controllers/mods");
-// const { listModpacks } = require("../controllers/modpacks");
-const { listUsers } = require("../controllers/users");
-
-const router = express.Router();
-
-// List mods
-router.get("/mods", async (req,res) => {
- listMods(req, res);
-});
-
-// List modpacks
-// router.get("/modpacks", async (req,res) => {
-// listModpacks(req, res);
-// });
-
-// List users
-router.get("/users", async (req,res) => {
- listUsers(req, res);
-});
-
-
-module.exports = router;
\ No newline at end of file
diff --git a/src/routes/login.js b/src/routes/login.js
deleted file mode 100644
index 14b8a87..0000000
--- a/src/routes/login.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const express = require("express");
-const controller = require("../controllers/auth");
-
-const router = express.Router();
-
-// Login
-router.post("/", async (req, res) => {
- controller.login(req, res);
-});
-
-module.exports = router;
\ No newline at end of file
diff --git a/src/routes/modpacks.js b/src/routes/modpacks.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/routes/mods.js b/src/routes/mods.js
deleted file mode 100644
index 82c1e02..0000000
--- a/src/routes/mods.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const express = require("express");
-const controller = require("../controllers/mods");
-
-const router = express.Router();
-
-// Create a mod
-router.post("/", async (req, res) => {
- controller.createMod(req, res);
-});
-
-// Modify mod
-router.put("/:name", async (req,res) => {
- controller.modifyMod(req,res);
-});
-
-// Get mod infos
-router.get("/:name", async (req,res) => {
- controller.getModByName(req, res);
-});
-
-// Delete mod
-router.delete("/:name", async (req,res) => {
- controller.deleteMod(req, res);
-});
-
-
-module.exports = router;
\ No newline at end of file
diff --git a/src/routes/users.js b/src/routes/users.js
deleted file mode 100644
index 390451f..0000000
--- a/src/routes/users.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const express = require("express");
-const controller = require("../controllers/users");
-
-const router = express.Router();
-
-// List users
-router.get("/", async (req,res) => {
- controller.listUsers(req,res);
-});
-
-// Create a user
-router.post("/", async (req, res) => {
- controller.createUser(req, res);
-})
-
-// Get user infos
-router.get("/:name", async (req,res) => {
- controller.getUserByName(req, res);
-});
-
-// Delete user
-router.delete("/:name", async (req,res) => {
- controller.deleteUser(req, res);
-});
-
-
-module.exports = router;
\ No newline at end of file
diff --git a/src/schemas/auth.js b/src/schemas/auth.js
deleted file mode 100644
index e57a75c..0000000
--- a/src/schemas/auth.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const Ajv = require("ajv");
-const ajv = new Ajv();
-
-// --- Schemas ---
-
-const AuthUserSchema = {
- type: 'object',
- properties: {
- email: { type: 'string', format: 'email' },
- password: { type: 'string', minLength: 3, maxLength: 30 },
- },
- required: ['email', 'password'],
- additionalProperties: false
-};
-
-const validateAuthUserData = ajv.compile(AuthUserSchema);
-
-
-// --- Exports ---
-
-module.exports = { validateAuthUserData, validateAuthNodeData };
\ No newline at end of file
diff --git a/src/schemas/mod.js b/src/schemas/mod.js
deleted file mode 100644
index 6d7dc9d..0000000
--- a/src/schemas/mod.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const Ajv = require("ajv");
-const ajv = new Ajv();
-
-// --- Schemas ---
-//TODO
-
-const newModSchema = {
- type: 'object',
- properties: {
- name: { type: 'string'},
- },
- required: ['name'],
- additionalProperties: false
-};
-
-const validateNewModData = ajv.compile(newModSchema);
-
-
-// --- Exports ---
-
-module.exports = { validateNewModData };
\ No newline at end of file
diff --git a/src/schemas/modpack.js b/src/schemas/modpack.js
deleted file mode 100644
index df4a49a..0000000
--- a/src/schemas/modpack.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const Ajv = require("ajv");
-const ajv = new Ajv();
-
-// --- Schemas ---
-//TODO
-
-const newModpackSchema = {
- type: 'object',
- properties: {
- name: { type: 'string'},
- },
- required: ['name'],
- additionalProperties: false
-};
-
-const validateNewModpackData = ajv.compile(newModpackSchema);
-
-
-// --- Exports ---
-
-module.exports = { validateNewModpackData };
\ No newline at end of file
diff --git a/src/schemas/user.js b/src/schemas/user.js
deleted file mode 100644
index 0c009a1..0000000
--- a/src/schemas/user.js
+++ /dev/null
@@ -1,23 +0,0 @@
-const Ajv = require("ajv");
-const ajv = new Ajv();
-
-// --- Schemas ---
-//TODO
-
-const newUserSchema = {
- type: 'object',
- properties: {
- email: { type: 'string', format: 'email' },
- name: { type: 'string' },
- password: { type: 'string', minLength: 3, maxLength: 30 },
- },
- required: ['name', 'email', 'password'],
- additionalProperties: false
-};
-
-const validateNewUserData = ajv.compile(newUserSchema);
-
-
-// --- Exports ---
-
-module.exports = { validateNewUserData };
\ No newline at end of file
diff --git a/src/services/authService.js b/src/services/authService.js
deleted file mode 100644
index e9dee2b..0000000
--- a/src/services/authService.js
+++ /dev/null
@@ -1,85 +0,0 @@
-const userModel = require("../models/user");
-const AppError = require("../utils/appError");
-const cryptoUtils = require("../utils/crypto");
-const configManager = require("../utils/configManager");
-const validate = require("../utils/validate_legacy");
-
-const JWT_Secret = configManager.getJWTSecret();
-
-async function login(username, email, password) {
-
- // Check for null
- if (!(username || email) || !password) {
- throw new AppError(400, "Bad request", "missing credentials");
- }
-
- // Get user data
- let user_get;
- if (email) { // If matches email
- user_get = await userModel.getUserByEmail(email);
- } else
- if (username) { // if matches username
- user_get = await userModel.getUserByName(username);
- } else {
- console.debug("Failed finding user, weird...")
- throw new AppError(401, "Unauthorized", "Invalid credentials");
- }
-
- // Check if user exists
- if (!user_get || user_get.length == 0) {
- // throw new AppError(401, "Unauthorized: No user with this name");
- throw new AppError(401, "Unauthorized", "Invalid credentials");
- }
- // Just in case
- if (user_get.length > 1) {
- throw new AppError(500, "Internal server error", "Found multiple users with this name or email, please contact administration");
- }
-
- const user = user_get[0];
-
- // Get user password
- const saved_password_get = await userModel.getUserPassword(user.username);
- // Check if retrieved password sucessfully
- if (!saved_password_get || saved_password_get.length == 0) {
- throw new AppError(500, "Unable to retrieve user password");
- }
- saved_password = saved_password_get[0].password;
- // Check if retrieved password sucessfully again
- if (!saved_password) {
- throw new AppError(500, "Unable to retrieve user password");
- }
-
- // Check if passwords match
- const passwords_match = await cryptoUtils.passwordsMatch(password, saved_password)
- if (!passwords_match) {
- // throw new AppError(401, "Unauthorized: Invalid password");
- console.debug(password, "differs from", saved_password);
- throw new AppError(401, "Unauthorized", "Invalid credentials");
- }
-
- const payload = { type: "user",
- username: user.username,
- email: user.email,
- role: user.role };
-
- const token = await cryptoUtils.signToken(payload);
- return token;
-
- // // Check if passwords match
- // const passwords_match = await bcrypt.compare(password, user[0].password);
- // if (!passwords_match) {
- // // throw new AppError(401, "Unauthorized: Invalid password");
- // console.debug("Password doesn't match")
- // throw new AppError(401, "Unauthorized", "Invalid credentials");
- // }
-
- // return jwt.sign({ username: user[0].username, role: user[0].role }, await JWT_Secret);
-}
-
-// function authorizeRole(user, roles) {
-// if (!user || !roles.includes(user.role)) {
-// throw new AppError(401, "Unauthorized: You don't have the necessary permissions to access this resource");
-// }
-// }
-
-module.exports = { login };
\ No newline at end of file
diff --git a/src/services/indexService.js b/src/services/indexService.js
deleted file mode 100644
index d2fc506..0000000
--- a/src/services/indexService.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const model = require("../models/index");
-
-async function getVersion() {
- return model.getVersion();
-}
-
-module.exports = { getVersion }
diff --git a/src/services/modService.js b/src/services/modService.js
deleted file mode 100644
index 4cd8862..0000000
--- a/src/services/modService.js
+++ /dev/null
@@ -1,164 +0,0 @@
-const model = require("../models/mod");
-const AppError = require("../utils/appError");
-const { validateModData } = require("../utils/validate_legacy");
-const { mdToHtml } = require("../utils/convert");
-const { sanitizeModData } = require("../utils/sanitize");
-
-
-// --- Get ---
-
-async function getAllMods() {
- return model.getAllMods();
-}
-
-async function getModByName(name) {
- const res = model.getModByName(name);
- if (res.length == 0) {
- throw new AppError(404, "Cannot find mod with this name", "Not found");
- }
- return res[0];
-}
-
-async function getFullModInfos(name) {
- const res = model.getFullModInfos(name);
- if (res.length == 0) {
- throw new AppError(404, "Cannot find mod with this name", "Not found");
- }
- return res[0];
-}
-
-async function getModVersion(infos) {
- const { mod, version_number, game_version, platform, environment} = infos;
- const res = model.getModVersion(mod, version_number, game_version, platform, environment);
- if (res.length == 0) {
- throw new AppError(404, "Cannot find mod with this name", "Not found");
- }
- return res[0];
-}
-
-
-// --- Create ---
-
-async function createMod(mod_data, author) {
-
- // Check body validity
- //TODO
- console.warn("Skipping validity checks for createMod");
- // await validateModData(mod_data);
-
- // Generate data
- const { name, display_name, description, mod_infos } = mod_data;
- mod_infos.full_description = await mdToHtml(mod_infos.full_description); // Convert
- await sanitizeModData(mod_data); // Sanitize
- //TODO
- mod_infos.creation_date = 0
-
- // Write changes to database
- await model.createMod(name, display_name, author, description, mod_infos);
-
- // Return
- return getModByName(name);
-}
-
-async function addVersion(version_data) {
-
- // Validate
- //TODO
- console.warn("Skipping validity checks for addVersion");
-
- // Generate data
- const { mod_name, version_number, channel, changelog, game_version,
- platform, environment, url } = version_data; // Split
- changelog = await mdToHtml(changelog); // Convert
- await sanitizeModData(mod_data); // Sanitize
- const release_date = (new Date()).toLocaleDateString();
-
- // Write changes
- await model.addVersion(mod_name, version_number, channel, changelog,
- release_date, game_version, platform, environment, url); // Database
-
- // Return
- return await model.getModVersion(mod_name, version_number, game_version, platform, environment );
-}
-
-async function addTags(mod, tags) {
-
- // Validate
- //TODO
- console.warn("Skipping validity checks for addTags");
-
- // Write changes
- await model.addTags(mod, tags);
-
- // Return
- const { tags:res } = await model.getFullModInfos(mod);
- return { "mod": mod, "tags": res};
-
-}
-
-// --- Update ---
-
-async function updateMod(diff_data) {
- //TODO
- throw new AppError(501, "Not implemented");
-}
-
-
-
-// Delete
-
-async function deleteMod(name) {
-
- // Check existence
- const mod = await model.getModByName(name);
- if (!mod) {
- throw new AppError(404, "No was found with this name", "Not found")
- }
-
- // Authorize
- // TODO move outside of this function
- if (mod.author != mod.user) {
- throw new AppError(403, "You don't have the necessary permissions to execute this action", "Forbidden");
- }
-
- // Write changes to database
- await model.deleteMod(name);
-
- // Return
- return mod;
-}
-
-async function deleteVersion(version_infos) {
-
- // Validate
- // TODO
-
- // Generate data
- const res = await getModVersion(version_infos);
- const { mod, version_number, game_version, platform, environment} = version_infos;
-
- // Write changes to db
- await model.deleteVersion(mod, version_number, game_version, platform, environment);
-
- // Return
- return res;
-}
-
-async function deleteTags(mod, tags) {
-
- // Validate (check existence)
- //TODO
- console.warn("Skipping validity checks for deleteTags");
-
- // Wites changes to db
- await model.deleteTags(mod, tags);
-
- // Return
- const { tags:res } = await model.getFullModInfos(mod);
- return { "mod": mod, "tags": res};
-}
-
-module.exports = { getAllMods, getModByName, getFullModInfos,
- createMod, addTags, addVersion,
- updateMod,
- deleteMod, deleteTags, deleteVersion };
\ No newline at end of file
diff --git a/src/services/modpackService.js b/src/services/modpackService.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/services/userService.js b/src/services/userService.js
deleted file mode 100644
index 8020e25..0000000
--- a/src/services/userService.js
+++ /dev/null
@@ -1,46 +0,0 @@
-const model = require("../models/user");
-const AppError = require("../utils/appError");
-const cryptoUtils = require("../utils/crypto");
-const { validateUserData } = require("../utils/validate_legacy");
-const { sanitizeUserData } = require("../utils/sanitize");
-
-async function getAllUsers() {
- return await model.getAllUsers();
-}
-
-async function getUserByName(name) {
- const res = await model.getUserByName(name);
- return res[0];
-}
-
-async function createUser(user_data) {
-
- // Check body validity
- // TODO
-
- // Sanitize
- // TODO
-
- // Gather data
- const { username, email, password, display_name, profile_picture, settings } = user_data
- const password_hash = await cryptoUtils.hashPassword(password);
-
- await model.createUser(username, email, password_hash, display_name, null, null);
- return model.getUserByName(username);
-}
-
-async function deleteUser(name, token_user) {
-
- // Check existence
- const exists = await model.exists(name);
- if (!exists) {
- throw new AppError(404, "Cannot find user with this name", "Not found");
- }
-
- const res = await model.getUserByName(name);
- await model.deleteUser(name);
-
- return res;
-}
-
-module.exports = { getAllUsers, getUserByName, createUser, deleteUser };
\ No newline at end of file
diff --git a/src/utils/appError.js b/src/utils/appError.js
deleted file mode 100644
index 5246dbc..0000000
--- a/src/utils/appError.js
+++ /dev/null
@@ -1,27 +0,0 @@
-class AppError extends Error {
- constructor(statusCode, message, status = "", debugMsg = "") {
- super(message);
- this.statusCode = statusCode;
- this.debugMsg = debugMsg;
- // Get status
- if (status === "") {
- if (statusCode.toString().startsWith("4")) {
- this.status = "Fail";
- } else {
- this.status = "Error";
- }
- } else {
- this.status = status;
- }
- }
-}
-
-exports.tryCatch = (controller) => async (req, res, next) => {
- try {
- await controller(req, res, next);
- } catch(err) {
- next(err);
- }
-}
-
-module.exports = AppError;
\ No newline at end of file
diff --git a/src/utils/configManager.js b/src/utils/configManager.js
deleted file mode 100644
index 5017a6f..0000000
--- a/src/utils/configManager.js
+++ /dev/null
@@ -1,89 +0,0 @@
-// --- Define constants ---
-
-// Imports
-const fs = require("fs");
-const path = require("path");
-const { version } = require("../../package.json");
-
-
-// Var decalaration
-const config_folder = "config";
-const config_file_name = "config.json"
-
-// Global variables
-let config = {};
-
-// --- Default config ---
-
-const default_config = {
-
- "port": 8000,
-
- "users": {
- "admin": {
- "username": "admin",
- "password": "admin"
- }
- },
-
- "database": {
- "type": "sqlite"
- },
-
- "auth" : {
- "JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY",
- "tokenExpiry": "1h"
- }
-}
-
-
-// --- Functions ---
-
-function loadConfig() {
-
- let user_config;
-
- // Parse
- try {
- // Get user config
- user_config = JSON.parse(fs.readFileSync(path.resolve(path.join(config_folder, config_file_name))));
-
- // Warns
- if (!user_config.auth || !user_config.auth.JWT_secret) {
- console.warn("WARNING: No JWT secret provided, using the default one. Please note that using the default secret is a major security risk.")
- }
-
- // Merge default and user configs (default values)
- config = { ...default_config, ...user_config };
- }
- catch (err) {
- // Error messages
- console.debug("Error:", err)
- console.error("Error loading configuration, using the default settings");
- console.debug("Search path:", path.resolve("./"));
- console.debug("Config file:", path.resolve(path.join(config_folder, config_file_name)))
-
- config = default_config;
- }
-
- return config;
-
-}
-
-
-async function getConfig() {
- return config;
-}
-
-async function getJWTSecret() {
- return config.auth.JWT_secret || process.env.JWT_secret;
-}
-
-async function getVersion() {
- // Could be done with process.env.npm_package_version
- // but may not work without without npm
- return version;
-}
-
-// Exports
-module.exports = { loadConfig, getConfig, getVersion, getJWTSecret };
\ No newline at end of file
diff --git a/src/utils/convert.js b/src/utils/convert.js
deleted file mode 100644
index 39a56a9..0000000
--- a/src/utils/convert.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const marked = require("marked");
-
-async function mdToHtml(md_content) {
- if (md_content) {
- return marked.parse(md_content);
- } else {
- return "";
- }
-}
-
-module.exports = { mdToHtml };
\ No newline at end of file
diff --git a/src/utils/crypto.js b/src/utils/crypto.js
deleted file mode 100644
index be1ffc5..0000000
--- a/src/utils/crypto.js
+++ /dev/null
@@ -1,61 +0,0 @@
-// --- Imports ---
-const jwt = require("jsonwebtoken");
-const bcrypt = require("bcrypt");
-const { getConfig, getJWTSecret } = require("./configManager");
-
-
-// --- Config ---
-
-// Declarations
-let JWT_Secret;
-let token_expiry;
-// Constant values
-const saltRounds = 12;
-// Load
-(async () => {
- const config = await getConfig();
- JWT_Secret = await getJWTSecret();
- token_expiry = config.auth.tokenExpiry;
- signature_algorithm = config.auth.signatureAlgorithm;
-})();
-
-
-// --- Functions ---
-
-async function hashPassword(passwd) {
- const hash = bcrypt.hashSync(passwd, saltRounds);
- return hash;
-}
-
-
-async function passwordsMatch(password, hashed_password) {
- return await bcrypt.compare(password, hashed_password);
-}
-
-
-async function signToken(payload, options = null) {
- if (options == null) {
- return jwt.sign(payload, JWT_Secret, { expiresIn: token_expiry, });
- }
- else {
- return jwt.sign(payload, JWT_Secret, options);
- }
-
-}
-
-
-function verifyToken(token) {
- return new Promise( async (resolve, reject) => {
- await jwt.verify( token, JWT_Secret, (err, user) => {
- if (err) {
- reject(err);
- } else {
- resolve(user);
- }
- });
- });
-}
-
-
-// --- Exports ---
-module.exports = { passwordsMatch, hashPassword, verifyToken, signToken };
\ No newline at end of file
diff --git a/src/utils/sanitize.js b/src/utils/sanitize.js
deleted file mode 100644
index be3885b..0000000
--- a/src/utils/sanitize.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const createDOMPurify = require("dompurify");
-const { JSDOM } = require("jsdom");
-
-// Initialize
-const window = new JSDOM("").window;
-const DOMPurify = createDOMPurify(window);
-
-async function sanitizeText(text) {
- return DOMPurify.sanitize(text);
-}
-
-async function sanitizeModData(mod_data) {
- console.warn("Skipping sanitanization (not implemented)");
- // mod_data.displayName = await sanitizeText(mod_data.displayName);
- // mod_data.otherInfos.description = await sanitizeText(mod_data.otherInfos.description);
- // mod_data.otherInfos.changelogs = await sanitizeText(mod_data.otherInfos.changelogs);
-}
-
-module.exports = { sanitizeText, sanitizeModData };
\ No newline at end of file
diff --git a/src/utils/validate.js b/src/utils/validate.js
deleted file mode 100644
index b7c3519..0000000
--- a/src/utils/validate.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// --- Imports ---
-const AppError = require("./appError");
-
-
-// --- Functions ---
-
-async function validateNewModData(mod_data) {
-
- throw new AppError(501, "Not implemented");
- //TODO
- // try {
- // node_schemas.validateNewModData(node_data);
- // } catch (err) {
- // throw new AppError(400, "Missing or invalid fields", "Bad request", err);
- // }
-
-}
-
-
-async function validateNewUserData(user_data) {
-
- throw new AppError(501, "Not implemented");
- //TODO
- // try {
- // node_schemas.validateNewUserData(node_data);
- // } catch (err) {
- // throw new AppError(400, "Missing or invalid fields", "Bad request", err);
- // }
-
-}
-
-async function validateCretendials(identifier, password) {
-
- throw new AppError(501, "Not implemented");
-}
-
-
-// --- Utils ---
-
-async function isEmail(text) {
- const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
- return email_regex.test(text);
-}
-
-async function isID(text) {
- const id_regex = /[a-zA-Z0-9_]+/;
- return id_regex.test(text);
-}
-
-
-module.exports = { validateNewModData, validateNewUserData, isEmail, isID };
\ No newline at end of file
diff --git a/src/utils/validate_legacy.js b/src/utils/validate_legacy.js
deleted file mode 100644
index 63c605b..0000000
--- a/src/utils/validate_legacy.js
+++ /dev/null
@@ -1,98 +0,0 @@
-const mod_model = require("../models/mod");
-const user_model = require("../models/user");
-const AppError = require("./appError");
-
-async function validateModData(mod_data) {
- //TODO WIP
- // Check fields existence
- const not_null = mod_data &&
- Object.keys(mod_data).length == 5 &&
- mod_data.name &&
- mod_data.displayName &&
- mod_data.author &&
- mod_data.versions != null;
-
- // mod_data.otherInfos != null &&
- // Object.keys(mod_data.otherInfos).length == 0 &&
- // mod_data.otherInfos.description != null &&
- // mod_data.otherInfos.links != null &&
- // mod_data.otherInfos.tags != null &&
- // mod_data.otherInfos.screenshots != null &&
- // mod_data.otherInfos.license != null &&
- // mod_data.otherInfos.changelogs != null;
-
- if (!not_null) {
- console.debug("Item is missing expected fields:", mod_data);
- throw new AppError(400, "Bad request", "Missing expected fields");
- }
-
- // Check fields format (check if sanitized)
- const is_valid_name = /^[a-zA-Z0-9_]+$/.test(mod_data.name);
- const is_valid_displayName = true;
- // const is_valid_displayName = /^[a-zA-Z0-9_]+$/.test(mod_data.name); // Temporary
- // const
-
- const is_valid = is_valid_name && is_valid_displayName;
- if (!is_valid) {
- console.debug("Fields are not following the expected formats");
- throw new AppError(400, "Bad request", "The provided fields don't match the expected format");
- }
-
- // Check if mod already exists
- const exists = await mod_model.exists(mod_data.name);
- if (exists) {
- console.debug("Error: Item already exists");
- throw new AppError(403, "Forbidden", "Content with this name already exists");
- }
-}
-
-
-async function validateUserData(user_data) {
- throw new AppError(501, "Not implemented");
-
- //TODO
-
- // Check fields existence
- // ...
-
- if (!not_null) {
- console.debug("Missing expected fields:", mod_data);
- throw new AppError(400, "Bad request: Missing expected fields");
- }
-
- // Check fields format (check if sanitized)
- const is_valid_username = /^[a-zA-Z0-9_]+$/.test(user_data.username);
- // const is_valid_email = ...
- // ...
-
- const is_valid = is_valid_username && is_valid_email;
- if (!is_valid) {
- console.debug("Fields are not following the expected formats");
- throw new AppError(400, "Bad request: The provided fields don't match the expected format");
- }
-
- // Check if user already exists
- const exists = await user_model.exists(user_data.username);
- if (exists) {
- console.debug("Error: User already exists");
- throw new AppError(403, "Forbidden: User with this name already exists");
- }
-}
-
-async function validateCretendials(identifier, password) {
-
- throw new AppError(501, "Not implemented");
-}
-
-async function isEmail(text) {
- const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
- return email_regex.test(text);
-}
-
-async function isID(text) {
- const id_regex = /[a-zA-Z0-9_]+/;
- return id_regex.test(text);
-}
-
-
-module.exports = { validateModData, validateUserData, isEmail, isID };
\ No newline at end of file