From f05dcabd1b7dcffd93814b29db4d115535d6a1a4 Mon Sep 17 00:00:00 2001 From: Bernd Storath <32197462+kaaax0815@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:36:48 +0100 Subject: [PATCH] Feat: SQLite (#1619) * start drizzle migration * split schema * improve schema * improve schema, cascade, unique * improve structure, start migration * migrate to sqlite * work in prod docker * start adding a better permission handler * permission matrix, permission handler * update packages * move session timeout to session config, use new permission handler * improve docker dev only install dependencies if changed * implement setup * migrate to sqlite * improve debug, fix custom migration * migrate to sqlite * regenerate migrations * ignore autogenerated migrations from prettier * migrate to sqlite * migrate to sqlite * Migrate to sqlite * fix prod error * move nuxt middleware from server to nuxt * update corepack in prod dockerfile * use correct branch for workflow * make docker file build on armv6/v7 * fix client update * update zod locales * cancel pr workflow if new commit * test concurrency --- .github/workflows/deploy-development.yml | 2 - .github/workflows/deploy-pr.yml | 6 +- .vscode/settings.json | 11 +- Dockerfile | 13 +- Dockerfile.dev | 20 +- package.json | 4 +- src/.gitignore | 2 + src/.npmrc | 1 + src/.prettierignore | 1 + src/app/app.vue | 4 +- src/app/components/ClientCard/Address.vue | 2 +- .../components/ClientCard/OneTimeLinkBtn.vue | 6 +- src/app/components/admin/CidrDialog.vue | 14 +- src/app/components/ui/UserMenu.vue | 2 +- src/app/middleware/auth.global.ts | 28 + src/app/pages/admin/config.vue | 49 +- src/app/pages/admin/hooks.vue | 8 +- src/app/pages/admin/interface.vue | 34 + src/app/pages/clients/[id].vue | 12 +- src/app/stores/auth.ts | 13 +- src/app/stores/modal.ts | 8 +- src/app/utils/api.ts | 19 - src/drizzle.config.ts | 10 + src/eslint.config.mjs | 2 + src/i18n/locales/en.json | 97 +- src/nuxt.config.ts | 9 + src/package.json | 30 +- src/pnpm-lock.yaml | 3112 ++++++++++------- src/server/api/admin/general.get.ts | 8 +- src/server/api/admin/general.post.ts | 21 +- src/server/api/admin/hooks.get.ts | 9 +- src/server/api/admin/hooks.post.ts | 23 +- src/server/api/admin/hostport.post.ts | 8 - src/server/api/admin/interface.get.ts | 4 - src/server/api/admin/interface.post.ts | 9 - src/server/api/admin/interface/cidr.post.ts | 15 + src/server/api/admin/interface/index.get.ts | 12 + src/server/api/admin/interface/index.post.ts | 14 + src/server/api/admin/userconfig.get.ts | 7 + src/server/api/admin/userconfig.post.ts | 14 + src/server/api/admin/userconfig/cidr.post.ts | 9 - src/server/api/admin/userconfig/index.get.ts | 4 - src/server/api/admin/userconfig/index.post.ts | 9 - .../client/[clientId]/configuration.get.ts | 51 +- .../api/client/[clientId]/disable.post.ts | 22 +- .../api/client/[clientId]/enable.post.ts | 22 +- .../[clientId]/generateOneTimeLink.post.ts | 21 +- .../api/client/[clientId]/index.delete.ts | 22 +- src/server/api/client/[clientId]/index.get.ts | 26 +- .../api/client/[clientId]/index.post.ts | 36 +- .../api/client/[clientId]/qrcode.svg.get.ts | 23 +- src/server/api/client/index.get.ts | 2 +- src/server/api/client/index.post.ts | 22 +- src/server/api/session.get.ts | 2 +- src/server/api/session.post.ts | 20 +- src/server/api/setup/4.post.ts | 17 +- src/server/api/setup/5.post.ts | 16 +- src/server/api/setup/migrate.post.ts | 18 +- src/server/api/wireguard/backup.get.ts | 15 +- src/server/api/wireguard/restore.put.ts | 13 +- .../database/migrations/0000_short_skin.sql | 100 + .../migrations/0001_classy_the_stranger.sql | 18 + .../migrations/meta/0000_snapshot.json | 686 ++++ .../migrations/meta/0001_snapshot.json | 686 ++++ .../database/migrations/meta/_journal.json | 20 + .../database/repositories/client/schema.ts | 37 + .../database/repositories/client/service.ts | 128 + .../database/repositories/client/types.ts | 72 + .../database/repositories/general/schema.ts | 16 + .../database/repositories/general/service.ts | 68 + .../database/repositories/general/types.ts | 15 + .../database/repositories/hooks/schema.ts | 24 + .../database/repositories/hooks/service.ts | 34 + .../database/repositories/hooks/types.ts | 18 + .../database/repositories/interface/schema.ts | 39 + .../repositories/interface/service.ts | 90 + .../database/repositories/interface/types.ts | 49 + .../database/repositories/metrics/schema.ts | 21 + .../database/repositories/metrics/service.ts | 31 + .../database/repositories/metrics/types.ts | 4 + .../repositories/oneTimeLink/schema.ts | 27 + .../repositories/oneTimeLink/service.ts | 52 + .../repositories/oneTimeLink/types.ts | 17 + .../database/repositories/user/schema.ts | 19 + .../database/repositories/user/service.ts | 63 + .../database/repositories/user/types.ts | 43 + .../repositories/userConfig/schema.ts | 29 + .../repositories/userConfig/service.ts | 50 + .../database/repositories/userConfig/types.ts | 31 + src/server/database/schema.ts | 12 + src/server/database/sqlite.ts | 63 + src/server/middleware/auth.ts | 35 - src/server/middleware/session.ts | 94 - src/server/middleware/setup.ts | 6 +- src/server/routes/cnf/[oneTimeLink].ts | 6 +- src/server/routes/metrics/index.get.ts | 6 +- src/server/routes/metrics/json.get.ts | 6 +- src/server/utils/Database.ts | 9 +- src/server/utils/WireGuard.ts | 376 +- src/server/utils/cmd.ts | 7 +- src/server/utils/crypto.ts | 7 - src/server/utils/handler.ts | 59 + src/server/utils/ip.ts | 38 +- src/server/utils/metrics.ts | 74 + src/server/utils/session.ts | 101 +- src/server/utils/template.ts | 17 +- src/server/utils/types.ts | 231 +- src/server/utils/wgHelper.ts | 77 +- src/services/database/lowdb.ts | 356 -- src/services/database/migrations/1.ts | 87 - src/services/database/migrations/index.ts | 30 - src/services/database/repositories/client.ts | 62 - .../database/repositories/database.ts | 81 - src/services/database/repositories/setup.ts | 11 - src/services/database/repositories/system.ts | 90 - src/services/database/repositories/user.ts | 41 - src/shared/utils/permissions.ts | 31 + 117 files changed, 5437 insertions(+), 3096 deletions(-) create mode 100644 src/.npmrc create mode 100644 src/app/middleware/auth.global.ts create mode 100644 src/drizzle.config.ts delete mode 100644 src/server/api/admin/hostport.post.ts delete mode 100644 src/server/api/admin/interface.get.ts delete mode 100644 src/server/api/admin/interface.post.ts create mode 100644 src/server/api/admin/interface/cidr.post.ts create mode 100644 src/server/api/admin/interface/index.get.ts create mode 100644 src/server/api/admin/interface/index.post.ts create mode 100644 src/server/api/admin/userconfig.get.ts create mode 100644 src/server/api/admin/userconfig.post.ts delete mode 100644 src/server/api/admin/userconfig/cidr.post.ts delete mode 100644 src/server/api/admin/userconfig/index.get.ts delete mode 100644 src/server/api/admin/userconfig/index.post.ts create mode 100644 src/server/database/migrations/0000_short_skin.sql create mode 100644 src/server/database/migrations/0001_classy_the_stranger.sql create mode 100644 src/server/database/migrations/meta/0000_snapshot.json create mode 100644 src/server/database/migrations/meta/0001_snapshot.json create mode 100644 src/server/database/migrations/meta/_journal.json create mode 100644 src/server/database/repositories/client/schema.ts create mode 100644 src/server/database/repositories/client/service.ts create mode 100644 src/server/database/repositories/client/types.ts create mode 100644 src/server/database/repositories/general/schema.ts create mode 100644 src/server/database/repositories/general/service.ts create mode 100644 src/server/database/repositories/general/types.ts create mode 100644 src/server/database/repositories/hooks/schema.ts create mode 100644 src/server/database/repositories/hooks/service.ts create mode 100644 src/server/database/repositories/hooks/types.ts create mode 100644 src/server/database/repositories/interface/schema.ts create mode 100644 src/server/database/repositories/interface/service.ts create mode 100644 src/server/database/repositories/interface/types.ts create mode 100644 src/server/database/repositories/metrics/schema.ts create mode 100644 src/server/database/repositories/metrics/service.ts create mode 100644 src/server/database/repositories/metrics/types.ts create mode 100644 src/server/database/repositories/oneTimeLink/schema.ts create mode 100644 src/server/database/repositories/oneTimeLink/service.ts create mode 100644 src/server/database/repositories/oneTimeLink/types.ts create mode 100644 src/server/database/repositories/user/schema.ts create mode 100644 src/server/database/repositories/user/service.ts create mode 100644 src/server/database/repositories/user/types.ts create mode 100644 src/server/database/repositories/userConfig/schema.ts create mode 100644 src/server/database/repositories/userConfig/service.ts create mode 100644 src/server/database/repositories/userConfig/types.ts create mode 100644 src/server/database/schema.ts create mode 100644 src/server/database/sqlite.ts delete mode 100644 src/server/middleware/auth.ts delete mode 100644 src/server/middleware/session.ts delete mode 100644 src/server/utils/crypto.ts create mode 100644 src/server/utils/handler.ts create mode 100644 src/server/utils/metrics.ts delete mode 100644 src/services/database/lowdb.ts delete mode 100644 src/services/database/migrations/1.ts delete mode 100644 src/services/database/migrations/index.ts delete mode 100644 src/services/database/repositories/client.ts delete mode 100644 src/services/database/repositories/database.ts delete mode 100644 src/services/database/repositories/setup.ts delete mode 100644 src/services/database/repositories/system.ts delete mode 100644 src/services/database/repositories/user.ts create mode 100644 src/shared/utils/permissions.ts diff --git a/.github/workflows/deploy-development.yml b/.github/workflows/deploy-development.yml index 608a9474..212ccff4 100644 --- a/.github/workflows/deploy-development.yml +++ b/.github/workflows/deploy-development.yml @@ -13,8 +13,6 @@ jobs: contents: read steps: - uses: actions/checkout@v4 - with: - ref: master - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.github/workflows/deploy-pr.yml b/.github/workflows/deploy-pr.yml index c31befbc..d1c226c1 100644 --- a/.github/workflows/deploy-pr.yml +++ b/.github/workflows/deploy-pr.yml @@ -4,6 +4,10 @@ on: workflow_dispatch: pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: deploy: name: Build & Deploy @@ -14,8 +18,6 @@ jobs: contents: read steps: - uses: actions/checkout@v4 - with: - ref: master - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.vscode/settings.json b/.vscode/settings.json index c8e84b69..25e14c36 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,13 +12,12 @@ "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "typescript.tsdk": "./src/node_modules/typescript/lib", - "i18n-ally.enabledFrameworks": [ - "vue" - ], - "i18n-ally.localesPaths": [ - "src/i18n/locales" - ], + "i18n-ally.enabledFrameworks": ["vue"], + "i18n-ally.localesPaths": ["src/i18n/locales"], "i18n-ally.sortKeys": false, "i18n-ally.keepFulfilled": false, "i18n-ally.keystyle": "nested", diff --git a/Dockerfile b/Dockerfile index 65b66d62..efdda18b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,8 @@ FROM docker.io/library/node:18-alpine AS build WORKDIR /app +# update corepack +RUN npm install --global corepack@latest # Install pnpm RUN corepack enable pnpm @@ -15,6 +17,10 @@ RUN pnpm install # Build UI RUN pnpm build +# Remove unnecessary node modules +RUN find ./node_modules/.pnpm -mindepth 1 -maxdepth 1 -type d ! -name '@libsql+linux*' -exec rm -r {} + +RUN find ./node_modules/@libsql -mindepth 1 -maxdepth 1 -type l ! -name 'linux*' -exec rm -r {} + + # Copy build result to a new image. # This saves a lot of disk space. FROM docker.io/library/node:lts-alpine @@ -24,6 +30,11 @@ HEALTHCHECK CMD /usr/bin/timeout 5s /bin/sh -c "/usr/bin/wg show | /bin/grep -q # Copy build COPY --from=build /app/.output /app +# Copy migrations +COPY --from=build /app/server/database/migrations /app/server/database/migrations +# libsql +COPY --from=build /app/node_modules/.pnpm/ /app/node_modules/.pnpm/ +COPY --from=build /app/node_modules/@libsql /app/node_modules/@libsql # Install Linux packages RUN apk add --no-cache \ @@ -40,7 +51,7 @@ RUN update-alternatives --install /usr/sbin/iptables iptables /usr/sbin/iptables RUN update-alternatives --install /usr/sbin/ip6tables ip6tables /usr/sbin/ip6tables-legacy 10 --slave /usr/sbin/ip6tables-restore ip6tables-restore /usr/sbin/ip6tables-legacy-restore --slave /usr/sbin/ip6tables-save ip6tables-save /usr/sbin/ip6tables-legacy-save # Set Environment -ENV DEBUG=Server,WireGuard,LowDB +ENV DEBUG=Server,WireGuard,Database,CMD ENV PORT=51821 ENV HOST=0.0.0.0 diff --git a/Dockerfile.dev b/Dockerfile.dev index cbd03238..53078a19 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,15 +1,11 @@ -# As a workaround we have to build on nodejs 18 -# nodejs 20 hangs on build with armv6/armv7 -FROM docker.io/library/node:20-alpine +FROM docker.io/library/node:lts-alpine WORKDIR /app +# update corepack +RUN npm install --global corepack@latest # Install pnpm RUN corepack enable pnpm -# Copy Web UI -COPY src ./ -RUN pnpm install - HEALTHCHECK CMD /usr/bin/timeout 5s /bin/sh -c "/usr/bin/wg show | /bin/grep -q interface || exit 1" --interval=1m --timeout=5s --retries=3 # Install Linux packages @@ -27,6 +23,14 @@ RUN update-alternatives --install /usr/sbin/iptables iptables /usr/sbin/iptables RUN update-alternatives --install /usr/sbin/ip6tables ip6tables /usr/sbin/ip6tables-legacy 10 --slave /usr/sbin/ip6tables-restore ip6tables-restore /usr/sbin/ip6tables-legacy-restore --slave /usr/sbin/ip6tables-save ip6tables-save /usr/sbin/ip6tables-legacy-save # Set Environment -ENV DEBUG=Server,WireGuard,LowDB +ENV DEBUG=Server,WireGuard,Database,CMD ENV PORT=51821 ENV HOST=0.0.0.0 + +# Install Dependencies +COPY src/package.json src/pnpm-lock.yaml ./ +RUN pnpm install + +# Copy Project +COPY src ./ + diff --git a/package.json b/package.json index 09863edf..0e2f6515 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "version": "1.0.0", "private": true, "scripts": { - "dev": "docker compose -f docker-compose.dev.yml up", + "dev": "docker compose -f docker-compose.dev.yml up --build", "build": "docker build -t wg-easy ." }, - "packageManager": "pnpm@9.15.3" + "packageManager": "pnpm@10.2.0" } diff --git a/src/.gitignore b/src/.gitignore index 4a7f73a2..7e0a1716 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -22,3 +22,5 @@ logs .env .env.* !.env.example + +wg0.db diff --git a/src/.npmrc b/src/.npmrc new file mode 100644 index 00000000..3fda400e --- /dev/null +++ b/src/.npmrc @@ -0,0 +1 @@ +public-hoist-pattern[]=@libsql/linux* diff --git a/src/.prettierignore b/src/.prettierignore index bd5535a6..48c57dec 100644 --- a/src/.prettierignore +++ b/src/.prettierignore @@ -1 +1,2 @@ pnpm-lock.yaml +server/database/migrations/meta diff --git a/src/app/app.vue b/src/app/app.vue index 025580ad..9ce499e4 100644 --- a/src/app/app.vue +++ b/src/app/app.vue @@ -5,7 +5,7 @@ - + @@ -13,7 +13,7 @@ diff --git a/src/app/components/ui/UserMenu.vue b/src/app/components/ui/UserMenu.vue index 8e956567..31547319 100644 --- a/src/app/components/ui/UserMenu.vue +++ b/src/app/components/ui/UserMenu.vue @@ -37,7 +37,7 @@ Account - + { + // api & setup handled server side + if (to.path.startsWith('/api/') || to.path.startsWith('/setup')) { + return; + } + + const authStore = useAuthStore(); + const userData = await authStore.getSession(); + + // skip login if already logged in + if (to.path === '/login') { + if (userData?.username) { + return navigateTo('/', { redirectCode: 302 }); + } + return; + } + // Require auth for every page other than Login + if (!userData?.username) { + return navigateTo('/login', { redirectCode: 302 }); + } + + // Check for admin access + if (to.path.startsWith('/admin')) { + if (userData.role !== roles.ADMIN) { + return abortNavigation('Not allowed to access Admin Panel'); + } + } +}); diff --git a/src/app/pages/admin/config.vue b/src/app/pages/admin/config.vue index ca399d77..c66d2b5b 100644 --- a/src/app/pages/admin/config.vue +++ b/src/app/pages/admin/config.vue @@ -8,7 +8,10 @@ Allowed IPs - + DNS @@ -16,10 +19,14 @@ Advanced - + @@ -27,14 +34,6 @@ Actions - - - @@ -79,30 +78,4 @@ async function revert() { await refresh(); data.value = toRef(_data.value).value; } - -async function changeCidr(address4: string, address6: string) { - try { - const res = await $fetch(`/api/admin/userconfig/cidr`, { - method: 'post', - body: { address4, address6 }, - }); - toast.showToast({ - type: 'success', - title: 'Success', - message: 'Changed CIDR', - }); - if (!res.success) { - throw new Error('Failed to change CIDR'); - } - await refreshNuxtData(); - } catch (e) { - if (e instanceof Error) { - toast.showToast({ - type: 'error', - title: 'Error', - message: e.message, - }); - } - } -} diff --git a/src/app/pages/admin/hooks.vue b/src/app/pages/admin/hooks.vue index 1566e8a6..a613b0f2 100644 --- a/src/app/pages/admin/hooks.vue +++ b/src/app/pages/admin/hooks.vue @@ -2,10 +2,10 @@
- - - - + + + + Actions diff --git a/src/app/pages/admin/interface.vue b/src/app/pages/admin/interface.vue index def6fc4a..7984c760 100644 --- a/src/app/pages/admin/interface.vue +++ b/src/app/pages/admin/interface.vue @@ -11,6 +11,14 @@ Actions + + +
@@ -55,4 +63,30 @@ async function revert() { await refresh(); data.value = toRef(_data.value).value; } + +async function changeCidr(ipv4Cidr: string, ipv6Cidr: string) { + try { + const res = await $fetch(`/api/admin/interface/cidr`, { + method: 'post', + body: { ipv4Cidr, ipv6Cidr }, + }); + toast.showToast({ + type: 'success', + title: 'Success', + message: 'Changed CIDR', + }); + if (!res.success) { + throw new Error('Failed to change CIDR'); + } + await refreshNuxtData(); + } catch (e) { + if (e instanceof Error) { + toast.showToast({ + type: 'error', + title: 'Error', + message: e.message, + }); + } + } +} diff --git a/src/app/pages/clients/[id].vue b/src/app/pages/clients/[id].vue index c7935b19..1f2fcabb 100644 --- a/src/app/pages/clients/[id].vue +++ b/src/app/pages/clients/[id].vue @@ -25,13 +25,13 @@ Address @@ -42,8 +42,8 @@ Server Allowed IPs diff --git a/src/app/stores/auth.ts b/src/app/stores/auth.ts index e1ed8d93..b574945d 100644 --- a/src/app/stores/auth.ts +++ b/src/app/stores/auth.ts @@ -3,6 +3,17 @@ export const useAuthStore = defineStore('Auth', () => { method: 'get', }); + async function getSession() { + try { + const { data } = await useFetch('/api/session', { + method: 'get', + }); + return data.value; + } catch { + return null; + } + } + /** * @throws if unsuccessful */ @@ -24,5 +35,5 @@ export const useAuthStore = defineStore('Auth', () => { return response.success; } - return { userData, login, logout, update }; + return { userData, login, logout, update, getSession }; }); diff --git a/src/app/stores/modal.ts b/src/app/stores/modal.ts index f3a1fd4e..0e6a1c5a 100644 --- a/src/app/stores/modal.ts +++ b/src/app/stores/modal.ts @@ -9,11 +9,13 @@ export const useModalStore = defineStore('Modal', () => { function createClient() { const name = clientCreateName.value; - const expireDate = clientExpireDate.value || null; + const expiresAt = clientExpireDate.value || null; if (!name) return; - api - .createClient({ name, expireDate }) + $fetch('/api/client', { + method: 'post', + body: { name, expiresAt }, + }) .catch((err) => alert(err.message || err.toString())) .finally(() => clientsStore.refresh().catch(console.error)); } diff --git a/src/app/utils/api.ts b/src/app/utils/api.ts index 231d533a..94b5b47b 100644 --- a/src/app/utils/api.ts +++ b/src/app/utils/api.ts @@ -5,25 +5,6 @@ class API { }); } - async createClient({ - name, - expireDate, - }: { - name: string; - expireDate: string | null; - }) { - return $fetch('/api/client', { - method: 'post', - body: { name, expireDate }, - }); - } - - async showOneTimeLink({ clientId }: { clientId: string }) { - return $fetch(`/api/client/${clientId}/generateOneTimeLink`, { - method: 'post', - }); - } - async restoreConfiguration(file: string) { return $fetch('/api/wireguard/restore', { method: 'put', diff --git a/src/drizzle.config.ts b/src/drizzle.config.ts new file mode 100644 index 00000000..3d0550cc --- /dev/null +++ b/src/drizzle.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + out: './server/database/migrations', + schema: './server/database/schema.ts', + dialect: 'sqlite', + dbCredentials: { + url: 'file:./wg0.db', + }, +}); diff --git a/src/eslint.config.mjs b/src/eslint.config.mjs index ad6fe8e4..07172140 100644 --- a/src/eslint.config.mjs +++ b/src/eslint.config.mjs @@ -2,3 +2,5 @@ import { createConfigForNuxt } from '@nuxt/eslint-config/flat'; import eslintConfigPrettier from 'eslint-config-prettier'; export default createConfigForNuxt().append(eslintConfigPrettier); + +// TODO: add typescript-eslint, import/order, ban raw defineEventHandler diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 6ba8c6b5..62083d46 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -39,58 +39,65 @@ "migration": "Restore the backup" }, "zod": { + "client": { + "id": "Client ID must be a valid number", + "name": "Name must be a valid string", + "nameMin": "Name must be at least 1 Character", + "expireDate": "expiredDate must be a valid string", + "expireDateMin": "expiredDate must be at least 1 Character", + "address4": "IPv4 Address must be a valid string", + "address4Min": "IPv4 Address must be a be at least 1 Character", + "address6": "IPv6 Address must be a valid string", + "address6Min": "IPv6 Address must be a be at least 1 Character", + "serverAllowedIps": "Allowed IPs must be a valid array of strings" + }, + "user": { + "username": "Username must be a valid string", + "usernameMin": "Username must be at least 8 Characters", + "password": "Password must be a valid string", + "passwordMin": "Password must be at least 12 Characters", + "passwordUppercase": "Password must have at least 1 uppercase letter", + "passwordLowercase": "Password must have at least 1 lowercase letter", + "passwordNumber": "Password must have at least 1 number", + "passwordSpecial": "Password must have at least 1 special character", + "remember": "Remember must be a valid boolean", + "accept": "Please accept the condition" + }, + "userConfig": { + "host": "Host must be a valid string", + "hostMin": "Host must contain at least 1 character" + }, + "general": { + "sessionTimeout": "Session Timeout must be a valid number" + }, + "interface": { + "cidr": "CIDR must be a valid string", + "cidrMin": "CIDR must be at least 1 Character", + "device": "Device must be a valid string", + "deviceMin": "Device must be at least 1 Character" + }, + "otl": { + "otl": "oneTimeLink must be a valid string", + "otlMin": "oneTimeLink must be at least 1 Character" + }, "stringMalformed": "String is malformed", - "id": "Client ID must be a valid UUID", - "address": "IP Address must be a valid string", - "addressMin": "IP Address must be a be at least 1 Character", - "address4": "IPv4 Address must be a valid string", - "address4Min": "IPv4 Address must be a be at least 1 Character", - "address6": "IPv6 Address must be a valid string", - "address6Min": "IPv6 Address must be a be at least 1 Character", - "allowedIps": "Allowed IPs must be a valid array of strings", - "allowedIpsMin": "Allowed IPs must have at least 1 item", - "serverAllowedIps": "Allowed IPs must be a valid array of strings", - "name": "Name must be a valid string", - "nameMin": "Name must be at least 1 Character", + "body": "Body must be a valid object", + "hook": "Hook must be a valid string", "mtu": "MTU must be a valid number", "mtuMin": "MTU must be at least 1280", "mtuMax": "MTU must be at most 9000", - "persistentKeepalive": "Persistent Keepalive must be a valid number", - "persistentKeepaliveMin": "Persistent Keepalive must be at least 0", - "persistentKeepaliveMax": "Persistent Keepalive must be at most 65535", - "file": "File must be a valid string", - "username": "Username must be a valid string", - "usernameMin": "Username must be at least 8 Characters", - "password": "Password must be a valid string", - "passwordMin": "Password must be at least 12 Characters", - "passwordUppercase": "Password must have at least 1 uppercase letter", - "passwordLowercase": "Password must have at least 1 lowercase letter", - "passwordNumber": "Password must have at least 1 number", - "passwordSpecial": "Password must have at least 1 special character", - "accept": "Please accept the condition", - "remember": "Remember must be a valid boolean", - "expireDate": "expiredDate must be a valid string", - "expireDateMin": "expiredDate must be at least 1 Character", - "otl": "oneTimeLink must be a valid string", - "otlMin": "oneTimeLink must be at least 1 Character", - "features": "key must be a valid string", - "ftBool": "enabled must be a valid boolean", - "ftObj": "value must be a valid object", - "ftObj2": "features must be a valid record", - "stat": "statistics must be a valid object", - "statBool": "enabled must be a valid boolean", - "statNumber": "chartType must be a valid number", - "body": "Body must be a valid object", - "host": "Host must be a valid string", - "hostMin": "Host must contain at least 1 character", "port": "Port must be a valid number", "portMin": "Port must be at least 1", "portMax": "Port must be at most 65535", - "sessionTimeout": "Session Timeout must be a valid number", - "device": "Device must be a valid string", - "deviceMin": "Device must be at least 1 Character", - "hook": "Hook must be a valid string", - "dns": "DNS must be a valid array of strings" + "persistentKeepalive": "Persistent Keepalive must be a valid number", + "persistentKeepaliveMin": "Persistent Keepalive must be at least 0", + "persistentKeepaliveMax": "Persistent Keepalive must be at most 65535", + "address": "IP Address must be a valid string", + "addressMin": "IP Address must be a be at least 1 Character", + "dns": "DNS must be a valid array of strings", + "dnsMin": "DNS must have at least 1 item", + "allowedIps": "Allowed IPs must be a valid array of strings", + "allowedIpsMin": "Allowed IPs must have at least 1 item" }, "name": "Name", "username": "Username", diff --git a/src/nuxt.config.ts b/src/nuxt.config.ts index 25904814..57b2cf54 100644 --- a/src/nuxt.config.ts +++ b/src/nuxt.config.ts @@ -1,3 +1,5 @@ +import { fileURLToPath } from 'node:url'; + // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ future: { @@ -44,5 +46,12 @@ export default defineNuxtConfig({ target: 'es2020', }, }, + alias: { + '#db': fileURLToPath(new URL('./server/database/', import.meta.url)), + }, + }, + alias: { + // for typecheck reasons (https://github.com/nuxt/cli/issues/323) + '#db': fileURLToPath(new URL('./server/database/', import.meta.url)), }, }); diff --git a/src/package.json b/src/package.json index 69387ea7..f7df9a36 100644 --- a/src/package.json +++ b/src/package.json @@ -14,30 +14,33 @@ "format": "prettier . --write", "format:check": "prettier . --check", "typecheck": "nuxt typecheck", - "check:all": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm build" + "check:all": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm build", + "db:generate": "drizzle-kit generate" }, "dependencies": { "@eschricht/nuxt-color-mode": "^1.1.5", - "@nuxtjs/i18n": "^9.1.1", - "@nuxtjs/tailwindcss": "^6.12.2", + "@libsql/client": "^0.14.0", + "@nuxtjs/i18n": "^9.1.5", + "@nuxtjs/tailwindcss": "^6.13.1", "@pinia/nuxt": "^0.9.0", "@tailwindcss/forms": "^0.5.10", - "apexcharts": "^4.3.0", + "apexcharts": "^4.4.0", "argon2": "^0.41.1", "basic-auth": "^2.0.1", "cidr-tools": "^11.0.2", "crc-32": "^1.2.2", "debug": "^4.4.0", + "drizzle-orm": "^0.39.1", "ip-bigint": "^8.2.0", "is-cidr": "^5.1.0", "is-ip": "^5.0.1", "js-sha256": "^0.11.0", "lowdb": "^7.0.1", - "nuxt": "^3.15.1", - "pinia": "^2.3.0", + "nuxt": "^3.15.4", + "pinia": "^2.3.1", "qrcode": "^1.5.4", - "radix-vue": "^1.9.12", - "semver": "^7.6.3", + "radix-vue": "^1.9.13", + "semver": "^7.7.1", "tailwindcss": "^3.4.17", "timeago.js": "^4.0.2", "vue": "latest", @@ -45,16 +48,17 @@ "zod": "^3.24.1" }, "devDependencies": { - "@nuxt/eslint-config": "^0.7.5", + "@nuxt/eslint-config": "^1.0.0", "@types/debug": "^4.1.12", "@types/qrcode": "^1.5.5", "@types/semver": "^7.5.8", - "eslint": "^9.17.0", - "eslint-config-prettier": "^9.1.0", + "drizzle-kit": "^0.30.4", + "eslint": "^9.19.0", + "eslint-config-prettier": "^10.0.1", "prettier": "^3.4.2", - "prettier-plugin-tailwindcss": "^0.6.9", + "prettier-plugin-tailwindcss": "^0.6.11", "typescript": "^5.7.3", "vue-tsc": "^2.2.0" }, - "packageManager": "pnpm@9.15.3" + "packageManager": "pnpm@10.2.0" } diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index 1443ce16..d5728669 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -10,22 +10,25 @@ importers: dependencies: '@eschricht/nuxt-color-mode': specifier: ^1.1.5 - version: 1.1.5(magicast@0.3.5)(rollup@4.30.1) + version: 1.1.5(magicast@0.3.5)(rollup@4.34.1) + '@libsql/client': + specifier: ^0.14.0 + version: 0.14.0 '@nuxtjs/i18n': - specifier: ^9.1.1 - version: 9.1.1(@vue/compiler-dom@3.5.13)(eslint@9.17.0(jiti@2.4.2))(magicast@0.3.5)(rollup@4.30.1)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) + specifier: ^9.1.5 + version: 9.1.5(@vue/compiler-dom@3.5.13)(eslint@9.19.0(jiti@2.4.2))(magicast@0.3.5)(rollup@4.34.1)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) '@nuxtjs/tailwindcss': - specifier: ^6.12.2 - version: 6.12.2(magicast@0.3.5)(rollup@4.30.1) + specifier: ^6.13.1 + version: 6.13.1(magicast@0.3.5)(rollup@4.34.1) '@pinia/nuxt': specifier: ^0.9.0 - version: 0.9.0(magicast@0.3.5)(pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(rollup@4.30.1) + version: 0.9.0(magicast@0.3.5)(pinia@2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(rollup@4.34.1) '@tailwindcss/forms': specifier: ^0.5.10 version: 0.5.10(tailwindcss@3.4.17) apexcharts: - specifier: ^4.3.0 - version: 4.3.0 + specifier: ^4.4.0 + version: 4.4.0 argon2: specifier: ^0.41.1 version: 0.41.1 @@ -41,6 +44,9 @@ importers: debug: specifier: ^4.4.0 version: 4.4.0(supports-color@9.4.0) + drizzle-orm: + specifier: ^0.39.1 + version: 0.39.1(@libsql/client@0.14.0) ip-bigint: specifier: ^8.2.0 version: 8.2.0 @@ -57,20 +63,20 @@ importers: specifier: ^7.0.1 version: 7.0.1 nuxt: - specifier: ^3.15.1 - version: 3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(db0@0.2.1)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0) + specifier: ^3.15.4 + version: 3.15.4(@libsql/client@0.14.0)(@parcel/watcher@2.5.1)(@types/node@22.13.1)(db0@0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)))(drizzle-orm@0.39.1(@libsql/client@0.14.0))(eslint@9.19.0(jiti@2.4.2))(ioredis@5.4.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0) pinia: - specifier: ^2.3.0 - version: 2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) + specifier: ^2.3.1 + version: 2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) qrcode: specifier: ^1.5.4 version: 1.5.4 radix-vue: - specifier: ^1.9.12 - version: 1.9.12(vue@3.5.13(typescript@5.7.3)) + specifier: ^1.9.13 + version: 1.9.13(vue@3.5.13(typescript@5.7.3)) semver: - specifier: ^7.6.3 - version: 7.6.3 + specifier: ^7.7.1 + version: 7.7.1 tailwindcss: specifier: ^3.4.17 version: 3.4.17 @@ -82,14 +88,14 @@ importers: version: 3.5.13(typescript@5.7.3) vue3-apexcharts: specifier: ^1.8.0 - version: 1.8.0(apexcharts@4.3.0)(vue@3.5.13(typescript@5.7.3)) + version: 1.8.0(apexcharts@4.4.0)(vue@3.5.13(typescript@5.7.3)) zod: specifier: ^3.24.1 version: 3.24.1 devDependencies: '@nuxt/eslint-config': - specifier: ^0.7.5 - version: 0.7.5(@vue/compiler-sfc@3.5.13)(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) + specifier: ^1.0.0 + version: 1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -99,18 +105,21 @@ importers: '@types/semver': specifier: ^7.5.8 version: 7.5.8 + drizzle-kit: + specifier: ^0.30.4 + version: 0.30.4 eslint: - specifier: ^9.17.0 - version: 9.17.0(jiti@2.4.2) + specifier: ^9.19.0 + version: 9.19.0(jiti@2.4.2) eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@9.17.0(jiti@2.4.2)) + specifier: ^10.0.1 + version: 10.0.1(eslint@9.19.0(jiti@2.4.2)) prettier: specifier: ^3.4.2 version: 3.4.2 prettier-plugin-tailwindcss: - specifier: ^0.6.9 - version: 0.6.9(prettier@3.4.2) + specifier: ^0.6.11 + version: 0.6.11(prettier@3.4.2) typescript: specifier: ^5.7.3 version: 5.7.3 @@ -138,24 +147,24 @@ packages: resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.3': - resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} + '@babel/compat-data@7.26.5': + resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} engines: {node: '>=6.9.0'} - '@babel/core@7.26.0': - resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + '@babel/core@7.26.7': + resolution: {integrity: sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.26.3': - resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==} + '@babel/generator@7.26.5': + resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.25.9': resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.25.9': - resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} engines: {node: '>=6.9.0'} '@babel/helper-create-class-features-plugin@7.25.9': @@ -182,12 +191,12 @@ packages: resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.25.9': - resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} engines: {node: '>=6.9.0'} - '@babel/helper-replace-supers@7.25.9': - resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==} + '@babel/helper-replace-supers@7.26.5': + resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -208,12 +217,12 @@ packages: resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.26.0': - resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + '@babel/helpers@7.26.7': + resolution: {integrity: sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==} engines: {node: '>=6.9.0'} - '@babel/parser@7.26.3': - resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} + '@babel/parser@7.26.7': + resolution: {integrity: sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==} engines: {node: '>=6.0.0'} hasBin: true @@ -252,26 +261,26 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.26.3': - resolution: {integrity: sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==} + '@babel/plugin-transform-typescript@7.26.7': + resolution: {integrity: sha512-5cJurntg+AT+cgelGP9Bt788DKiAw9gIMSMU2NJrLAilnj0m8WZWUNZPSLOmadYsujHutpgElO+50foX+ib/Wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/standalone@7.26.4': - resolution: {integrity: sha512-SF+g7S2mhTT1b7CHyfNjDkPU1corxg4LPYsyP0x5KuCl+EbtBQHRLqr9N3q7e7+x7NQ5LYxQf8mJ2PmzebLr0A==} + '@babel/standalone@7.26.7': + resolution: {integrity: sha512-Fvdo9Dd20GDUAREzYMIR2EFMKAJ+ccxstgQdb39XV/yvygHL4UPcqgTkiChPyltAe/b+zgq+vUPXeukEZ6aUeA==} engines: {node: '>=6.9.0'} '@babel/template@7.25.9': resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.26.4': - resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==} + '@babel/traverse@7.26.7': + resolution: {integrity: sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==} engines: {node: '>=6.9.0'} - '@babel/types@7.26.3': - resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} + '@babel/types@7.26.7': + resolution: {integrity: sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==} engines: {node: '>=6.9.0'} '@clack/core@0.4.1': @@ -296,12 +305,23 @@ packages: peerDependencies: postcss-selector-parser: ^7.0.0 + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@es-joy/jsdoccomment@0.49.0': resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} engines: {node: '>=16'} - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild/aix-ppc64@0.19.12': + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] @@ -312,8 +332,14 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.19.12': + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -324,8 +350,14 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.19.12': + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -336,8 +368,14 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.19.12': + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -348,8 +386,14 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.19.12': + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -360,8 +404,14 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.19.12': + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -372,8 +422,14 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.19.12': + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -384,8 +440,14 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.19.12': + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -396,8 +458,14 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.19.12': + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -408,8 +476,14 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.19.12': + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -420,8 +494,14 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.19.12': + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -432,8 +512,14 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.19.12': + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -444,8 +530,14 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.19.12': + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -456,8 +548,14 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.19.12': + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -468,8 +566,14 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.19.12': + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -480,8 +584,14 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.19.12': + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -492,8 +602,14 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.19.12': + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -510,8 +626,14 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.19.12': + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -528,8 +650,14 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.19.12': + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -540,8 +668,14 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.19.12': + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -552,8 +686,14 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.19.12': + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -564,8 +704,14 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.19.12': + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -576,8 +722,14 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.19.12': + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -601,8 +753,8 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.2.4': - resolution: {integrity: sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==} + '@eslint/compat@1.2.6': + resolution: {integrity: sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^9.10.0 @@ -610,28 +762,28 @@ packages: eslint: optional: true - '@eslint/config-array@0.19.1': - resolution: {integrity: sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==} + '@eslint/config-array@0.19.2': + resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.9.1': - resolution: {integrity: sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==} + '@eslint/core@0.10.0': + resolution: {integrity: sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.2.0': resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.17.0': - resolution: {integrity: sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==} + '@eslint/js@9.19.0': + resolution: {integrity: sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.5': - resolution: {integrity: sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==} + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.4': - resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} + '@eslint/plugin-kit@0.2.5': + resolution: {integrity: sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@floating-ui/core@1.6.9': @@ -666,8 +818,8 @@ packages: resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} - '@internationalized/date@3.6.0': - resolution: {integrity: sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ==} + '@internationalized/date@3.7.0': + resolution: {integrity: sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==} '@internationalized/number@3.6.0': resolution: {integrity: sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw==} @@ -712,8 +864,8 @@ packages: resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==} engines: {node: '>= 16'} - '@intlify/shared@11.0.1': - resolution: {integrity: sha512-lH164+aDDptHZ3dBDbIhRa1dOPQUp+83iugpc+1upTOWCnwyC1PVis6rSWNMMJ8VQxvtHQB9JMib48K55y0PvQ==} + '@intlify/shared@11.1.0': + resolution: {integrity: sha512-DvpNSxiMrFqYMaGSRDDnQgO/L0MqNH4KWw9CUx8LRHHIdWp08En9DpmSRNpauUOxKpHAhyJJxx92BHZk9J84EQ==} engines: {node: '>= 16'} '@intlify/unplugin-vue-i18n@6.0.3': @@ -793,8 +945,59 @@ packages: '@kwsites/promise-deferred@1.1.1': resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} - '@mapbox/node-pre-gyp@2.0.0-rc.0': - resolution: {integrity: sha512-nhSMNprz3WmeRvd8iUs5JqkKr0Ncx46JtPxM3AhXes84XpSJfmIwKeWXRpsr53S7kqPkQfPhzrMFUxSNb23qSA==} + '@libsql/client@0.14.0': + resolution: {integrity: sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==} + + '@libsql/core@0.14.0': + resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==} + + '@libsql/darwin-arm64@0.4.7': + resolution: {integrity: sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-x64@0.4.7': + resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==} + cpu: [x64] + os: [darwin] + + '@libsql/hrana-client@0.7.0': + resolution: {integrity: sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==} + + '@libsql/isomorphic-fetch@0.3.1': + resolution: {integrity: sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==} + engines: {node: '>=18.0.0'} + + '@libsql/isomorphic-ws@0.1.5': + resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} + + '@libsql/linux-arm64-gnu@0.4.7': + resolution: {integrity: sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.4.7': + resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-x64-gnu@0.4.7': + resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-musl@0.4.7': + resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==} + cpu: [x64] + os: [linux] + + '@libsql/win32-x64-msvc@0.4.7': + resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==} + cpu: [x64] + os: [win32] + + '@mapbox/node-pre-gyp@2.0.0': + resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==} engines: {node: '>=18'} hasBin: true @@ -803,6 +1006,9 @@ packages: peerDependencies: rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 + '@neon-rs/load@0.0.4': + resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} + '@netlify/functions@2.8.2': resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==} engines: {node: '>=14.0.0'} @@ -827,6 +1033,11 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@nuxt/cli@3.21.1': + resolution: {integrity: sha512-GFFHSEtNtf1s4anMKWFfKSbKiNvEwOKxfP3uls7anZ8GCVYrKthMMxeou4fZBcRhTAFbiLC7DytsKnjfmY2t9w==} + engines: {node: ^16.10.0 || >=18.0.0} + hasBin: true + '@nuxt/devalue@2.0.2': resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} @@ -845,26 +1056,26 @@ packages: peerDependencies: vite: '*' - '@nuxt/eslint-config@0.7.5': - resolution: {integrity: sha512-nUMMiVNZ7qk7FP5Uev/zuTZoTwBnlfr0qSt355aw21SoUkXw0YFRFsImdzkjnEN7kQjgZj0PcCJs/ejv8mRROg==} + '@nuxt/eslint-config@1.0.0': + resolution: {integrity: sha512-Bxvx6y68WqLkubKv9zDP7mdl82ljO7Zmqi13RWveGTvFt61BwP4bQIF10s8r1rfE+2svDN8d0L9eIDoDHtHZQg==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^9.0.0 eslint-plugin-format: '*' peerDependenciesMeta: eslint-plugin-format: optional: true - '@nuxt/eslint-plugin@0.7.5': - resolution: {integrity: sha512-EBb9KiUbnGK6yJnOmGAaURS8NTfNaMXHiAyRtEmLTtj/IwNqFUtgoDLFqBDBCGIjd8my2WA1m9HjQK/+la9Z0Q==} + '@nuxt/eslint-plugin@1.0.0': + resolution: {integrity: sha512-mYkq6V3xCVwnJxiwqTYfEe3HYV/Nxayes9cqY5maijSMJSCSI8l73FYWal2HFvsSoqilYhN4EfgzCHPhyWHqQQ==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^9.0.0 - '@nuxt/kit@3.15.1': - resolution: {integrity: sha512-7cVWjzfz3L6CsZrg6ppDZa7zGrZxCSfZjEQDIvVFn4mFKtJlK9k2izf5EewL6luzWwIQojkZAC3iq/1wtgI0Xw==} - engines: {node: '>=18.20.5'} + '@nuxt/kit@3.15.4': + resolution: {integrity: sha512-dr7I7eZOoRLl4uxdxeL2dQsH0OrbEiVPIyBHnBpA4co24CBnoJoF+JINuP9l3PAM3IhUzc5JIVq3/YY3lEc3Hw==} + engines: {node: '>=18.12.0'} - '@nuxt/schema@3.15.1': - resolution: {integrity: sha512-n5kOHt8uUyUM9z4Wu/8tIZkBYh3KTCGvyruG6oD9bfeT4OaS21+X3M7XsTXFMe+eYBZA70IFFlWn1JJZIPsKeA==} + '@nuxt/schema@3.15.4': + resolution: {integrity: sha512-pAYZb/3ocSC/db1EFd5y+otmgHqUkvfxfhd9EknDB5DygnJuOIQNuGJ7LMJM6S2c0DYgBIHOdEelLxKHOjwbgQ==} engines: {node: ^14.18.0 || >=16.10.0} '@nuxt/telemetry@2.6.4': @@ -872,105 +1083,105 @@ packages: engines: {node: '>=18.20.5'} hasBin: true - '@nuxt/vite-builder@3.15.1': - resolution: {integrity: sha512-b9uvLuRSgZy+pvU0rwHOpYo9XmAPibNGFEn0MeG6rUWVee9didV0Q5voAr+/1kq9bIbf6V0QFh9TE+4pCxZuMQ==} - engines: {node: ^18.20.5 || ^20.9.0 || >=22.0.0} + '@nuxt/vite-builder@3.15.4': + resolution: {integrity: sha512-yBK6tWT973+ExKC3ciTWymZpjJ+enToOtYz574kXCyGO0PbSnuXdoJKTvrwXw1lK97PajCKxExlmwI/3oLOmMQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0.0} peerDependencies: vue: ^3.3.4 - '@nuxtjs/i18n@9.1.1': - resolution: {integrity: sha512-S8l5ri1GFo5OUsl9qSgicE9Sm0BZjVHU7p6ml1qhQUTewngnTPTlcytWX5etwJeAjHEu2w9VAV4qXTn9Q5EgmQ==} + '@nuxtjs/i18n@9.1.5': + resolution: {integrity: sha512-dFbo3etm5xqG3vF4sLeVrR+wXVcxBszDCds5xtJBSESS7riJBtW83BujSMUnalbRxvGOLhJj+b6Qb8vj7Im/9Q==} engines: {node: ^14.16.0 || >=16.11.0} - '@nuxtjs/tailwindcss@6.12.2': - resolution: {integrity: sha512-qPJiFH67CkTj/2kBGBzqXihOD1rQXMsbVS4vdQvfBxOBLPfGhU1yw7AATdhPl2BBjO2krjJLuZj39t7dnDYOwg==} + '@nuxtjs/tailwindcss@6.13.1': + resolution: {integrity: sha512-atL2SaPsxLfMTlXUQvr1UpDYdz6ocNOhH35H+t7M++g4r79QiQScJ7XuyyMR9AyBN19lkPA3nw7NXxazXmYxlA==} - '@parcel/watcher-android-arm64@2.5.0': - resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.5.0': - resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.5.0': - resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.5.0': - resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.5.0': - resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - '@parcel/watcher-linux-arm-musl@2.5.0': - resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - '@parcel/watcher-linux-arm64-glibc@2.5.0': - resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - '@parcel/watcher-linux-arm64-musl@2.5.0': - resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - '@parcel/watcher-linux-x64-glibc@2.5.0': - resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - '@parcel/watcher-linux-x64-musl@2.5.0': - resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - '@parcel/watcher-wasm@2.5.0': - resolution: {integrity: sha512-Z4ouuR8Pfggk1EYYbTaIoxc+Yv4o7cGQnH0Xy8+pQ+HbiW+ZnwhcD2LPf/prfq1nIWpAxjOkQ8uSMFWMtBLiVQ==} + '@parcel/watcher-wasm@2.5.1': + resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} engines: {node: '>= 10.0.0'} bundledDependencies: - napi-wasm - '@parcel/watcher-win32-arm64@2.5.0': - resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] - '@parcel/watcher-win32-ia32@2.5.0': - resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] - '@parcel/watcher-win32-x64@2.5.0': - resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] - '@parcel/watcher@2.5.0': - resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} engines: {node: '>= 10.0.0'} '@phc/format@1.0.0': @@ -996,12 +1207,12 @@ packages: '@redocly/ajv@8.11.2': resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} - '@redocly/config@0.17.1': - resolution: {integrity: sha512-CEmvaJuG7pm2ylQg53emPmtgm4nW2nxBgwXzbVEHpGas/lGnMyN8Zlkgiz6rPw0unASg6VW3wlz27SOL5XFHYQ==} + '@redocly/config@0.20.3': + resolution: {integrity: sha512-Nyyv1Bj7GgYwj/l46O0nkH1GTKWbO3Ixe7KFcn021aZipkZd+z8Vlu1BwkhqtVgivcKaClaExtWU/lDHkjBzag==} - '@redocly/openapi-core@1.27.1': - resolution: {integrity: sha512-zQ47/A+Drk2Y75/af69MD3Oad4H9LxkUDzcm7XBkyLNDKIWQrDKDnS5476oDq77+zciymNxgMVtxxVXlnGS8kw==} - engines: {node: '>=14.19.0', npm: '>=7.0.0'} + '@redocly/openapi-core@1.28.1': + resolution: {integrity: sha512-f9sx2WEhhU6YxajyqE+vQC7/DWiQxk8TiLA6Axba7wnvQUCknvmZ6xOeOdlV1lyfaADhbJ/5hBQHNwfcc0pMhg==} + engines: {node: '>=18.17.0', npm: '>=10.8.2'} '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} @@ -1084,98 +1295,98 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.30.1': - resolution: {integrity: sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==} + '@rollup/rollup-android-arm-eabi@4.34.1': + resolution: {integrity: sha512-kwctwVlswSEsr4ljpmxKrRKp1eG1v2NAhlzFzDf1x1OdYaMjBYjDCbHkzWm57ZXzTwqn8stMXgROrnMw8dJK3w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.30.1': - resolution: {integrity: sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==} + '@rollup/rollup-android-arm64@4.34.1': + resolution: {integrity: sha512-4H5ZtZitBPlbPsTv6HBB8zh1g5d0T8TzCmpndQdqq20Ugle/nroOyDMf9p7f88Gsu8vBLU78/cuh8FYHZqdXxw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.30.1': - resolution: {integrity: sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==} + '@rollup/rollup-darwin-arm64@4.34.1': + resolution: {integrity: sha512-f2AJ7Qwx9z25hikXvg+asco8Sfuc5NCLg8rmqQBIOUoWys5sb/ZX9RkMZDPdnnDevXAMJA5AWLnRBmgdXGEUiA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.30.1': - resolution: {integrity: sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==} + '@rollup/rollup-darwin-x64@4.34.1': + resolution: {integrity: sha512-+/2JBrRfISCsWE4aEFXxd+7k9nWGXA8+wh7ZUHn/u8UDXOU9LN+QYKKhd57sIn6WRcorOnlqPMYFIwie/OHXWw==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.30.1': - resolution: {integrity: sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==} + '@rollup/rollup-freebsd-arm64@4.34.1': + resolution: {integrity: sha512-SUeB0pYjIXwT2vfAMQ7E4ERPq9VGRrPR7Z+S4AMssah5EHIilYqjWQoTn5dkDtuIJUSTs8H+C9dwoEcg3b0sCA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.30.1': - resolution: {integrity: sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==} + '@rollup/rollup-freebsd-x64@4.34.1': + resolution: {integrity: sha512-L3T66wAZiB/ooiPbxz0s6JEX6Sr2+HfgPSK+LMuZkaGZFAFCQAHiP3dbyqovYdNaiUXcl9TlgnIbcsIicAnOZg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.30.1': - resolution: {integrity: sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==} + '@rollup/rollup-linux-arm-gnueabihf@4.34.1': + resolution: {integrity: sha512-UBXdQ4+ATARuFgsFrQ+tAsKvBi/Hly99aSVdeCUiHV9dRTTpMU7OrM3WXGys1l40wKVNiOl0QYY6cZQJ2xhKlQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.30.1': - resolution: {integrity: sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==} + '@rollup/rollup-linux-arm-musleabihf@4.34.1': + resolution: {integrity: sha512-m/yfZ25HGdcCSwmopEJm00GP7xAUyVcBPjttGLRAqZ60X/bB4Qn6gP7XTwCIU6bITeKmIhhwZ4AMh2XLro+4+w==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.30.1': - resolution: {integrity: sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==} + '@rollup/rollup-linux-arm64-gnu@4.34.1': + resolution: {integrity: sha512-Wy+cUmFuvziNL9qWRRzboNprqSQ/n38orbjRvd6byYWridp5TJ3CD+0+HUsbcWVSNz9bxkDUkyASGP0zS7GAvg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.30.1': - resolution: {integrity: sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==} + '@rollup/rollup-linux-arm64-musl@4.34.1': + resolution: {integrity: sha512-CQ3MAGgiFmQW5XJX5W3wnxOBxKwFlUAgSXFA2SwgVRjrIiVt5LHfcQLeNSHKq5OEZwv+VCBwlD1+YKCjDG8cpg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.30.1': - resolution: {integrity: sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==} + '@rollup/rollup-linux-loongarch64-gnu@4.34.1': + resolution: {integrity: sha512-rSzb1TsY4lSwH811cYC3OC2O2mzNMhM13vcnA7/0T6Mtreqr3/qs6WMDriMRs8yvHDI54qxHgOk8EV5YRAHFbw==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.30.1': - resolution: {integrity: sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.34.1': + resolution: {integrity: sha512-fwr0n6NS0pG3QxxlqVYpfiY64Fd1Dqd8Cecje4ILAV01ROMp4aEdCj5ssHjRY3UwU7RJmeWd5fi89DBqMaTawg==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.30.1': - resolution: {integrity: sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==} + '@rollup/rollup-linux-riscv64-gnu@4.34.1': + resolution: {integrity: sha512-4uJb9qz7+Z/yUp5RPxDGGGUcoh0PnKF33QyWgEZ3X/GocpWb6Mb+skDh59FEt5d8+Skxqs9mng6Swa6B2AmQZg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.30.1': - resolution: {integrity: sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==} + '@rollup/rollup-linux-s390x-gnu@4.34.1': + resolution: {integrity: sha512-QlIo8ndocWBEnfmkYqj8vVtIUpIqJjfqKggjy7IdUncnt8BGixte1wDON7NJEvLg3Kzvqxtbo8tk+U1acYEBlw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.30.1': - resolution: {integrity: sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==} + '@rollup/rollup-linux-x64-gnu@4.34.1': + resolution: {integrity: sha512-hzpleiKtq14GWjz3ahWvJXgU1DQC9DteiwcsY4HgqUJUGxZThlL66MotdUEK9zEo0PK/2ADeZGM9LIondE302A==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.30.1': - resolution: {integrity: sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==} + '@rollup/rollup-linux-x64-musl@4.34.1': + resolution: {integrity: sha512-jqtKrO715hDlvUcEsPn55tZt2TEiBvBtCMkUuU0R6fO/WPT7lO9AONjPbd8II7/asSiNVQHCMn4OLGigSuxVQA==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.30.1': - resolution: {integrity: sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==} + '@rollup/rollup-win32-arm64-msvc@4.34.1': + resolution: {integrity: sha512-RnHy7yFf2Wz8Jj1+h8klB93N0NHNHXFhNwAmiy9zJdpY7DE01VbEVtPdrK1kkILeIbHGRJjvfBDBhnxBr8kD4g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.30.1': - resolution: {integrity: sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==} + '@rollup/rollup-win32-ia32-msvc@4.34.1': + resolution: {integrity: sha512-i7aT5HdiZIcd7quhzvwQ2oAuX7zPYrYfkrd1QFfs28Po/i0q6kas/oRrzGlDhAEyug+1UfUtkWdmoVlLJj5x9Q==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.30.1': - resolution: {integrity: sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==} + '@rollup/rollup-win32-x64-msvc@4.34.1': + resolution: {integrity: sha512-k3MVFD9Oq+laHkw2N2v7ILgoa9017ZMF/inTtHzyTVZjYs9cSH18sdyAf6spBAJIGwJ5UaC7et2ZH1WCdlhkMw==} cpu: [x64] os: [win32] @@ -1183,14 +1394,14 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} - '@stylistic/eslint-plugin@2.12.1': - resolution: {integrity: sha512-fubZKIHSPuo07FgRTn6S4Nl0uXPRPYVNpyZzIDGfp7Fny6JjNus6kReLD7NI380JXi4HtUTSOZ34LBuNPO1XLQ==} + '@stylistic/eslint-plugin@3.0.1': + resolution: {integrity: sha512-rQ3tcT5N2cynofJfbjUsnL4seoewTaOVBLyUEwtNldo7iNMPo3h/GUQk+Cl3iHEWwRxjq2wuH6q0FufQrbVL1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.40.0' - '@svgdotjs/svg.draggable.js@3.0.4': - resolution: {integrity: sha512-vWi/Col5Szo74HJVBgMHz23kLVljt3jvngmh0DzST45iO2ubIZ487uUAHIxSZH2tVRyiaaTL+Phaasgp4gUD2g==} + '@svgdotjs/svg.draggable.js@3.0.5': + resolution: {integrity: sha512-ljL/fB0tAjRfFOJGhXpr7rEx9DJ6D7Pxt3AXvgxjEM17g6wK3Ho9nXhntraOMx8JLZdq4NBMjokeXMvnQzJVYA==} peerDependencies: '@svgdotjs/svg.js': ^3.2.4 @@ -1222,11 +1433,11 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' - '@tanstack/virtual-core@3.11.2': - resolution: {integrity: sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw==} + '@tanstack/virtual-core@3.12.0': + resolution: {integrity: sha512-7mDINtua3v/pOnn6WUmuT9dPXYSO7WidFej7JzoAfqEOcbbpt/iZ1WPqd+eg+FnrL9nUJK8radqj4iAU51Zchg==} - '@tanstack/vue-virtual@3.11.2': - resolution: {integrity: sha512-y0b1p1FTlzxcSt/ZdGWY1AZ52ddwSU69pvFRYAELUSdLLxV8QOPe9dyT/KATO43UCb3DAwiyzi96h2IoYstBOQ==} + '@tanstack/vue-virtual@3.12.0': + resolution: {integrity: sha512-+XaB92VXHggiMTP9b0ZoTEvKl2YhxfWaF2BW9xYYt2N4e+gyvz0Phmjdz7oVSbKCDdI0oKSUp/z+KzJ6JZYjCg==} peerDependencies: vue: ^2.7.0 || ^3.0.0 @@ -1249,11 +1460,11 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/ms@0.7.34': - resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@22.10.5': - resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + '@types/node@22.13.1': + resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1273,67 +1484,70 @@ packages: '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - '@typescript-eslint/eslint-plugin@8.19.1': - resolution: {integrity: sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==} + '@types/ws@8.5.14': + resolution: {integrity: sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==} + + '@typescript-eslint/eslint-plugin@8.23.0': + resolution: {integrity: sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/parser@8.19.1': - resolution: {integrity: sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==} + '@typescript-eslint/parser@8.23.0': + resolution: {integrity: sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/scope-manager@8.19.1': - resolution: {integrity: sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==} + '@typescript-eslint/scope-manager@8.23.0': + resolution: {integrity: sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.19.1': - resolution: {integrity: sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==} + '@typescript-eslint/type-utils@8.23.0': + resolution: {integrity: sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/types@8.19.1': - resolution: {integrity: sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==} + '@typescript-eslint/types@8.23.0': + resolution: {integrity: sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.19.1': - resolution: {integrity: sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==} + '@typescript-eslint/typescript-estree@8.23.0': + resolution: {integrity: sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.19.1': - resolution: {integrity: sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==} + '@typescript-eslint/utils@8.23.0': + resolution: {integrity: sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/visitor-keys@8.19.1': - resolution: {integrity: sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==} + '@typescript-eslint/visitor-keys@8.23.0': + resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@unhead/dom@1.11.15': - resolution: {integrity: sha512-2OZ7zvZQLqlqkhvsKsNOhxxoO3vgjygzzrmtooQR9QNKY+3HjwJ3+QfjGswXI976YV7VJem57ydQSMk1ijB7yg==} + '@unhead/dom@1.11.18': + resolution: {integrity: sha512-zQuJUw/et9zYEV0SZWTDX23IgurwMaXycAuxt4L6OgNL0T4TWP3a0J/Vm3Q02hmdNo/cPKeVBrwBdnFUXjGU4w==} - '@unhead/schema@1.11.15': - resolution: {integrity: sha512-UkLz1dqw4yoh4jELEyLsgSG7yrXc+gv68GkQeTv8LysEPa8sXtFqhfuqTBLhY3sHqSnP8RkDknhtFhG2S3fuKQ==} + '@unhead/schema@1.11.18': + resolution: {integrity: sha512-a3TA/OJCRdfbFhcA3Hq24k1ZU1o9szicESrw8DZcGyQFacHnh84mVgnyqSkMnwgCmfN4kvjSiTBlLEHS6+wATw==} - '@unhead/shared@1.11.15': - resolution: {integrity: sha512-VT42ssmwpFGfixfXqAZ+Rn7KyNG0yFqWGsvLOXIgahiTzh3N1k2st1tPvuYFZU22dtWBNxG7cvy8yxUd1vunMQ==} + '@unhead/shared@1.11.18': + resolution: {integrity: sha512-OsupRQRxJqqnuKiL1Guqipjbl7MndD5DofvmGa3PFGu2qNPmOmH2mxGFjRBBgq2XxY1KalIHl/2I9HV6gbK8cw==} - '@unhead/ssr@1.11.15': - resolution: {integrity: sha512-btoJ7huldVdxOJOr9yx8DpDiUELzdlX3LB0k5cBub+CI4nZoPC/8ovuaYzKBriAIkEtQp9g9ytHRUJYDvim/1g==} + '@unhead/ssr@1.11.18': + resolution: {integrity: sha512-uaHPz0RRAb18yKeCmHyHk5QKWRk/uHpOrqSbhRXTOhbrd3Ur3gGTVaAoyUoRYKGPU5B5/pyHh3TfLw0LkfrH1A==} - '@unhead/vue@1.11.15': - resolution: {integrity: sha512-2NT8Kph5AvB/qO+C8UKAc7cudbFRZTJk0eRpn8o1nG3yk2+mWvN0vsTTjnKvXixNF193I/R+zqo/NkcjgaWG9A==} + '@unhead/vue@1.11.18': + resolution: {integrity: sha512-Jfi7t/XNBnlcauP9UTH3VHBcS69G70ikFd2e5zdgULLDRWpOlLs1sSTH1V2juNptc93DOk9RQfC5jLWbLcivFw==} peerDependencies: vue: '>=2.7 || >=3' @@ -1365,8 +1579,8 @@ packages: '@volar/typescript@2.4.11': resolution: {integrity: sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==} - '@vue-macros/common@1.15.1': - resolution: {integrity: sha512-O0ZXaladWXwHplQnSjxLbB/G1KpdWCUNJPNYVHIxHonGex1BGpoB4fBZZLgddHgAiy18VZG/Iu5L0kwG+SV7JQ==} + '@vue-macros/common@1.16.1': + resolution: {integrity: sha512-Pn/AWMTjoMYuquepLZP813BIcq8DTZiNCoaceuNlvaYuOTd8DqBZWc5u0uOMQZMInwME1mdSmmBAcTluiV9Jtg==} engines: {node: '>=16.14.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 @@ -1416,8 +1630,8 @@ packages: '@vue/devtools-kit@7.6.8': resolution: {integrity: sha512-JhJ8M3sPU+v0P2iZBF2DkdmR9L0dnT5RXJabJqX6o8KtFs3tebdvfoXV2Dm3BFuqeECuMJIfF1aCzSt+WQ4wrw==} - '@vue/devtools-shared@7.7.0': - resolution: {integrity: sha512-jtlQY26R5thQxW9YQTpXbI0HoK0Wf9Rd4ekidOkRvSy7ChfK0kIU6vvcBtjj87/EcpeOSK49fZAicaFNJcoTcQ==} + '@vue/devtools-shared@7.7.1': + resolution: {integrity: sha512-BtgF7kHq4BHG23Lezc/3W2UhK2ga7a8ohAIAGJMBr4BkxUFzhqntQtCiuL1ijo2ztWnmusymkirgqUrXoQKumA==} '@vue/language-core@2.2.0': resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} @@ -1456,9 +1670,9 @@ packages: '@yr/monotone-cubic-spline@1.0.3': resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==} - abbrev@2.0.0: - resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abbrev@3.0.0: + resolution: {integrity: sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==} + engines: {node: ^18.17.0 || >=20.5.0} abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} @@ -1524,8 +1738,8 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - apexcharts@4.3.0: - resolution: {integrity: sha512-PfvZQpv91T68hzry9l5zP3Gip7sQvF0nFK91uCBrswIKX7rbIdbVNS4fOks9m9yP3Ppgs6LHgU2M/mjoG4NM0A==} + apexcharts@4.4.0: + resolution: {integrity: sha512-JGsHeQEKDlQh1rob8aBai9/HKvXIpbZ83TnobKZAcdOELf+oQZaxZyAnbbldr6PPBdCgG2zzzLaP1dtEsJxzWw==} archiver-utils@5.0.2: resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} @@ -1553,8 +1767,8 @@ packages: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} - ast-kit@1.3.2: - resolution: {integrity: sha512-gdvX700WVC6sHCJQ7bJGfDvtuKAh6Sa6weIZROxfzUZKP7BjvB8y0SMlM/o4omSQ3L60PQSJROBJsb0vEViVnA==} + ast-kit@1.4.0: + resolution: {integrity: sha512-BlGeOw73FDsX7z0eZE/wuuafxYoek2yzNJ6l6A1nsb4+z/p87TOPbHaWuN53kFKNuUXiCQa2M+xLF71IqQmRSw==} engines: {node: '>=16.14.0'} ast-walker-scope@0.6.2: @@ -1587,8 +1801,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - bare-events@2.5.3: - resolution: {integrity: sha512-pCO3aoRJ0MBiRMu8B7vUga0qL3L7gO1+SW7ku6qlSsMLwuhaawnuvZDyzJY/kyC63Un0XAB0OPUcfF1eTO/V+Q==} + bare-events@2.5.4: + resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1682,8 +1896,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001692: - resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} + caniuse-lite@1.0.30001697: + resolution: {integrity: sha512-GwNPlWJin8E+d7Gxq96jxM6w0w+VFeyyXRsjU58emtkYqnbwHqXm5uT2uCmO0RQE9htWknOP4xtBlLmM/gWxvQ==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1802,8 +2016,8 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - consola@3.3.3: - resolution: {integrity: sha512-Qil5KwghMzlqd51UXM0b6fyaGHtOC22scxrwrz4A2882LyUMwQjnvaedN1HAeXzphspQ6CpHkzMAWxBTUruDLg==} + consola@3.4.0: + resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} engines: {node: ^14.18.0 || >=16.10.0} content-disposition@0.5.4: @@ -1851,16 +2065,16 @@ packages: resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} engines: {node: '>=18.0'} - cronstrue@2.52.0: - resolution: {integrity: sha512-NKgHbWkSZXJUcaBHSsyzC8eegD6bBd4O0oCI6XMIJ+y4Bq3v4w7sY3wfWoKPuVlq9pQHRB6od0lmKpIqi8TlKA==} + cronstrue@2.54.0: + resolution: {integrity: sha512-vyp5NklDxA5MjPfQgkn0bA+0vRQe7Q9keX7RPdV6rMgd7LtDvbuKgnT+3T5ZAX16anSP5HmahcRp8mziXsLfaw==} hasBin: true cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crossws@0.3.1: - resolution: {integrity: sha512-HsZgeVYaG+b5zA+9PbIPGq4+J/CJynJuearykPsXx4V/eMhyQ5EDVg3Ak2FBZtVXCiOLu/U7IiwDHTr9MA+IKw==} + crossws@0.3.3: + resolution: {integrity: sha512-/71DJT3xJlqSnBr83uGJesmVHSzZEvgxHt/fIKxBAAngqMHmnBWQNxCphVxxJ2XL3xleu5+hJD6IQ3TglBedcw==} css-declaration-sorter@7.2.0: resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} @@ -1913,14 +2127,19 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - db0@0.2.1: - resolution: {integrity: sha512-BWSFmLaCkfyqbSEZBQINMVNjCVfrogi7GQ2RSy1tmtfK9OXlsup6lUMwLsqSD7FbAjD04eWFdXowSHHUp6SE/Q==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + db0@0.2.3: + resolution: {integrity: sha512-PunuHESDNefmwVy1LDpY663uWwKt2ogLGoB6NOz2sflGREWqDreMwDgF8gfkXxgNXW+dqviyiJGm924H1BaGiw==} peerDependencies: '@electric-sql/pglite': '*' '@libsql/client': '*' better-sqlite3: '*' drizzle-orm: '*' mysql2: '*' + sqlite3: '*' peerDependenciesMeta: '@electric-sql/pglite': optional: true @@ -1932,6 +2151,8 @@ packages: optional: true mysql2: optional: true + sqlite3: + optional: true de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} @@ -2021,6 +2242,10 @@ packages: engines: {node: '>=0.10'} hasBin: true + detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -2066,6 +2291,102 @@ packages: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} + drizzle-kit@0.30.4: + resolution: {integrity: sha512-B2oJN5UkvwwNHscPWXDG5KqAixu7AUzZ3qbe++KU9SsQ+cZWR4DXEPYcvWplyFAno0dhRJECNEhNxiDmFaPGyQ==} + hasBin: true + + drizzle-orm@0.39.1: + resolution: {integrity: sha512-2bDHlzTY31IDmrYn8i+ZZrxK8IyBD4mPZ7JmZdVDQj2tpBZXs/gxB/1kK5pSvkjxPUMNOVsTnoGkSltgjuJwcA==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=4' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.10.0' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/react': '>=18' + '@types/sql.js': '*' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=14.0.0' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + react: '>=18' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/react': + optional: true + '@types/sql.js': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + react: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2079,8 +2400,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.79: - resolution: {integrity: sha512-nYOxJNxQ9Om4EC88BE4pPoNI8xwSFf8pU/BAeOl4Hh/b/i6V4biTAzwV7pXi3ARKeoYO5JZKMIXTryXSVer5RA==} + electron-to-chromium@1.5.91: + resolution: {integrity: sha512-sNSHHyq048PFmZY4S90ax61q+gLCs0X0YmcOII9wG9S2XwbVr+h4VW2wWhnbp/Eys3cCwTxVF292W3qPaxIapQ==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2124,12 +2445,22 @@ packages: es-module-lexer@1.6.0: resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + peerDependencies: + esbuild: '>=0.12 <1' + + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true @@ -2162,17 +2493,19 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-flat-gitignore@0.2.0: - resolution: {integrity: sha512-s4lsQLYX+76FCt3PZPwdLwWlqssa5SLufl2gopFmCo3PETOLY3OW5IrD3/l2R0FfYEJvd9BRJ19yJ+yfc5oW3g==} + eslint-config-flat-gitignore@2.0.0: + resolution: {integrity: sha512-9iH+DZO94uxsw5iFjzqa9GfahA5oK3nA1GoJK/6u8evAtooYJMwuSWiLcGDfrdLoqdQ5/kqFJKKuMY/+SAasvg==} + peerDependencies: + eslint: ^9.5.0 - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + eslint-config-prettier@10.0.1: + resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==} hasBin: true peerDependencies: eslint: '>=7.0.0' - eslint-flat-config-utils@1.0.0: - resolution: {integrity: sha512-tmzcXeCsa24/u3glyw1Mo7KfC/r9a5Vsu1nPCkX7uefD7C5Z4x922Q2KP/drhTLbOI5lcFHYpfXjKhqqnUWObw==} + eslint-flat-config-utils@2.0.1: + resolution: {integrity: sha512-brf0eAgQ6JlKj3bKfOTuuI7VcCZvi8ZCD1MMTVoEvS/d38j8cByZViLFALH/36+eqB17ukmfmKq3bWzGvizejA==} eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} @@ -2188,8 +2521,8 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 - eslint-plugin-jsdoc@50.6.1: - resolution: {integrity: sha512-UWyaYi6iURdSfdVVqvfOs2vdCVz0J40O/z/HTsv2sFjdjmdlUI/qlKLOTmwbPQ2tAfQnE5F9vqx+B+poF71DBQ==} + eslint-plugin-jsdoc@50.6.3: + resolution: {integrity: sha512-NxbJyt1M5zffPcYZ8Nb53/8nnbIScmiLAMdoe0/FAszwb7lcSiX3iYBTsuF7RV84dZZJC8r3NghomrUXsmWvxQ==} engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -2212,8 +2545,8 @@ packages: peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-processor-vue-blocks@0.1.2: - resolution: {integrity: sha512-PfpJ4uKHnqeL/fXUnzYkOax3aIenlwewXRX8jFinA1a2yCFnLgMuiH3xvCgvHHUlV2xJWQHbCTdiJWGwb3NqpQ==} + eslint-processor-vue-blocks@1.0.0: + resolution: {integrity: sha512-q+Wn9bCml65NwYtuINVCE5dUqZa/uVoY4jfc8qEDwWbcGqdRyfJJmAONNZsreA4Q9EJqjYGjk8Hk1QuwAktgkw==} peerDependencies: '@vue/compiler-sfc': ^3.3.0 eslint: ^8.50.0 || ^9.0.0 @@ -2234,8 +2567,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.17.0: - resolution: {integrity: sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==} + eslint@9.19.0: + resolution: {integrity: sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -2321,17 +2654,21 @@ packages: fast-npm-meta@0.2.2: resolution: {integrity: sha512-E+fdxeaOQGo/CMWc9f4uHFfgUPJRAu7N3uB8GBvB3SDPAIWJK4GKyYhkAGFq+GYrcbKNfQIz5VVQyJnDuPPCrg==} - fastq@1.18.0: - resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + fastq@1.19.0: + resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} - fdir@6.4.2: - resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2343,10 +2680,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-up-simple@1.0.0: - resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} - engines: {node: '>=18'} - find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -2366,6 +2699,10 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -2373,8 +2710,8 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} engines: {node: '>=14.14'} fs-extra@9.1.0: @@ -2400,6 +2737,10 @@ packages: resolution: {integrity: sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==} engines: {node: '>=14.16'} + fuse.js@7.1.0: + resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + engines: {node: '>=10'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -2427,11 +2768,11 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} - get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} - giget@1.2.3: - resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==} + giget@1.2.4: + resolution: {integrity: sha512-Wv+daGyispVoA31TrWAVR+aAdP7roubTPEM/8JzRnqXhLbdJH0T9eQyXVFF8fjk3WKTsctII6QcyxILYgNp2DA==} hasBin: true git-config-path@2.0.0: @@ -2498,8 +2839,8 @@ packages: resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - h3@1.13.0: - resolution: {integrity: sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg==} + h3@1.14.0: + resolution: {integrity: sha512-ao22eiONdgelqcnknw0iD645qW0s9NnrJHr5OBz4WOMdBdycfSas1EQf1wXRsm+PcB2Yoj43pjBPwqIpJQTeWg==} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -2555,8 +2896,8 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - httpxy@0.1.5: - resolution: {integrity: sha512-hqLDO+rfststuyEUTWObQK6zHEEmZ/kaIP2/zclGGZn6X8h/ESTWg+WKecQ/e5k4nPswjzZD+q2VqZIbr15CoQ==} + httpxy@0.1.7: + resolution: {integrity: sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==} human-signals@4.3.1: resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} @@ -2573,15 +2914,15 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.0: - resolution: {integrity: sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A==} + ignore@7.0.3: + resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} engines: {node: '>= 4'} image-meta@0.2.1: resolution: {integrity: sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==} - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} impound@0.2.0: @@ -2758,6 +3099,9 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} @@ -2866,6 +3210,11 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libsql@0.4.7: + resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + cpu: [x64, arm64, wasm32] + os: [darwin, linux, win32] + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -2881,6 +3230,10 @@ packages: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} + local-pkg@1.0.0: + resolution: {integrity: sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==} + engines: {node: '>=14'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2917,8 +3270,8 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - magic-string-ast@0.6.3: - resolution: {integrity: sha512-C9sgUzVZtUtzCBoMdYtwrIRQ4IucGRFGgdhkjL7PXsVfPYmTuWtewqzk7dlipaCMWH/gOYehW9rgMoa4Oebtpw==} + magic-string-ast@0.7.0: + resolution: {integrity: sha512-686fgAHaJY7wLTFEq7nnKqeQrhqmXB19d1HnqT35Ci7BN6hbAYLZUezTQ062uUHM7ggZEQlqJ94Ftls+KDXU8Q==} engines: {node: '>=16.14.0'} magic-string@0.30.17: @@ -3042,8 +3395,8 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.3: - resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} @@ -3071,8 +3424,8 @@ packages: engines: {node: ^18 || >=20} hasBin: true - nanotar@0.1.1: - resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==} + nanotar@0.2.0: + resolution: {integrity: sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==} natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -3098,8 +3451,12 @@ packages: resolution: {integrity: sha512-8VOpLHFrOQlAH+qA0ZzuGRlALRA6/LVh8QJldbrC4DY0hXoMP0l4Acq8TzFC018HztWiRqyCEj2aTWY2UvnJUg==} engines: {node: ^18 || ^20 || >= 21} - node-fetch-native@1.6.4: - resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + node-fetch-native@1.6.6: + resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} @@ -3110,6 +3467,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -3121,8 +3482,8 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - nopt@8.0.0: - resolution: {integrity: sha512-1L/fTJ4UmV/lUxT2Uf006pfZKTvAgCF+chz+0OgBHO8u2Z67pE7AaAUUj7CJy0lXqHmymUvGFt6NE9R3HER0yw==} + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true @@ -3148,13 +3509,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nuxi@3.19.1: - resolution: {integrity: sha512-yjJggqwSkymaWM/f4+1nPBTW1Hg7tZ0ZQax69zlqq+Ftc6rfAnJSgGUwhAuoo7E7x3JGQ0Uzzokz11Y7PuRj6g==} - engines: {node: ^16.10.0 || >=18.0.0} - hasBin: true - - nuxt@3.15.1: - resolution: {integrity: sha512-8sKgqjhu5JoaVv89TnBW5S0jvsXRrEWGF+CguYUPK+6sRAtNcJAwcWxd4pEmURYQ2D0jjdfgr/VyH0i9CdhkBQ==} + nuxt@3.15.4: + resolution: {integrity: sha512-hSbZO4mR0uAMJtZPNTnCfiAtgleoOu28gvJcBNU7KQHgWnNXPjlWgwMczko2O4Tmnv9zIe/CQged+2HsPwl2ZA==} engines: {node: ^18.20.5 || ^20.9.0 || >=22.0.0} hasBin: true peerDependencies: @@ -3166,13 +3522,13 @@ packages: '@types/node': optional: true - nypm@0.3.12: - resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} + nypm@0.4.1: + resolution: {integrity: sha512-1b9mihliBh8UCcKtcGRu//G50iHpjxIQVUqkdhPT/SDVE7KdJKoHXLS0heuYTQCx95dFqiyUbXZB9r8ikn+93g==} engines: {node: ^14.16.0 || >=16.10.0} hasBin: true - nypm@0.4.1: - resolution: {integrity: sha512-1b9mihliBh8UCcKtcGRu//G50iHpjxIQVUqkdhPT/SDVE7KdJKoHXLS0heuYTQCx95dFqiyUbXZB9r8ikn+93g==} + nypm@0.5.2: + resolution: {integrity: sha512-AHzvnyUJYSrrphPhRWWZNcoZfArGNp3Vrc4pm/ZurO74tYNTgAPrEyBQEKy+qioqmWlPXwvMZCG2wOaHlPG0Pw==} engines: {node: ^14.16.0 || >=16.10.0} hasBin: true @@ -3216,8 +3572,8 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-typescript@7.5.2: - resolution: {integrity: sha512-W/QXuQz0Fa3bGY6LKoqTCgrSX+xI/ST+E5RXo2WBmp3WwgXCWKDJPHv5GZmElF4yLCccnqYsakBDOJikHZYGRw==} + openapi-typescript@7.6.1: + resolution: {integrity: sha512-F7RXEeo/heF3O9lOXo2bNjCOtfp7u+D6W3a3VNEH2xE6v+fxLtn5nq0uvUcA1F5aT+CMhNeC5Uqtg5tlXFX/ag==} hasBin: true peerDependencies: typescript: ^5.x @@ -3249,8 +3605,8 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@0.2.8: - resolution: {integrity: sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA==} + package-manager-detector@0.2.9: + resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} packrup@0.1.2: resolution: {integrity: sha512-ZcKU7zrr5GlonoS9cxxrb5HVswGnyj6jQvwFBa6p5VFw7G71VAHcUKL5wyZSU/ECtPM/9gacWxy2KFQKt1gMNA==} @@ -3322,8 +3678,8 @@ packages: pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - pathe@2.0.0: - resolution: {integrity: sha512-G7n4uhtk9qJt2hlD+UFfsIGY854wpF+zs2bUbQ3CQEUTcn7v25LRsrmurOxTo4bJgjE4qkyshd9ldsEuY9M6xg==} + pathe@2.0.2: + resolution: {integrity: sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==} perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} @@ -3343,8 +3699,8 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pinia@2.3.0: - resolution: {integrity: sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==} + pinia@2.3.1: + resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==} peerDependencies: typescript: '>=4.4.4' vue: ^2.7.0 || ^3.5.11 @@ -3356,8 +3712,8 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - pkg-types@1.3.0: - resolution: {integrity: sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} @@ -3371,8 +3727,8 @@ packages: resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} engines: {node: '>= 0.12.0'} - postcss-calc@10.1.0: - resolution: {integrity: sha512-uQ/LDGsf3mgsSUEXmAt3VsCSHR3aKqtEIkmB+4PhzYwRYOW5MZs/GhCCFpsOtJJkP6EC6uGipbrnaTjqaJZcJw==} + postcss-calc@10.1.1: + resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} engines: {node: ^18.12 || ^20.9 || >=22.0} peerDependencies: postcss: ^8.4.38 @@ -3580,23 +3936,23 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + postcss@8.5.1: + resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-plugin-tailwindcss@0.6.9: - resolution: {integrity: sha512-r0i3uhaZAXYP0At5xGfJH876W3HHGHDp+LCRUJrs57PBeQ6mYHMwr25KH8NPX44F2yGTvdnH7OqCshlQx183Eg==} + prettier-plugin-tailwindcss@0.6.11: + resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==} engines: {node: '>=14.21.3'} peerDependencies: '@ianvs/prettier-plugin-sort-imports': '*' '@prettier/plugin-pug': '*' '@shopify/prettier-plugin-liquid': '*' '@trivago/prettier-plugin-sort-imports': '*' - '@zackad/prettier-plugin-twig-melody': '*' + '@zackad/prettier-plugin-twig': '*' prettier: ^3.0 prettier-plugin-astro: '*' prettier-plugin-css-order: '*' @@ -3618,7 +3974,7 @@ packages: optional: true '@trivago/prettier-plugin-sort-imports': optional: true - '@zackad/prettier-plugin-twig-melody': + '@zackad/prettier-plugin-twig': optional: true prettier-plugin-astro: optional: true @@ -3659,6 +4015,9 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -3678,11 +4037,8 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - queue-tick@1.0.1: - resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - - radix-vue@1.9.12: - resolution: {integrity: sha512-zkr66Jqxbej4+oR6O/pZRzyM/VZi66ndbyIBZQjJKAXa1lIoYReZJse6W1EEDZKXknD7rXhpS+jM9Sr23lIqfg==} + radix-vue@1.9.13: + resolution: {integrity: sha512-wk0G69vRDU5TDmhYHZv5Y4j905CLfnvcsFB+CXAbXRuQIl5fUCmOWSOukKhj0MT9YRsW5ujZUjtDF0Ou/hg+8Q==} peerDependencies: vue: '>= 3.2.0' @@ -3724,9 +4080,9 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.0.2: - resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} - engines: {node: '>= 14.16.0'} + readdirp@4.1.1: + resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} + engines: {node: '>= 14.18.0'} redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} @@ -3812,8 +4168,8 @@ packages: rollup: optional: true - rollup@4.30.1: - resolution: {integrity: sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==} + rollup@4.34.1: + resolution: {integrity: sha512-iYZ/+PcdLYSGfH3S+dGahlW/RWmsqDhLgj1BT9DH/xXJ0ggZN7xkdP9wipPNjjNLczI+fmMLmTB9pye+d2r4GQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3849,8 +4205,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} hasBin: true @@ -3943,8 +4299,8 @@ packages: spdx-expression-parse@4.0.0: resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + spdx-license-ids@3.0.21: + resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} speakingurl@14.0.1: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} @@ -3971,8 +4327,8 @@ packages: resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==} engines: {node: '>=18'} - streamx@2.21.1: - resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + streamx@2.22.0: + resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -4011,6 +4367,9 @@ packages: strip-literal@2.1.1: resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + stylehacks@7.0.4: resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} @@ -4136,8 +4495,8 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - ts-api-utils@2.0.0: - resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} + ts-api-utils@2.0.1: + resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -4172,8 +4531,8 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} - type-fest@4.32.0: - resolution: {integrity: sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==} + type-fest@4.33.0: + resolution: {integrity: sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==} engines: {node: '>=16'} type-is@1.6.18: @@ -4203,15 +4562,19 @@ packages: unenv@1.10.0: resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} - unhead@1.11.15: - resolution: {integrity: sha512-fA0rYB7qMHKY4sg0yzEXhi0cqiF/nl/OUKNaXOS9ChJwCjJxabpZvmQIUOiGS+1ckoFbZc3qZnhDLpdeNhOQwg==} + unhead@1.11.18: + resolution: {integrity: sha512-TWgGUoZMpYe2yJwY6jZ0/9kpQT18ygr2h5lI6cUXdfD9UzDc0ytM9jGaleSYkj9guJWXkk7izYBnzJvxl8mRvQ==} unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} - unimport@3.14.5: - resolution: {integrity: sha512-tn890SwFFZxqaJSKQPPd+yygfKSATbM8BZWW1aCR2TJBTs1SDrmLamBueaFtYsGjHtQaRgqEbQflOjN2iW12gA==} + unimport@3.14.6: + resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==} + + unimport@4.0.0: + resolution: {integrity: sha512-FH+yZ36YaVlh0ZjHesP20Q4uL+wL0EqTNxDZcUupsIn6WRYXZAbIYEMDLTaLBpkNVzFpqZXS+am51/HR3ANUNw==} + engines: {node: '>=18.12.0'} universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} @@ -4225,6 +4588,14 @@ packages: vue-router: optional: true + unplugin-vue-router@0.11.2: + resolution: {integrity: sha512-X8BbQ3BNnMqaCYeMj80jtz5jC4AB0jcpdmECIYey9qKm6jy/upaPZ/WzfuT+iTGRiQAY4WemHueXxuzH127oOg==} + peerDependencies: + vue-router: ^4.4.0 + peerDependenciesMeta: + vue-router: + optional: true + unplugin@1.16.1: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} @@ -4340,9 +4711,9 @@ packages: peerDependencies: vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 - vite-node@2.1.8: - resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} - engines: {node: ^18.0.0 || >=20.0.0} + vite-node@3.0.5: + resolution: {integrity: sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true vite-plugin-checker@0.8.0: @@ -4394,39 +4765,8 @@ packages: peerDependencies: vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 - vite@5.4.11: - resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vite@6.0.7: - resolution: {integrity: sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==} + vite@6.0.11: + resolution: {integrity: sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -4543,6 +4883,10 @@ packages: typescript: optional: true + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -4674,7 +5018,7 @@ snapshots: '@antfu/install-pkg@1.0.0': dependencies: - package-manager-detector: 0.2.8 + package-manager-detector: 0.2.9 tinyexec: 0.3.2 '@antfu/utils@0.7.10': {} @@ -4685,20 +5029,20 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.26.3': {} + '@babel/compat-data@7.26.5': {} - '@babel/core@7.26.0': + '@babel/core@7.26.7': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.3 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helpers': 7.26.0 - '@babel/parser': 7.26.3 + '@babel/generator': 7.26.5 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.7) + '@babel/helpers': 7.26.7 + '@babel/parser': 7.26.7 '@babel/template': 7.25.9 - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.7 + '@babel/types': 7.26.7 convert-source-map: 2.0.0 debug: 4.4.0(supports-color@9.4.0) gensync: 1.0.0-beta.2 @@ -4707,81 +5051,81 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.26.3': + '@babel/generator@7.26.5': dependencies: - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.7 + '@babel/types': 7.26.7 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.25.9': dependencies: - '@babel/types': 7.26.3 + '@babel/types': 7.26.7 - '@babel/helper-compilation-targets@7.25.9': + '@babel/helper-compilation-targets@7.26.5': dependencies: - '@babel/compat-data': 7.26.3 + '@babel/compat-data': 7.26.5 '@babel/helper-validator-option': 7.25.9 browserslist: 4.24.4 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.26.7 '@babel/helper-annotate-as-pure': 7.25.9 '@babel/helper-member-expression-to-functions': 7.25.9 '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.7) '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/traverse': 7.26.4 + '@babel/traverse': 7.26.7 semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/helper-member-expression-to-functions@7.25.9': dependencies: - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.7 + '@babel/types': 7.26.7 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.25.9': dependencies: - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.7 + '@babel/types': 7.26.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.26.7 '@babel/helper-module-imports': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.4 + '@babel/traverse': 7.26.7 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.25.9': dependencies: - '@babel/types': 7.26.3 + '@babel/types': 7.26.7 - '@babel/helper-plugin-utils@7.25.9': {} + '@babel/helper-plugin-utils@7.26.5': {} - '@babel/helper-replace-supers@7.25.9(@babel/core@7.26.0)': + '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.26.7 '@babel/helper-member-expression-to-functions': 7.25.9 '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.26.4 + '@babel/traverse': 7.26.7 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.25.9': dependencies: - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.7 + '@babel/types': 7.26.7 transitivePeerDependencies: - supports-color @@ -4791,81 +5135,81 @@ snapshots: '@babel/helper-validator-option@7.25.9': {} - '@babel/helpers@7.26.0': + '@babel/helpers@7.26.7': dependencies: '@babel/template': 7.25.9 - '@babel/types': 7.26.3 + '@babel/types': 7.26.7 - '@babel/parser@7.26.3': + '@babel/parser@7.26.7': dependencies: - '@babel/types': 7.26.3 + '@babel/types': 7.26.7 - '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.0) + '@babel/core': 7.26.7 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.7) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.7) transitivePeerDependencies: - supports-color - '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.26.7 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.26.7 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.26.7 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.26.7 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/core': 7.26.7 + '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-typescript@7.26.3(@babel/core@7.26.0)': + '@babel/plugin-transform-typescript@7.26.7(@babel/core@7.26.7)': dependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.26.7 '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.7) + '@babel/helper-plugin-utils': 7.26.5 '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.7) transitivePeerDependencies: - supports-color - '@babel/standalone@7.26.4': {} + '@babel/standalone@7.26.7': {} '@babel/template@7.25.9': dependencies: '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.7 + '@babel/types': 7.26.7 - '@babel/traverse@7.26.4': + '@babel/traverse@7.26.7': dependencies: '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.3 - '@babel/parser': 7.26.3 + '@babel/generator': 7.26.5 + '@babel/parser': 7.26.7 '@babel/template': 7.25.9 - '@babel/types': 7.26.3 + '@babel/types': 7.26.7 debug: 4.4.0(supports-color@9.4.0) globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.26.3': + '@babel/types@7.26.7': dependencies: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 @@ -4893,109 +5237,169 @@ snapshots: dependencies: postcss-selector-parser: 7.0.0 + '@drizzle-team/brocli@0.10.2': {} + '@es-joy/jsdoccomment@0.49.0': dependencies: comment-parser: 1.4.1 esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@esbuild/aix-ppc64@0.21.5': + '@esbuild-kit/core-utils@3.3.2': + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + + '@esbuild-kit/esm-loader@2.6.5': + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.10.0 + + '@esbuild/aix-ppc64@0.19.12': optional: true '@esbuild/aix-ppc64@0.24.2': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm64@0.19.12': optional: true '@esbuild/android-arm64@0.24.2': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-arm@0.19.12': optional: true '@esbuild/android-arm@0.24.2': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/android-x64@0.19.12': optional: true '@esbuild/android-x64@0.24.2': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.19.12': optional: true '@esbuild/darwin-arm64@0.24.2': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.19.12': optional: true '@esbuild/darwin-x64@0.24.2': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.19.12': optional: true '@esbuild/freebsd-arm64@0.24.2': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.19.12': optional: true '@esbuild/freebsd-x64@0.24.2': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.19.12': optional: true '@esbuild/linux-arm64@0.24.2': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-arm@0.19.12': optional: true '@esbuild/linux-arm@0.24.2': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.19.12': optional: true '@esbuild/linux-ia32@0.24.2': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.19.12': optional: true '@esbuild/linux-loong64@0.24.2': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.19.12': optional: true '@esbuild/linux-mips64el@0.24.2': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.19.12': optional: true '@esbuild/linux-ppc64@0.24.2': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.19.12': optional: true '@esbuild/linux-riscv64@0.24.2': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.19.12': optional: true '@esbuild/linux-s390x@0.24.2': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/linux-x64@0.19.12': optional: true '@esbuild/linux-x64@0.24.2': @@ -5004,7 +5408,10 @@ snapshots: '@esbuild/netbsd-arm64@0.24.2': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.19.12': optional: true '@esbuild/netbsd-x64@0.24.2': @@ -5013,64 +5420,79 @@ snapshots: '@esbuild/openbsd-arm64@0.24.2': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.19.12': optional: true '@esbuild/openbsd-x64@0.24.2': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.19.12': optional: true '@esbuild/sunos-x64@0.24.2': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.19.12': optional: true '@esbuild/win32-arm64@0.24.2': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.19.12': optional: true '@esbuild/win32-ia32@0.24.2': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-x64@0.18.20': + optional: true + + '@esbuild/win32-x64@0.19.12': optional: true '@esbuild/win32-x64@0.24.2': optional: true - '@eschricht/nuxt-color-mode@1.1.5(magicast@0.3.5)(rollup@4.30.1)': + '@eschricht/nuxt-color-mode@1.1.5(magicast@0.3.5)(rollup@4.34.1)': dependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) transitivePeerDependencies: - magicast - rollup - supports-color - '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.4.1(eslint@9.19.0(jiti@2.4.2))': dependencies: - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.2.4(eslint@9.17.0(jiti@2.4.2))': + '@eslint/compat@1.2.6(eslint@9.19.0(jiti@2.4.2))': optionalDependencies: - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) - '@eslint/config-array@0.19.1': + '@eslint/config-array@0.19.2': dependencies: - '@eslint/object-schema': 2.1.5 + '@eslint/object-schema': 2.1.6 debug: 4.4.0(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color - '@eslint/core@0.9.1': + '@eslint/core@0.10.0': dependencies: '@types/json-schema': 7.0.15 @@ -5081,19 +5503,20 @@ snapshots: espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 js-yaml: 4.1.0 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.17.0': {} + '@eslint/js@9.19.0': {} - '@eslint/object-schema@2.1.5': {} + '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.2.4': + '@eslint/plugin-kit@0.2.5': dependencies: + '@eslint/core': 0.10.0 levn: 0.4.1 '@floating-ui/core@1.6.9': @@ -5129,7 +5552,7 @@ snapshots: '@humanwhocodes/retry@0.4.1': {} - '@internationalized/date@3.6.0': + '@internationalized/date@3.7.0': dependencies: '@swc/helpers': 0.5.15 @@ -5145,7 +5568,7 @@ snapshots: escodegen: 2.1.0 estree-walker: 2.0.2 jsonc-eslint-parser: 2.4.0 - mlly: 1.7.3 + mlly: 1.7.4 source-map-js: 1.2.1 yaml-eslint-parser: 1.2.3 optionalDependencies: @@ -5180,17 +5603,17 @@ snapshots: '@intlify/shared@11.0.0-rc.1': {} - '@intlify/shared@11.0.1': {} + '@intlify/shared@11.1.0': {} - '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.17.0(jiti@2.4.2))(rollup@4.30.1)(typescript@5.7.3)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': + '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.19.0(jiti@2.4.2))(rollup@4.34.1)(typescript@5.7.3)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) '@intlify/bundle-utils': 10.0.0(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3))) - '@intlify/shared': 11.0.1 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - '@typescript-eslint/scope-manager': 8.19.1 - '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) + '@intlify/shared': 11.1.0 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.0)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) debug: 4.4.0(supports-color@9.4.0) fast-glob: 3.3.3 js-yaml: 4.1.0 @@ -5211,11 +5634,11 @@ snapshots: '@intlify/utils@0.13.0': {} - '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.0)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': dependencies: - '@babel/parser': 7.26.3 + '@babel/parser': 7.26.7 optionalDependencies: - '@intlify/shared': 11.0.1 + '@intlify/shared': 11.1.0 '@vue/compiler-dom': 3.5.13 vue: 3.5.13(typescript@5.7.3) vue-i18n: 10.0.5(vue@3.5.13(typescript@5.7.3)) @@ -5275,24 +5698,82 @@ snapshots: '@kwsites/promise-deferred@1.1.1': {} - '@mapbox/node-pre-gyp@2.0.0-rc.0': + '@libsql/client@0.14.0': + dependencies: + '@libsql/core': 0.14.0 + '@libsql/hrana-client': 0.7.0 + js-base64: 3.7.7 + libsql: 0.4.7 + promise-limit: 2.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/core@0.14.0': + dependencies: + js-base64: 3.7.7 + + '@libsql/darwin-arm64@0.4.7': + optional: true + + '@libsql/darwin-x64@0.4.7': + optional: true + + '@libsql/hrana-client@0.7.0': + dependencies: + '@libsql/isomorphic-fetch': 0.3.1 + '@libsql/isomorphic-ws': 0.1.5 + js-base64: 3.7.7 + node-fetch: 3.3.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/isomorphic-fetch@0.3.1': {} + + '@libsql/isomorphic-ws@0.1.5': + dependencies: + '@types/ws': 8.5.14 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/linux-arm64-gnu@0.4.7': + optional: true + + '@libsql/linux-arm64-musl@0.4.7': + optional: true + + '@libsql/linux-x64-gnu@0.4.7': + optional: true + + '@libsql/linux-x64-musl@0.4.7': + optional: true + + '@libsql/win32-x64-msvc@0.4.7': + optional: true + + '@mapbox/node-pre-gyp@2.0.0': dependencies: - consola: 3.3.3 + consola: 3.4.0 detect-libc: 2.0.3 https-proxy-agent: 7.0.6(supports-color@9.4.0) node-fetch: 2.7.0 - nopt: 8.0.0 - semver: 7.6.3 + nopt: 8.1.0 + semver: 7.7.1 tar: 7.4.3 transitivePeerDependencies: - encoding - supports-color - '@miyaneee/rollup-plugin-json5@1.2.0(rollup@4.30.1)': + '@miyaneee/rollup-plugin-json5@1.2.0(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) json5: 2.2.3 - rollup: 4.30.1 + rollup: 4.34.1 + + '@neon-rs/load@0.0.4': {} '@netlify/functions@2.8.2': dependencies: @@ -5315,16 +5796,44 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.18.0 + fastq: 1.19.0 + + '@nuxt/cli@3.21.1(magicast@0.3.5)': + dependencies: + c12: 2.0.1(magicast@0.3.5) + chokidar: 4.0.3 + citty: 0.1.6 + clipboardy: 4.0.0 + consola: 3.4.0 + defu: 6.1.4 + fuse.js: 7.1.0 + giget: 1.2.4 + h3: 1.14.0 + httpxy: 0.1.7 + jiti: 2.4.2 + listhen: 1.9.0 + nypm: 0.5.2 + ofetch: 1.4.1 + ohash: 1.1.4 + pathe: 2.0.2 + perfect-debounce: 1.0.0 + pkg-types: 1.3.1 + scule: 1.3.0 + semver: 7.7.1 + std-env: 3.8.0 + tinyexec: 0.3.2 + ufo: 1.5.4 + transitivePeerDependencies: + - magicast '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))': + '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(rollup@4.34.1)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))': dependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - '@nuxt/schema': 3.15.1 + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + '@nuxt/schema': 3.15.4 execa: 7.2.0 - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) transitivePeerDependencies: - magicast - rollup @@ -5332,28 +5841,28 @@ snapshots: '@nuxt/devtools-wizard@1.7.0': dependencies: - consola: 3.3.3 + consola: 3.4.0 diff: 7.0.0 execa: 7.2.0 global-directory: 4.0.1 magicast: 0.3.5 pathe: 1.1.2 - pkg-types: 1.3.0 + pkg-types: 1.3.1 prompts: 2.4.2 rc9: 2.1.2 - semver: 7.6.3 + semver: 7.7.1 - '@nuxt/devtools@1.7.0(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + '@nuxt/devtools@1.7.0(rollup@4.34.1)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': dependencies: '@antfu/utils': 0.7.10 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) + '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.34.1)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) '@nuxt/devtools-wizard': 1.7.0 - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - '@vue/devtools-core': 7.6.8(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + '@vue/devtools-core': 7.6.8(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) '@vue/devtools-kit': 7.6.8 birpc: 0.2.19 - consola: 3.3.3 - cronstrue: 2.52.0 + consola: 3.4.0 + cronstrue: 2.54.0 destr: 2.0.3 error-stack-parser-es: 0.1.5 execa: 7.2.0 @@ -5370,17 +5879,17 @@ snapshots: ohash: 1.1.4 pathe: 1.1.2 perfect-debounce: 1.0.0 - pkg-types: 1.3.0 + pkg-types: 1.3.1 rc9: 2.1.2 scule: 1.3.0 - semver: 7.6.3 + semver: 7.7.1 simple-git: 3.27.0 sirv: 3.0.0 tinyglobby: 0.2.10 - unimport: 3.14.5(rollup@4.30.1) - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.1(magicast@0.3.5)(rollup@4.30.1))(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) - vite-plugin-vue-inspector: 5.3.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) + unimport: 3.14.6(rollup@4.34.1) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.34.1))(rollup@4.34.1)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) + vite-plugin-vue-inspector: 5.3.1(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) which: 3.0.1 ws: 8.18.0 transitivePeerDependencies: @@ -5390,90 +5899,90 @@ snapshots: - utf-8-validate - vue - '@nuxt/eslint-config@0.7.5(@vue/compiler-sfc@3.5.13)(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@nuxt/eslint-config@1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@antfu/install-pkg': 1.0.0 '@clack/prompts': 0.9.1 - '@eslint/js': 9.17.0 - '@nuxt/eslint-plugin': 0.7.5(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - '@stylistic/eslint-plugin': 2.12.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/eslint-plugin': 8.19.1(@typescript-eslint/parser@8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/parser': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - eslint: 9.17.0(jiti@2.4.2) - eslint-config-flat-gitignore: 0.2.0(eslint@9.17.0(jiti@2.4.2)) - eslint-flat-config-utils: 1.0.0 - eslint-merge-processors: 1.0.0(eslint@9.17.0(jiti@2.4.2)) - eslint-plugin-import-x: 4.6.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - eslint-plugin-jsdoc: 50.6.1(eslint@9.17.0(jiti@2.4.2)) - eslint-plugin-regexp: 2.7.0(eslint@9.17.0(jiti@2.4.2)) - eslint-plugin-unicorn: 56.0.1(eslint@9.17.0(jiti@2.4.2)) - eslint-plugin-vue: 9.32.0(eslint@9.17.0(jiti@2.4.2)) - eslint-processor-vue-blocks: 0.1.2(@vue/compiler-sfc@3.5.13)(eslint@9.17.0(jiti@2.4.2)) + '@eslint/js': 9.19.0 + '@nuxt/eslint-plugin': 1.0.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + '@stylistic/eslint-plugin': 3.0.1(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/eslint-plugin': 8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/parser': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + eslint: 9.19.0(jiti@2.4.2) + eslint-config-flat-gitignore: 2.0.0(eslint@9.19.0(jiti@2.4.2)) + eslint-flat-config-utils: 2.0.1 + eslint-merge-processors: 1.0.0(eslint@9.19.0(jiti@2.4.2)) + eslint-plugin-import-x: 4.6.1(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + eslint-plugin-jsdoc: 50.6.3(eslint@9.19.0(jiti@2.4.2)) + eslint-plugin-regexp: 2.7.0(eslint@9.19.0(jiti@2.4.2)) + eslint-plugin-unicorn: 56.0.1(eslint@9.19.0(jiti@2.4.2)) + eslint-plugin-vue: 9.32.0(eslint@9.19.0(jiti@2.4.2)) + eslint-processor-vue-blocks: 1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.2)) globals: 15.14.0 - local-pkg: 0.5.1 - pathe: 2.0.0 - vue-eslint-parser: 9.4.3(eslint@9.17.0(jiti@2.4.2)) + local-pkg: 1.0.0 + pathe: 2.0.2 + vue-eslint-parser: 9.4.3(eslint@9.19.0(jiti@2.4.2)) transitivePeerDependencies: - '@vue/compiler-sfc' - supports-color - typescript - '@nuxt/eslint-plugin@0.7.5(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@nuxt/eslint-plugin@1.0.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.19.1 - '@typescript-eslint/utils': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - eslint: 9.17.0(jiti@2.4.2) + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + eslint: 9.19.0(jiti@2.4.2) transitivePeerDependencies: - supports-color - typescript - '@nuxt/kit@3.15.1(magicast@0.3.5)(rollup@4.30.1)': + '@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.34.1)': dependencies: - '@nuxt/schema': 3.15.1 c12: 2.0.1(magicast@0.3.5) - consola: 3.3.3 + consola: 3.4.0 defu: 6.1.4 destr: 2.0.3 globby: 14.0.2 - ignore: 7.0.0 + ignore: 7.0.3 jiti: 2.4.2 klona: 2.0.6 knitwork: 1.2.0 - mlly: 1.7.3 + mlly: 1.7.4 ohash: 1.1.4 - pathe: 2.0.0 - pkg-types: 1.3.0 + pathe: 2.0.2 + pkg-types: 1.3.1 scule: 1.3.0 - semver: 7.6.3 + semver: 7.7.1 + std-env: 3.8.0 ufo: 1.5.4 unctx: 2.4.1 - unimport: 3.14.5(rollup@4.30.1) + unimport: 4.0.0(rollup@4.34.1) untyped: 1.5.2 transitivePeerDependencies: - magicast - rollup - supports-color - '@nuxt/schema@3.15.1': + '@nuxt/schema@3.15.4': dependencies: - consola: 3.3.3 + consola: 3.4.0 defu: 6.1.4 - pathe: 2.0.0 + pathe: 2.0.2 std-env: 3.8.0 - '@nuxt/telemetry@2.6.4(magicast@0.3.5)(rollup@4.30.1)': + '@nuxt/telemetry@2.6.4(magicast@0.3.5)(rollup@4.34.1)': dependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) citty: 0.1.6 - consola: 3.3.3 + consola: 3.4.0 destr: 2.0.3 dotenv: 16.4.7 git-url-parse: 16.0.0 is-docker: 3.0.0 ofetch: 1.4.1 - package-manager-detector: 0.2.8 + package-manager-detector: 0.2.9 parse-git-config: 3.0.0 - pathe: 2.0.0 + pathe: 2.0.2 rc9: 2.1.2 std-env: 3.8.0 transitivePeerDependencies: @@ -5481,38 +5990,38 @@ snapshots: - rollup - supports-color - '@nuxt/vite-builder@3.15.1(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0)': + '@nuxt/vite-builder@3.15.4(@types/node@22.13.1)(eslint@9.19.0(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.1)(terser@5.37.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0)': dependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - '@rollup/plugin-replace': 6.0.2(rollup@4.30.1) - '@vitejs/plugin-vue': 5.2.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - '@vitejs/plugin-vue-jsx': 4.1.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - autoprefixer: 10.4.20(postcss@8.4.49) - consola: 3.3.3 - cssnano: 7.0.6(postcss@8.4.49) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + '@rollup/plugin-replace': 6.0.2(rollup@4.34.1) + '@vitejs/plugin-vue': 5.2.1(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) + '@vitejs/plugin-vue-jsx': 4.1.1(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) + autoprefixer: 10.4.20(postcss@8.5.1) + consola: 3.4.0 + cssnano: 7.0.6(postcss@8.5.1) defu: 6.1.4 esbuild: 0.24.2 escape-string-regexp: 5.0.0 externality: 1.0.2 get-port-please: 3.1.2 - h3: 1.13.0 + h3: 1.14.0 jiti: 2.4.2 knitwork: 1.2.0 magic-string: 0.30.17 - mlly: 1.7.3 + mlly: 1.7.4 ohash: 1.1.4 - pathe: 2.0.0 + pathe: 2.0.2 perfect-debounce: 1.0.0 - pkg-types: 1.3.0 - postcss: 8.4.49 - rollup-plugin-visualizer: 5.14.0(rollup@4.30.1) + pkg-types: 1.3.1 + postcss: 8.5.1 + rollup-plugin-visualizer: 5.14.0(rollup@4.34.1) std-env: 3.8.0 ufo: 1.5.4 unenv: 1.10.0 unplugin: 2.1.2 - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vite-node: 2.1.8(@types/node@22.10.5)(terser@5.37.0) - vite-plugin-checker: 0.8.0(eslint@9.17.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite-node: 3.0.5(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite-plugin-checker: 0.8.0(eslint@9.19.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.7.3)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)) vue: 3.5.13(typescript@5.7.3) vue-bundle-renderer: 2.1.1 transitivePeerDependencies: @@ -5540,15 +6049,15 @@ snapshots: - vue-tsc - yaml - '@nuxtjs/i18n@9.1.1(@vue/compiler-dom@3.5.13)(eslint@9.17.0(jiti@2.4.2))(magicast@0.3.5)(rollup@4.30.1)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))': + '@nuxtjs/i18n@9.1.5(@vue/compiler-dom@3.5.13)(eslint@9.19.0(jiti@2.4.2))(magicast@0.3.5)(rollup@4.34.1)(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))': dependencies: '@intlify/h3': 0.6.1 '@intlify/shared': 10.0.5 - '@intlify/unplugin-vue-i18n': 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.17.0(jiti@2.4.2))(rollup@4.30.1)(typescript@5.7.3)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) + '@intlify/unplugin-vue-i18n': 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.19.0(jiti@2.4.2))(rollup@4.34.1)(typescript@5.7.3)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) '@intlify/utils': 0.13.0 - '@miyaneee/rollup-plugin-json5': 1.2.0(rollup@4.30.1) - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - '@rollup/plugin-yaml': 4.1.2(rollup@4.30.1) + '@miyaneee/rollup-plugin-json5': 1.2.0(rollup@4.34.1) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + '@rollup/plugin-yaml': 4.1.2(rollup@4.34.1) '@vue/compiler-sfc': 3.5.13 debug: 4.4.0(supports-color@9.4.0) defu: 6.1.4 @@ -5556,13 +6065,13 @@ snapshots: is-https: 4.0.0 knitwork: 1.2.0 magic-string: 0.30.17 - mlly: 1.7.3 + mlly: 1.7.4 pathe: 1.1.2 scule: 1.3.0 sucrase: 3.35.0 ufo: 1.5.4 unplugin: 1.16.1 - unplugin-vue-router: 0.10.9(rollup@4.30.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) + unplugin-vue-router: 0.10.9(rollup@4.34.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) vue-i18n: 10.0.5(vue@3.5.13(typescript@5.7.3)) vue-router: 4.5.0(vue@3.5.13(typescript@5.7.3)) transitivePeerDependencies: @@ -5575,17 +6084,18 @@ snapshots: - typescript - vue - '@nuxtjs/tailwindcss@6.12.2(magicast@0.3.5)(rollup@4.30.1)': + '@nuxtjs/tailwindcss@6.13.1(magicast@0.3.5)(rollup@4.34.1)': dependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - autoprefixer: 10.4.20(postcss@8.4.49) - consola: 3.3.3 + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + autoprefixer: 10.4.20(postcss@8.5.1) + c12: 2.0.1(magicast@0.3.5) + consola: 3.4.0 defu: 6.1.4 - h3: 1.13.0 + h3: 1.14.0 klona: 2.0.6 - pathe: 1.1.2 - postcss: 8.4.49 - postcss-nesting: 13.0.1(postcss@8.4.49) + pathe: 2.0.2 + postcss: 8.5.1 + postcss-nesting: 13.0.1(postcss@8.5.1) tailwind-config-viewer: 2.0.4(tailwindcss@3.4.17) tailwindcss: 3.4.17 ufo: 1.5.4 @@ -5596,77 +6106,77 @@ snapshots: - supports-color - ts-node - '@parcel/watcher-android-arm64@2.5.0': + '@parcel/watcher-android-arm64@2.5.1': optional: true - '@parcel/watcher-darwin-arm64@2.5.0': + '@parcel/watcher-darwin-arm64@2.5.1': optional: true - '@parcel/watcher-darwin-x64@2.5.0': + '@parcel/watcher-darwin-x64@2.5.1': optional: true - '@parcel/watcher-freebsd-x64@2.5.0': + '@parcel/watcher-freebsd-x64@2.5.1': optional: true - '@parcel/watcher-linux-arm-glibc@2.5.0': + '@parcel/watcher-linux-arm-glibc@2.5.1': optional: true - '@parcel/watcher-linux-arm-musl@2.5.0': + '@parcel/watcher-linux-arm-musl@2.5.1': optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.0': + '@parcel/watcher-linux-arm64-glibc@2.5.1': optional: true - '@parcel/watcher-linux-arm64-musl@2.5.0': + '@parcel/watcher-linux-arm64-musl@2.5.1': optional: true - '@parcel/watcher-linux-x64-glibc@2.5.0': + '@parcel/watcher-linux-x64-glibc@2.5.1': optional: true - '@parcel/watcher-linux-x64-musl@2.5.0': + '@parcel/watcher-linux-x64-musl@2.5.1': optional: true - '@parcel/watcher-wasm@2.5.0': + '@parcel/watcher-wasm@2.5.1': dependencies: is-glob: 4.0.3 micromatch: 4.0.8 - '@parcel/watcher-win32-arm64@2.5.0': + '@parcel/watcher-win32-arm64@2.5.1': optional: true - '@parcel/watcher-win32-ia32@2.5.0': + '@parcel/watcher-win32-ia32@2.5.1': optional: true - '@parcel/watcher-win32-x64@2.5.0': + '@parcel/watcher-win32-x64@2.5.1': optional: true - '@parcel/watcher@2.5.0': + '@parcel/watcher@2.5.1': dependencies: detect-libc: 1.0.3 is-glob: 4.0.3 micromatch: 4.0.8 node-addon-api: 7.1.1 optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.0 - '@parcel/watcher-darwin-arm64': 2.5.0 - '@parcel/watcher-darwin-x64': 2.5.0 - '@parcel/watcher-freebsd-x64': 2.5.0 - '@parcel/watcher-linux-arm-glibc': 2.5.0 - '@parcel/watcher-linux-arm-musl': 2.5.0 - '@parcel/watcher-linux-arm64-glibc': 2.5.0 - '@parcel/watcher-linux-arm64-musl': 2.5.0 - '@parcel/watcher-linux-x64-glibc': 2.5.0 - '@parcel/watcher-linux-x64-musl': 2.5.0 - '@parcel/watcher-win32-arm64': 2.5.0 - '@parcel/watcher-win32-ia32': 2.5.0 - '@parcel/watcher-win32-x64': 2.5.0 + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 '@phc/format@1.0.0': {} - '@pinia/nuxt@0.9.0(magicast@0.3.5)(pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(rollup@4.30.1)': + '@pinia/nuxt@0.9.0(magicast@0.3.5)(pinia@2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(rollup@4.34.1)': dependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - pinia: 2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + pinia: 2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) transitivePeerDependencies: - magicast - rollup @@ -5686,158 +6196,156 @@ snapshots: require-from-string: 2.0.2 uri-js-replace: 1.0.1 - '@redocly/config@0.17.1': {} + '@redocly/config@0.20.3': {} - '@redocly/openapi-core@1.27.1(supports-color@9.4.0)': + '@redocly/openapi-core@1.28.1(supports-color@9.4.0)': dependencies: '@redocly/ajv': 8.11.2 - '@redocly/config': 0.17.1 + '@redocly/config': 0.20.3 colorette: 1.4.0 https-proxy-agent: 7.0.6(supports-color@9.4.0) js-levenshtein: 1.1.6 js-yaml: 4.1.0 minimatch: 5.1.6 - node-fetch: 2.7.0 pluralize: 8.0.0 yaml-ast-parser: 0.0.43 transitivePeerDependencies: - - encoding - supports-color - '@rollup/plugin-alias@5.1.1(rollup@4.30.1)': + '@rollup/plugin-alias@5.1.1(rollup@4.34.1)': optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-commonjs@28.0.2(rollup@4.30.1)': + '@rollup/plugin-commonjs@28.0.2(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) commondir: 1.0.1 estree-walker: 2.0.2 - fdir: 6.4.2(picomatch@4.0.2) + fdir: 6.4.3(picomatch@4.0.2) is-reference: 1.2.1 magic-string: 0.30.17 picomatch: 4.0.2 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-inject@5.0.5(rollup@4.30.1)': + '@rollup/plugin-inject@5.0.5(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) estree-walker: 2.0.2 magic-string: 0.30.17 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-json@6.1.0(rollup@4.30.1)': + '@rollup/plugin-json@6.1.0(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.30.1)': + '@rollup/plugin-node-resolve@15.3.1(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.10 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-replace@6.0.2(rollup@4.30.1)': + '@rollup/plugin-replace@6.0.2(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) magic-string: 0.30.17 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-terser@0.4.4(rollup@4.30.1)': + '@rollup/plugin-terser@0.4.4(rollup@4.34.1)': dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 terser: 5.37.0 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/plugin-yaml@4.1.2(rollup@4.30.1)': + '@rollup/plugin-yaml@4.1.2(rollup@4.34.1)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) js-yaml: 4.1.0 tosource: 2.0.0-alpha.3 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/pluginutils@5.1.4(rollup@4.30.1)': + '@rollup/pluginutils@5.1.4(rollup@4.34.1)': dependencies: '@types/estree': 1.0.6 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - '@rollup/rollup-android-arm-eabi@4.30.1': + '@rollup/rollup-android-arm-eabi@4.34.1': optional: true - '@rollup/rollup-android-arm64@4.30.1': + '@rollup/rollup-android-arm64@4.34.1': optional: true - '@rollup/rollup-darwin-arm64@4.30.1': + '@rollup/rollup-darwin-arm64@4.34.1': optional: true - '@rollup/rollup-darwin-x64@4.30.1': + '@rollup/rollup-darwin-x64@4.34.1': optional: true - '@rollup/rollup-freebsd-arm64@4.30.1': + '@rollup/rollup-freebsd-arm64@4.34.1': optional: true - '@rollup/rollup-freebsd-x64@4.30.1': + '@rollup/rollup-freebsd-x64@4.34.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.30.1': + '@rollup/rollup-linux-arm-gnueabihf@4.34.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.30.1': + '@rollup/rollup-linux-arm-musleabihf@4.34.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.30.1': + '@rollup/rollup-linux-arm64-gnu@4.34.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.30.1': + '@rollup/rollup-linux-arm64-musl@4.34.1': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.30.1': + '@rollup/rollup-linux-loongarch64-gnu@4.34.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.30.1': + '@rollup/rollup-linux-powerpc64le-gnu@4.34.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.30.1': + '@rollup/rollup-linux-riscv64-gnu@4.34.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.30.1': + '@rollup/rollup-linux-s390x-gnu@4.34.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.30.1': + '@rollup/rollup-linux-x64-gnu@4.34.1': optional: true - '@rollup/rollup-linux-x64-musl@4.30.1': + '@rollup/rollup-linux-x64-musl@4.34.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.30.1': + '@rollup/rollup-win32-arm64-msvc@4.34.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.30.1': + '@rollup/rollup-win32-ia32-msvc@4.34.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.30.1': + '@rollup/rollup-win32-x64-msvc@4.34.1': optional: true '@sindresorhus/merge-streams@2.3.0': {} - '@stylistic/eslint-plugin@2.12.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@stylistic/eslint-plugin@3.0.1(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@typescript-eslint/utils': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - eslint: 9.17.0(jiti@2.4.2) + '@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + eslint: 9.19.0(jiti@2.4.2) eslint-visitor-keys: 4.2.0 espree: 10.3.0 estraverse: 5.3.0 @@ -5846,7 +6354,7 @@ snapshots: - supports-color - typescript - '@svgdotjs/svg.draggable.js@3.0.4(@svgdotjs/svg.js@3.2.4)': + '@svgdotjs/svg.draggable.js@3.0.5(@svgdotjs/svg.js@3.2.4)': dependencies: '@svgdotjs/svg.js': 3.2.4 @@ -5874,18 +6382,18 @@ snapshots: mini-svg-data-uri: 1.4.4 tailwindcss: 3.4.17 - '@tanstack/virtual-core@3.11.2': {} + '@tanstack/virtual-core@3.12.0': {} - '@tanstack/vue-virtual@3.11.2(vue@3.5.13(typescript@5.7.3))': + '@tanstack/vue-virtual@3.12.0(vue@3.5.13(typescript@5.7.3))': dependencies: - '@tanstack/virtual-core': 3.11.2 + '@tanstack/virtual-core': 3.12.0 vue: 3.5.13(typescript@5.7.3) '@trysound/sax@0.2.0': {} '@types/debug@4.1.12': dependencies: - '@types/ms': 0.7.34 + '@types/ms': 2.1.0 '@types/doctrine@0.0.9': {} @@ -5893,13 +6401,13 @@ snapshots: '@types/http-proxy@1.17.15': dependencies: - '@types/node': 22.10.5 + '@types/node': 22.13.1 '@types/json-schema@7.0.15': {} - '@types/ms@0.7.34': {} + '@types/ms@2.1.0': {} - '@types/node@22.10.5': + '@types/node@22.13.1': dependencies: undici-types: 6.20.0 @@ -5909,7 +6417,7 @@ snapshots: '@types/qrcode@1.5.5': dependencies: - '@types/node': 22.10.5 + '@types/node': 22.13.1 '@types/resolve@1.20.2': {} @@ -5917,115 +6425,119 @@ snapshots: '@types/web-bluetooth@0.0.20': {} - '@typescript-eslint/eslint-plugin@8.19.1(@typescript-eslint/parser@8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@types/ws@8.5.14': + dependencies: + '@types/node': 22.13.1 + + '@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/scope-manager': 8.19.1 - '@typescript-eslint/type-utils': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/utils': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.19.1 - eslint: 9.17.0(jiti@2.4.2) + '@typescript-eslint/parser': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/type-utils': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.23.0 + eslint: 9.19.0(jiti@2.4.2) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 2.0.0(typescript@5.7.3) + ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@typescript-eslint/scope-manager': 8.19.1 - '@typescript-eslint/types': 8.19.1 - '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.19.1 + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.23.0 debug: 4.4.0(supports-color@9.4.0) - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.19.1': + '@typescript-eslint/scope-manager@8.23.0': dependencies: - '@typescript-eslint/types': 8.19.1 - '@typescript-eslint/visitor-keys': 8.19.1 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/visitor-keys': 8.23.0 - '@typescript-eslint/type-utils@8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/type-utils@8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) - '@typescript-eslint/utils': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) debug: 4.4.0(supports-color@9.4.0) - eslint: 9.17.0(jiti@2.4.2) - ts-api-utils: 2.0.0(typescript@5.7.3) + eslint: 9.19.0(jiti@2.4.2) + ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.19.1': {} + '@typescript-eslint/types@8.23.0': {} - '@typescript-eslint/typescript-estree@8.19.1(typescript@5.7.3)': + '@typescript-eslint/typescript-estree@8.23.0(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.19.1 - '@typescript-eslint/visitor-keys': 8.19.1 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/visitor-keys': 8.23.0 debug: 4.4.0(supports-color@9.4.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 2.0.0(typescript@5.7.3) + semver: 7.7.1 + ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/utils@8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 8.19.1 - '@typescript-eslint/types': 8.19.1 - '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.7.3) - eslint: 9.17.0(jiti@2.4.2) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) + eslint: 9.19.0(jiti@2.4.2) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.19.1': + '@typescript-eslint/visitor-keys@8.23.0': dependencies: - '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/types': 8.23.0 eslint-visitor-keys: 4.2.0 - '@unhead/dom@1.11.15': + '@unhead/dom@1.11.18': dependencies: - '@unhead/schema': 1.11.15 - '@unhead/shared': 1.11.15 + '@unhead/schema': 1.11.18 + '@unhead/shared': 1.11.18 - '@unhead/schema@1.11.15': + '@unhead/schema@1.11.18': dependencies: hookable: 5.5.3 zhead: 2.2.4 - '@unhead/shared@1.11.15': + '@unhead/shared@1.11.18': dependencies: - '@unhead/schema': 1.11.15 + '@unhead/schema': 1.11.18 packrup: 0.1.2 - '@unhead/ssr@1.11.15': + '@unhead/ssr@1.11.18': dependencies: - '@unhead/schema': 1.11.15 - '@unhead/shared': 1.11.15 + '@unhead/schema': 1.11.18 + '@unhead/shared': 1.11.18 - '@unhead/vue@1.11.15(vue@3.5.13(typescript@5.7.3))': + '@unhead/vue@1.11.18(vue@3.5.13(typescript@5.7.3))': dependencies: - '@unhead/schema': 1.11.15 - '@unhead/shared': 1.11.15 + '@unhead/schema': 1.11.18 + '@unhead/shared': 1.11.18 hookable: 5.5.3 - unhead: 1.11.15 + unhead: 1.11.18 vue: 3.5.13(typescript@5.7.3) - '@vercel/nft@0.27.10(rollup@4.30.1)': + '@vercel/nft@0.27.10(rollup@4.34.1)': dependencies: - '@mapbox/node-pre-gyp': 2.0.0-rc.0 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@mapbox/node-pre-gyp': 2.0.0 + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) acorn: 8.14.0 acorn-import-attributes: 1.9.5(acorn@8.14.0) async-sema: 3.1.1 @@ -6041,19 +6553,19 @@ snapshots: - rollup - supports-color - '@vitejs/plugin-vue-jsx@4.1.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + '@vitejs/plugin-vue-jsx@4.1.1(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-transform-typescript': 7.26.3(@babel/core@7.26.0) - '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.0) - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + '@babel/core': 7.26.7 + '@babel/plugin-transform-typescript': 7.26.7(@babel/core@7.26.7) + '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.7) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) vue: 3.5.13(typescript@5.7.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.2.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + '@vitejs/plugin-vue@5.2.1(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': dependencies: - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) vue: 3.5.13(typescript@5.7.3) '@volar/language-core@2.4.11': @@ -6068,52 +6580,50 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.0.8 - '@vue-macros/common@1.15.1(rollup@4.30.1)(vue@3.5.13(typescript@5.7.3))': + '@vue-macros/common@1.16.1(vue@3.5.13(typescript@5.7.3))': dependencies: - '@babel/types': 7.26.3 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) '@vue/compiler-sfc': 3.5.13 - ast-kit: 1.3.2 - local-pkg: 0.5.1 - magic-string-ast: 0.6.3 + ast-kit: 1.4.0 + local-pkg: 1.0.0 + magic-string-ast: 0.7.0 + pathe: 2.0.2 + picomatch: 4.0.2 optionalDependencies: vue: 3.5.13(typescript@5.7.3) - transitivePeerDependencies: - - rollup '@vue/babel-helper-vue-transform-on@1.2.5': {} - '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.0)': + '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.7)': dependencies: '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.7) '@babel/template': 7.25.9 - '@babel/traverse': 7.26.4 - '@babel/types': 7.26.3 + '@babel/traverse': 7.26.7 + '@babel/types': 7.26.7 '@vue/babel-helper-vue-transform-on': 1.2.5 - '@vue/babel-plugin-resolve-type': 1.2.5(@babel/core@7.26.0) + '@vue/babel-plugin-resolve-type': 1.2.5(@babel/core@7.26.7) html-tags: 3.3.1 svg-tags: 1.0.0 optionalDependencies: - '@babel/core': 7.26.0 + '@babel/core': 7.26.7 transitivePeerDependencies: - supports-color - '@vue/babel-plugin-resolve-type@1.2.5(@babel/core@7.26.0)': + '@vue/babel-plugin-resolve-type@1.2.5(@babel/core@7.26.7)': dependencies: '@babel/code-frame': 7.26.2 - '@babel/core': 7.26.0 + '@babel/core': 7.26.7 '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/parser': 7.26.3 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/parser': 7.26.7 '@vue/compiler-sfc': 3.5.13 transitivePeerDependencies: - supports-color '@vue/compiler-core@3.5.13': dependencies: - '@babel/parser': 7.26.3 + '@babel/parser': 7.26.7 '@vue/shared': 3.5.13 entities: 4.5.0 estree-walker: 2.0.2 @@ -6126,14 +6636,14 @@ snapshots: '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.26.3 + '@babel/parser': 7.26.7 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 estree-walker: 2.0.2 magic-string: 0.30.17 - postcss: 8.4.49 + postcss: 8.5.1 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.13': @@ -6148,21 +6658,21 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/devtools-core@7.6.8(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': + '@vue/devtools-core@7.6.8(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3))': dependencies: '@vue/devtools-kit': 7.6.8 - '@vue/devtools-shared': 7.7.0 + '@vue/devtools-shared': 7.7.1 mitt: 3.0.1 nanoid: 5.0.9 pathe: 1.1.2 - vite-hot-client: 0.2.4(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) + vite-hot-client: 0.2.4(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)) vue: 3.5.13(typescript@5.7.3) transitivePeerDependencies: - vite '@vue/devtools-kit@7.6.8': dependencies: - '@vue/devtools-shared': 7.7.0 + '@vue/devtools-shared': 7.7.1 birpc: 0.2.19 hookable: 5.5.3 mitt: 3.0.1 @@ -6170,7 +6680,7 @@ snapshots: speakingurl: 14.0.1 superjson: 2.2.2 - '@vue/devtools-shared@7.7.0': + '@vue/devtools-shared@7.7.1': dependencies: rfdc: 1.4.1 @@ -6232,7 +6742,7 @@ snapshots: '@yr/monotone-cubic-spline@1.0.3': {} - abbrev@2.0.0: {} + abbrev@3.0.0: {} abort-controller@3.0.0: dependencies: @@ -6287,9 +6797,9 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - apexcharts@4.3.0: + apexcharts@4.4.0: dependencies: - '@svgdotjs/svg.draggable.js': 3.0.4(@svgdotjs/svg.js@3.2.4) + '@svgdotjs/svg.draggable.js': 3.0.5(@svgdotjs/svg.js@3.2.4) '@svgdotjs/svg.filter.js': 3.0.8 '@svgdotjs/svg.js': 3.2.4 '@svgdotjs/svg.resize.js': 2.0.5(@svgdotjs/svg.js@3.2.4)(@svgdotjs/svg.select.js@4.0.2(@svgdotjs/svg.js@3.2.4)) @@ -6332,15 +6842,15 @@ snapshots: dependencies: tslib: 2.8.1 - ast-kit@1.3.2: + ast-kit@1.4.0: dependencies: - '@babel/parser': 7.26.3 - pathe: 1.1.2 + '@babel/parser': 7.26.7 + pathe: 2.0.2 ast-walker-scope@0.6.2: dependencies: - '@babel/parser': 7.26.3 - ast-kit: 1.3.2 + '@babel/parser': 7.26.7 + ast-kit: 1.4.0 async-sema@3.1.1: {} @@ -6352,21 +6862,21 @@ snapshots: at-least-node@1.0.0: {} - autoprefixer@10.4.20(postcss@8.4.49): + autoprefixer@10.4.20(postcss@8.5.1): dependencies: browserslist: 4.24.4 - caniuse-lite: 1.0.30001692 + caniuse-lite: 1.0.30001697 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 b4a@1.6.7: {} balanced-match@1.0.2: {} - bare-events@2.5.3: + bare-events@2.5.4: optional: true base64-js@1.5.1: {} @@ -6400,8 +6910,8 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001692 - electron-to-chromium: 1.5.79 + caniuse-lite: 1.0.30001697 + electron-to-chromium: 1.5.91 node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) @@ -6426,13 +6936,13 @@ snapshots: confbox: 0.1.8 defu: 6.1.4 dotenv: 16.4.7 - giget: 1.2.3 + giget: 1.2.4 jiti: 2.4.2 - mlly: 1.7.3 + mlly: 1.7.4 ohash: 1.1.4 pathe: 1.1.2 perfect-debounce: 1.0.0 - pkg-types: 1.3.0 + pkg-types: 1.3.1 rc9: 2.1.2 optionalDependencies: magicast: 0.3.5 @@ -6463,11 +6973,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.24.4 - caniuse-lite: 1.0.30001692 + caniuse-lite: 1.0.30001697 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001692: {} + caniuse-lite@1.0.30001697: {} chalk@4.1.2: dependencies: @@ -6490,7 +7000,7 @@ snapshots: chokidar@4.0.3: dependencies: - readdirp: 4.0.2 + readdirp: 4.1.1 chownr@2.0.0: {} @@ -6508,7 +7018,7 @@ snapshots: citty@0.1.6: dependencies: - consola: 3.3.3 + consola: 3.4.0 clean-regexp@1.0.0: dependencies: @@ -6578,7 +7088,7 @@ snapshots: confbox@0.1.8: {} - consola@3.3.3: {} + consola@3.4.0: {} content-disposition@0.5.4: dependencies: @@ -6616,7 +7126,7 @@ snapshots: croner@9.0.0: {} - cronstrue@2.52.0: {} + cronstrue@2.54.0: {} cross-spawn@7.0.6: dependencies: @@ -6624,13 +7134,13 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crossws@0.3.1: + crossws@0.3.3: dependencies: uncrypto: 0.1.3 - css-declaration-sorter@7.2.0(postcss@8.4.49): + css-declaration-sorter@7.2.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 css-select@5.1.0: dependencies: @@ -6654,49 +7164,49 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@7.0.6(postcss@8.4.49): + cssnano-preset-default@7.0.6(postcss@8.5.1): dependencies: browserslist: 4.24.4 - css-declaration-sorter: 7.2.0(postcss@8.4.49) - cssnano-utils: 5.0.0(postcss@8.4.49) - postcss: 8.4.49 - postcss-calc: 10.1.0(postcss@8.4.49) - postcss-colormin: 7.0.2(postcss@8.4.49) - postcss-convert-values: 7.0.4(postcss@8.4.49) - postcss-discard-comments: 7.0.3(postcss@8.4.49) - postcss-discard-duplicates: 7.0.1(postcss@8.4.49) - postcss-discard-empty: 7.0.0(postcss@8.4.49) - postcss-discard-overridden: 7.0.0(postcss@8.4.49) - postcss-merge-longhand: 7.0.4(postcss@8.4.49) - postcss-merge-rules: 7.0.4(postcss@8.4.49) - postcss-minify-font-values: 7.0.0(postcss@8.4.49) - postcss-minify-gradients: 7.0.0(postcss@8.4.49) - postcss-minify-params: 7.0.2(postcss@8.4.49) - postcss-minify-selectors: 7.0.4(postcss@8.4.49) - postcss-normalize-charset: 7.0.0(postcss@8.4.49) - postcss-normalize-display-values: 7.0.0(postcss@8.4.49) - postcss-normalize-positions: 7.0.0(postcss@8.4.49) - postcss-normalize-repeat-style: 7.0.0(postcss@8.4.49) - postcss-normalize-string: 7.0.0(postcss@8.4.49) - postcss-normalize-timing-functions: 7.0.0(postcss@8.4.49) - postcss-normalize-unicode: 7.0.2(postcss@8.4.49) - postcss-normalize-url: 7.0.0(postcss@8.4.49) - postcss-normalize-whitespace: 7.0.0(postcss@8.4.49) - postcss-ordered-values: 7.0.1(postcss@8.4.49) - postcss-reduce-initial: 7.0.2(postcss@8.4.49) - postcss-reduce-transforms: 7.0.0(postcss@8.4.49) - postcss-svgo: 7.0.1(postcss@8.4.49) - postcss-unique-selectors: 7.0.3(postcss@8.4.49) - - cssnano-utils@5.0.0(postcss@8.4.49): - dependencies: - postcss: 8.4.49 - - cssnano@7.0.6(postcss@8.4.49): - dependencies: - cssnano-preset-default: 7.0.6(postcss@8.4.49) + css-declaration-sorter: 7.2.0(postcss@8.5.1) + cssnano-utils: 5.0.0(postcss@8.5.1) + postcss: 8.5.1 + postcss-calc: 10.1.1(postcss@8.5.1) + postcss-colormin: 7.0.2(postcss@8.5.1) + postcss-convert-values: 7.0.4(postcss@8.5.1) + postcss-discard-comments: 7.0.3(postcss@8.5.1) + postcss-discard-duplicates: 7.0.1(postcss@8.5.1) + postcss-discard-empty: 7.0.0(postcss@8.5.1) + postcss-discard-overridden: 7.0.0(postcss@8.5.1) + postcss-merge-longhand: 7.0.4(postcss@8.5.1) + postcss-merge-rules: 7.0.4(postcss@8.5.1) + postcss-minify-font-values: 7.0.0(postcss@8.5.1) + postcss-minify-gradients: 7.0.0(postcss@8.5.1) + postcss-minify-params: 7.0.2(postcss@8.5.1) + postcss-minify-selectors: 7.0.4(postcss@8.5.1) + postcss-normalize-charset: 7.0.0(postcss@8.5.1) + postcss-normalize-display-values: 7.0.0(postcss@8.5.1) + postcss-normalize-positions: 7.0.0(postcss@8.5.1) + postcss-normalize-repeat-style: 7.0.0(postcss@8.5.1) + postcss-normalize-string: 7.0.0(postcss@8.5.1) + postcss-normalize-timing-functions: 7.0.0(postcss@8.5.1) + postcss-normalize-unicode: 7.0.2(postcss@8.5.1) + postcss-normalize-url: 7.0.0(postcss@8.5.1) + postcss-normalize-whitespace: 7.0.0(postcss@8.5.1) + postcss-ordered-values: 7.0.1(postcss@8.5.1) + postcss-reduce-initial: 7.0.2(postcss@8.5.1) + postcss-reduce-transforms: 7.0.0(postcss@8.5.1) + postcss-svgo: 7.0.1(postcss@8.5.1) + postcss-unique-selectors: 7.0.3(postcss@8.5.1) + + cssnano-utils@5.0.0(postcss@8.5.1): + dependencies: + postcss: 8.5.1 + + cssnano@7.0.6(postcss@8.5.1): + dependencies: + cssnano-preset-default: 7.0.6(postcss@8.5.1) lilconfig: 3.1.3 - postcss: 8.4.49 + postcss: 8.5.1 csso@5.0.5: dependencies: @@ -6704,7 +7214,12 @@ snapshots: csstype@3.1.3: {} - db0@0.2.1: {} + data-uri-to-buffer@4.0.1: {} + + db0@0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)): + optionalDependencies: + '@libsql/client': 0.14.0 + drizzle-orm: 0.39.1(@libsql/client@0.14.0) de-indent@1.0.2: {} @@ -6757,6 +7272,8 @@ snapshots: detect-libc@1.0.3: {} + detect-libc@2.0.2: {} + detect-libc@2.0.3: {} devalue@5.1.1: {} @@ -6793,10 +7310,23 @@ snapshots: dot-prop@9.0.0: dependencies: - type-fest: 4.32.0 + type-fest: 4.33.0 dotenv@16.4.7: {} + drizzle-kit@0.30.4: + dependencies: + '@drizzle-team/brocli': 0.10.2 + '@esbuild-kit/esm-loader': 2.6.5 + esbuild: 0.19.12 + esbuild-register: 3.6.0(esbuild@0.19.12) + transitivePeerDependencies: + - supports-color + + drizzle-orm@0.39.1(@libsql/client@0.14.0): + optionalDependencies: + '@libsql/client': 0.14.0 + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.1 @@ -6809,7 +7339,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.79: {} + electron-to-chromium@1.5.91: {} emoji-regex@8.0.0: {} @@ -6840,35 +7370,67 @@ snapshots: es-module-lexer@1.6.0: {} - es-object-atoms@1.0.0: + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 - esbuild@0.21.5: + esbuild-register@3.6.0(esbuild@0.19.12): + dependencies: + debug: 4.4.0(supports-color@9.4.0) + esbuild: 0.19.12 + transitivePeerDependencies: + - supports-color + + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + esbuild@0.19.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 esbuild@0.24.2: optionalDependencies: @@ -6916,20 +7478,18 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-flat-gitignore@0.2.0(eslint@9.17.0(jiti@2.4.2)): + eslint-config-flat-gitignore@2.0.0(eslint@9.19.0(jiti@2.4.2)): dependencies: - '@eslint/compat': 1.2.4(eslint@9.17.0(jiti@2.4.2)) - find-up-simple: 1.0.0 - transitivePeerDependencies: - - eslint + '@eslint/compat': 1.2.6(eslint@9.19.0(jiti@2.4.2)) + eslint: 9.19.0(jiti@2.4.2) - eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@2.4.2)): + eslint-config-prettier@10.0.1(eslint@9.19.0(jiti@2.4.2)): dependencies: - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) - eslint-flat-config-utils@1.0.0: + eslint-flat-config-utils@2.0.1: dependencies: - pathe: 2.0.0 + pathe: 2.0.2 eslint-import-resolver-node@0.3.9: dependencies: @@ -6939,66 +7499,66 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-merge-processors@1.0.0(eslint@9.17.0(jiti@2.4.2)): + eslint-merge-processors@1.0.0(eslint@9.19.0(jiti@2.4.2)): dependencies: - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) - eslint-plugin-import-x@4.6.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3): + eslint-plugin-import-x@4.6.1(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3): dependencies: '@types/doctrine': 0.0.9 - '@typescript-eslint/scope-manager': 8.19.1 - '@typescript-eslint/utils': 8.19.1(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3) debug: 4.4.0(supports-color@9.4.0) doctrine: 3.0.0 enhanced-resolve: 5.18.0 - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - get-tsconfig: 4.8.1 + get-tsconfig: 4.10.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.3 + semver: 7.7.1 stable-hash: 0.0.4 tslib: 2.8.1 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-jsdoc@50.6.1(eslint@9.17.0(jiti@2.4.2)): + eslint-plugin-jsdoc@50.6.3(eslint@9.19.0(jiti@2.4.2)): dependencies: '@es-joy/jsdoccomment': 0.49.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 debug: 4.4.0(supports-color@9.4.0) escape-string-regexp: 4.0.0 - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) espree: 10.3.0 esquery: 1.6.0 parse-imports: 2.2.1 - semver: 7.6.3 + semver: 7.7.1 spdx-expression-parse: 4.0.0 synckit: 0.9.2 transitivePeerDependencies: - supports-color - eslint-plugin-regexp@2.7.0(eslint@9.17.0(jiti@2.4.2)): + eslint-plugin-regexp@2.7.0(eslint@9.19.0(jiti@2.4.2)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.1 comment-parser: 1.4.1 - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) jsdoc-type-pratt-parser: 4.1.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-unicorn@56.0.1(eslint@9.17.0(jiti@2.4.2)): + eslint-plugin-unicorn@56.0.1(eslint@9.19.0(jiti@2.4.2)): dependencies: '@babel/helper-validator-identifier': 7.25.9 - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) ci-info: 4.1.0 clean-regexp: 1.0.0 core-js-compat: 3.40.0 - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) esquery: 1.6.0 globals: 15.14.0 indent-string: 4.0.0 @@ -7008,27 +7568,27 @@ snapshots: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.6.3 + semver: 7.7.1 strip-indent: 3.0.0 - eslint-plugin-vue@9.32.0(eslint@9.17.0(jiti@2.4.2)): + eslint-plugin-vue@9.32.0(eslint@9.19.0(jiti@2.4.2)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2)) - eslint: 9.17.0(jiti@2.4.2) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) + eslint: 9.19.0(jiti@2.4.2) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 - semver: 7.6.3 - vue-eslint-parser: 9.4.3(eslint@9.17.0(jiti@2.4.2)) + semver: 7.7.1 + vue-eslint-parser: 9.4.3(eslint@9.19.0(jiti@2.4.2)) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color - eslint-processor-vue-blocks@0.1.2(@vue/compiler-sfc@3.5.13)(eslint@9.17.0(jiti@2.4.2)): + eslint-processor-vue-blocks@1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.2)): dependencies: '@vue/compiler-sfc': 3.5.13 - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) eslint-scope@7.2.2: dependencies: @@ -7044,15 +7604,15 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.17.0(jiti@2.4.2): + eslint@9.19.0(jiti@2.4.2): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.1 - '@eslint/core': 0.9.1 + '@eslint/config-array': 0.19.2 + '@eslint/core': 0.10.0 '@eslint/eslintrc': 3.2.0 - '@eslint/js': 9.17.0 - '@eslint/plugin-kit': 0.2.4 + '@eslint/js': 9.19.0 + '@eslint/plugin-kit': 0.2.5 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.1 @@ -7150,7 +7710,7 @@ snapshots: externality@1.0.2: dependencies: enhanced-resolve: 5.18.0 - mlly: 1.7.3 + mlly: 1.7.4 pathe: 1.1.2 ufo: 1.5.4 @@ -7172,14 +7732,19 @@ snapshots: fast-npm-meta@0.2.2: {} - fastq@1.18.0: + fastq@1.19.0: dependencies: reusify: 1.0.4 - fdir@6.4.2(picomatch@4.0.2): + fdir@6.4.3(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -7190,8 +7755,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - find-up-simple@1.0.0: {} - find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -7214,11 +7777,15 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + fraction.js@4.3.7: {} fresh@0.5.2: {} - fs-extra@11.2.0: + fs-extra@11.3.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 @@ -7244,6 +7811,8 @@ snapshots: function-timeout@0.1.1: {} + fuse.js@7.1.0: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -7253,7 +7822,7 @@ snapshots: call-bind-apply-helpers: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 @@ -7266,25 +7835,25 @@ snapshots: get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 get-stream@6.0.1: {} get-stream@8.0.1: {} - get-tsconfig@4.8.1: + get-tsconfig@4.10.0: dependencies: resolve-pkg-maps: 1.0.0 - giget@1.2.3: + giget@1.2.4: dependencies: citty: 0.1.6 - consola: 3.3.3 + consola: 3.4.0 defu: 6.1.4 - node-fetch-native: 1.6.4 - nypm: 0.3.12 + node-fetch-native: 1.6.6 + nypm: 0.5.2 ohash: 1.1.4 - pathe: 1.1.2 + pathe: 2.0.2 tar: 6.2.1 git-config-path@2.0.0: {} @@ -7357,10 +7926,10 @@ snapshots: dependencies: duplexer: 0.1.2 - h3@1.13.0: + h3@1.14.0: dependencies: cookie-es: 1.2.2 - crossws: 0.3.1 + crossws: 0.3.3 defu: 6.1.4 destr: 2.0.3 iron-webcrypto: 1.2.1 @@ -7427,7 +7996,7 @@ snapshots: transitivePeerDependencies: - supports-color - httpxy@0.1.5: {} + httpxy@0.1.7: {} human-signals@4.3.1: {} @@ -7437,19 +8006,19 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.0: {} + ignore@7.0.3: {} image-meta@0.2.1: {} - import-fresh@3.3.0: + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - impound@0.2.0(rollup@4.30.1): + impound@0.2.0(rollup@4.34.1): dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - mlly: 1.7.3 + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) + mlly: 1.7.4 pathe: 1.1.2 unenv: 1.10.0 unplugin: 1.16.1 @@ -7603,6 +8172,8 @@ snapshots: jiti@2.4.2: {} + js-base64@3.7.7: {} + js-levenshtein@1.1.6: {} js-sha256@0.11.0: {} @@ -7638,7 +8209,7 @@ snapshots: acorn: 8.14.0 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - semver: 7.6.3 + semver: 7.7.1 jsonfile@6.1.0: dependencies: @@ -7726,24 +8297,37 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libsql@0.4.7: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.4.7 + '@libsql/darwin-x64': 0.4.7 + '@libsql/linux-arm64-gnu': 0.4.7 + '@libsql/linux-arm64-musl': 0.4.7 + '@libsql/linux-x64-gnu': 0.4.7 + '@libsql/linux-x64-musl': 0.4.7 + '@libsql/win32-x64-msvc': 0.4.7 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} listhen@1.9.0: dependencies: - '@parcel/watcher': 2.5.0 - '@parcel/watcher-wasm': 2.5.0 + '@parcel/watcher': 2.5.1 + '@parcel/watcher-wasm': 2.5.1 citty: 0.1.6 clipboardy: 4.0.0 - consola: 3.3.3 - crossws: 0.3.1 + consola: 3.4.0 + crossws: 0.3.3 defu: 6.1.4 get-port-please: 3.1.2 - h3: 1.13.0 + h3: 1.14.0 http-shutdown: 1.2.2 jiti: 2.4.2 - mlly: 1.7.3 + mlly: 1.7.4 node-forge: 1.3.1 pathe: 1.1.2 std-env: 3.8.0 @@ -7753,8 +8337,13 @@ snapshots: local-pkg@0.5.1: dependencies: - mlly: 1.7.3 - pkg-types: 1.3.0 + mlly: 1.7.4 + pkg-types: 1.3.1 + + local-pkg@1.0.0: + dependencies: + mlly: 1.7.4 + pkg-types: 1.3.1 locate-path@5.0.0: dependencies: @@ -7786,7 +8375,7 @@ snapshots: dependencies: yallist: 3.1.1 - magic-string-ast@0.6.3: + magic-string-ast@0.7.0: dependencies: magic-string: 0.30.17 @@ -7796,8 +8385,8 @@ snapshots: magicast@0.3.5: dependencies: - '@babel/parser': 7.26.3 - '@babel/types': 7.26.3 + '@babel/parser': 7.26.7 + '@babel/types': 7.26.7 source-map-js: 1.2.1 math-intrinsics@1.1.0: {} @@ -7879,11 +8468,11 @@ snapshots: mkdirp@3.0.1: {} - mlly@1.7.3: + mlly@1.7.4: dependencies: acorn: 8.14.0 - pathe: 1.1.2 - pkg-types: 1.3.0 + pathe: 2.0.2 + pkg-types: 1.3.1 ufo: 1.5.4 mrmime@2.0.0: {} @@ -7904,49 +8493,49 @@ snapshots: nanoid@5.0.9: {} - nanotar@0.1.1: {} + nanotar@0.2.0: {} natural-compare@1.4.0: {} negotiator@0.6.3: {} - nitropack@2.10.4(typescript@5.7.3): + nitropack@2.10.4(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0))(typescript@5.7.3): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 '@netlify/functions': 2.8.2 - '@rollup/plugin-alias': 5.1.1(rollup@4.30.1) - '@rollup/plugin-commonjs': 28.0.2(rollup@4.30.1) - '@rollup/plugin-inject': 5.0.5(rollup@4.30.1) - '@rollup/plugin-json': 6.1.0(rollup@4.30.1) - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.30.1) - '@rollup/plugin-replace': 6.0.2(rollup@4.30.1) - '@rollup/plugin-terser': 0.4.4(rollup@4.30.1) - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/plugin-alias': 5.1.1(rollup@4.34.1) + '@rollup/plugin-commonjs': 28.0.2(rollup@4.34.1) + '@rollup/plugin-inject': 5.0.5(rollup@4.34.1) + '@rollup/plugin-json': 6.1.0(rollup@4.34.1) + '@rollup/plugin-node-resolve': 15.3.1(rollup@4.34.1) + '@rollup/plugin-replace': 6.0.2(rollup@4.34.1) + '@rollup/plugin-terser': 0.4.4(rollup@4.34.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) '@types/http-proxy': 1.17.15 - '@vercel/nft': 0.27.10(rollup@4.30.1) + '@vercel/nft': 0.27.10(rollup@4.34.1) archiver: 7.0.1 c12: 2.0.1(magicast@0.3.5) chokidar: 3.6.0 citty: 0.1.6 compatx: 0.1.8 confbox: 0.1.8 - consola: 3.3.3 + consola: 3.4.0 cookie-es: 1.2.2 croner: 9.0.0 - crossws: 0.3.1 - db0: 0.2.1 + crossws: 0.3.3 + db0: 0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)) defu: 6.1.4 destr: 2.0.3 dot-prop: 9.0.0 esbuild: 0.24.2 escape-string-regexp: 5.0.0 etag: 1.8.1 - fs-extra: 11.2.0 + fs-extra: 11.3.0 globby: 14.0.2 gzip-size: 7.0.0 - h3: 1.13.0 + h3: 1.14.0 hookable: 5.5.3 - httpxy: 0.1.5 + httpxy: 0.1.7 ioredis: 5.4.2 jiti: 2.4.2 klona: 2.0.6 @@ -7955,20 +8544,20 @@ snapshots: magic-string: 0.30.17 magicast: 0.3.5 mime: 4.0.6 - mlly: 1.7.3 - node-fetch-native: 1.6.4 + mlly: 1.7.4 + node-fetch-native: 1.6.6 ofetch: 1.4.1 ohash: 1.1.4 - openapi-typescript: 7.5.2(typescript@5.7.3) + openapi-typescript: 7.6.1(typescript@5.7.3) pathe: 1.1.2 perfect-debounce: 1.0.0 - pkg-types: 1.3.0 + pkg-types: 1.3.1 pretty-bytes: 6.1.1 radix3: 1.1.2 - rollup: 4.30.1 - rollup-plugin-visualizer: 5.14.0(rollup@4.30.1) + rollup: 4.34.1 + rollup-plugin-visualizer: 5.14.0(rollup@4.34.1) scule: 1.3.0 - semver: 7.6.3 + semver: 7.7.1 serve-placeholder: 2.0.2 serve-static: 1.16.2 std-env: 3.8.0 @@ -7976,8 +8565,8 @@ snapshots: uncrypto: 0.1.3 unctx: 2.4.1 unenv: 1.10.0 - unimport: 3.14.5(rollup@4.30.1) - unstorage: 1.14.4(db0@0.2.1)(ioredis@5.4.2) + unimport: 3.14.6(rollup@4.34.1) + unstorage: 1.14.4(db0@0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)))(ioredis@5.4.2) untyped: 1.5.2 unwasm: 0.3.9 transitivePeerDependencies: @@ -8003,6 +8592,7 @@ snapshots: - idb-keyval - mysql2 - rolldown + - sqlite3 - supports-color - typescript - uploadthing @@ -8011,21 +8601,29 @@ snapshots: node-addon-api@8.3.0: {} - node-fetch-native@1.6.4: {} + node-domexception@1.0.0: {} + + node-fetch-native@1.6.6: {} node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-forge@1.3.1: {} node-gyp-build@4.8.4: {} node-releases@2.0.19: {} - nopt@8.0.0: + nopt@8.1.0: dependencies: - abbrev: 2.0.0 + abbrev: 3.0.0 normalize-package-data@2.5.0: dependencies: @@ -8050,26 +8648,25 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxi@3.19.1: {} - - nuxt@3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(db0@0.2.1)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0): + nuxt@3.15.4(@libsql/client@0.14.0)(@parcel/watcher@2.5.1)(@types/node@22.13.1)(db0@0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)))(drizzle-orm@0.39.1(@libsql/client@0.14.0))(eslint@9.19.0(jiti@2.4.2))(ioredis@5.4.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3))(yaml@2.7.0): dependencies: + '@nuxt/cli': 3.21.1(magicast@0.3.5) '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 1.7.0(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) - '@nuxt/schema': 3.15.1 - '@nuxt/telemetry': 2.6.4(magicast@0.3.5)(rollup@4.30.1) - '@nuxt/vite-builder': 3.15.1(@types/node@22.10.5)(eslint@9.17.0(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.1)(terser@5.37.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0) - '@unhead/dom': 1.11.15 - '@unhead/shared': 1.11.15 - '@unhead/ssr': 1.11.15 - '@unhead/vue': 1.11.15(vue@3.5.13(typescript@5.7.3)) + '@nuxt/devtools': 1.7.0(rollup@4.34.1)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) + '@nuxt/schema': 3.15.4 + '@nuxt/telemetry': 2.6.4(magicast@0.3.5)(rollup@4.34.1) + '@nuxt/vite-builder': 3.15.4(@types/node@22.13.1)(eslint@9.19.0(jiti@2.4.2))(magicast@0.3.5)(optionator@0.9.4)(rollup@4.34.1)(terser@5.37.0)(typescript@5.7.3)(vue-tsc@2.2.0(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3))(yaml@2.7.0) + '@unhead/dom': 1.11.18 + '@unhead/shared': 1.11.18 + '@unhead/ssr': 1.11.18 + '@unhead/vue': 1.11.18(vue@3.5.13(typescript@5.7.3)) '@vue/shared': 3.5.13 acorn: 8.14.0 c12: 2.0.1(magicast@0.3.5) chokidar: 4.0.3 compatx: 0.1.8 - consola: 3.3.3 + consola: 3.4.0 cookie-es: 1.2.2 defu: 6.1.4 destr: 2.0.3 @@ -8079,48 +8676,47 @@ snapshots: escape-string-regexp: 5.0.0 estree-walker: 3.0.3 globby: 14.0.2 - h3: 1.13.0 + h3: 1.14.0 hookable: 5.5.3 - ignore: 7.0.0 - impound: 0.2.0(rollup@4.30.1) + ignore: 7.0.3 + impound: 0.2.0(rollup@4.34.1) jiti: 2.4.2 klona: 2.0.6 knitwork: 1.2.0 magic-string: 0.30.17 - mlly: 1.7.3 - nanotar: 0.1.1 - nitropack: 2.10.4(typescript@5.7.3) - nuxi: 3.19.1 - nypm: 0.4.1 + mlly: 1.7.4 + nanotar: 0.2.0 + nitropack: 2.10.4(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0))(typescript@5.7.3) + nypm: 0.5.2 ofetch: 1.4.1 ohash: 1.1.4 - pathe: 2.0.0 + pathe: 2.0.2 perfect-debounce: 1.0.0 - pkg-types: 1.3.0 + pkg-types: 1.3.1 radix3: 1.1.2 scule: 1.3.0 - semver: 7.6.3 + semver: 7.7.1 std-env: 3.8.0 - strip-literal: 2.1.1 + strip-literal: 3.0.0 tinyglobby: 0.2.10 ufo: 1.5.4 ultrahtml: 1.5.3 uncrypto: 0.1.3 unctx: 2.4.1 unenv: 1.10.0 - unhead: 1.11.15 - unimport: 3.14.5(rollup@4.30.1) + unhead: 1.11.18 + unimport: 4.0.0(rollup@4.34.1) unplugin: 2.1.2 - unplugin-vue-router: 0.10.9(rollup@4.30.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) - unstorage: 1.14.4(db0@0.2.1)(ioredis@5.4.2) + unplugin-vue-router: 0.11.2(rollup@4.34.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) + unstorage: 1.14.4(db0@0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)))(ioredis@5.4.2) untyped: 1.5.2 vue: 3.5.13(typescript@5.7.3) vue-bundle-renderer: 2.1.1 vue-devtools-stub: 0.1.0 vue-router: 4.5.0(vue@3.5.13(typescript@5.7.3)) optionalDependencies: - '@parcel/watcher': 2.5.0 - '@types/node': 22.10.5 + '@parcel/watcher': 2.5.1 + '@types/node': 22.13.1 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -8157,6 +8753,7 @@ snapshots: - rollup - sass - sass-embedded + - sqlite3 - stylelint - stylus - sugarss @@ -8173,21 +8770,21 @@ snapshots: - xml2js - yaml - nypm@0.3.12: + nypm@0.4.1: dependencies: citty: 0.1.6 - consola: 3.3.3 - execa: 8.0.1 + consola: 3.4.0 pathe: 1.1.2 - pkg-types: 1.3.0 + pkg-types: 1.3.1 + tinyexec: 0.3.2 ufo: 1.5.4 - nypm@0.4.1: + nypm@0.5.2: dependencies: citty: 0.1.6 - consola: 3.3.3 - pathe: 1.1.2 - pkg-types: 1.3.0 + consola: 3.4.0 + pathe: 2.0.2 + pkg-types: 1.3.1 tinyexec: 0.3.2 ufo: 1.5.4 @@ -8198,7 +8795,7 @@ snapshots: ofetch@1.4.1: dependencies: destr: 2.0.3 - node-fetch-native: 1.6.4 + node-fetch-native: 1.6.6 ufo: 1.5.4 ohash@1.1.4: {} @@ -8235,17 +8832,15 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-typescript@7.5.2(typescript@5.7.3): + openapi-typescript@7.6.1(typescript@5.7.3): dependencies: - '@redocly/openapi-core': 1.27.1(supports-color@9.4.0) + '@redocly/openapi-core': 1.28.1(supports-color@9.4.0) ansi-colors: 4.1.3 change-case: 5.4.4 parse-json: 8.1.0 supports-color: 9.4.0 typescript: 5.7.3 yargs-parser: 21.1.1 - transitivePeerDependencies: - - encoding optionator@0.9.4: dependencies: @@ -8276,7 +8871,7 @@ snapshots: package-json-from-dist@1.0.1: {} - package-manager-detector@0.2.8: {} + package-manager-detector@0.2.9: {} packrup@0.1.2: {} @@ -8305,7 +8900,7 @@ snapshots: dependencies: '@babel/code-frame': 7.26.2 index-to-position: 0.1.2 - type-fest: 4.32.0 + type-fest: 4.33.0 parse-path@7.0.0: dependencies: @@ -8341,7 +8936,7 @@ snapshots: pathe@1.1.2: {} - pathe@2.0.0: {} + pathe@2.0.2: {} perfect-debounce@1.0.0: {} @@ -8353,7 +8948,7 @@ snapshots: pify@2.3.0: {} - pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)): + pinia@2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)): dependencies: '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.7.3) @@ -8365,11 +8960,11 @@ snapshots: pirates@4.0.6: {} - pkg-types@1.3.0: + pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.7.3 - pathe: 1.1.2 + mlly: 1.7.4 + pathe: 2.0.2 pluralize@8.0.0: {} @@ -8383,173 +8978,173 @@ snapshots: transitivePeerDependencies: - supports-color - postcss-calc@10.1.0(postcss@8.4.49): + postcss-calc@10.1.1(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 7.0.0 postcss-value-parser: 4.2.0 - postcss-colormin@7.0.2(postcss@8.4.49): + postcss-colormin@7.0.2(postcss@8.5.1): dependencies: browserslist: 4.24.4 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-convert-values@7.0.4(postcss@8.4.49): + postcss-convert-values@7.0.4(postcss@8.5.1): dependencies: browserslist: 4.24.4 - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-discard-comments@7.0.3(postcss@8.4.49): + postcss-discard-comments@7.0.3(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 6.1.2 - postcss-discard-duplicates@7.0.1(postcss@8.4.49): + postcss-discard-duplicates@7.0.1(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 - postcss-discard-empty@7.0.0(postcss@8.4.49): + postcss-discard-empty@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 - postcss-discard-overridden@7.0.0(postcss@8.4.49): + postcss-discard-overridden@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 - postcss-import@15.1.0(postcss@8.4.49): + postcss-import@15.1.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.10 - postcss-js@4.0.1(postcss@8.4.49): + postcss-js@4.0.1(postcss@8.5.1): dependencies: camelcase-css: 2.0.1 - postcss: 8.4.49 + postcss: 8.5.1 - postcss-load-config@4.0.2(postcss@8.4.49): + postcss-load-config@4.0.2(postcss@8.5.1): dependencies: lilconfig: 3.1.3 yaml: 2.7.0 optionalDependencies: - postcss: 8.4.49 + postcss: 8.5.1 - postcss-merge-longhand@7.0.4(postcss@8.4.49): + postcss-merge-longhand@7.0.4(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - stylehacks: 7.0.4(postcss@8.4.49) + stylehacks: 7.0.4(postcss@8.5.1) - postcss-merge-rules@7.0.4(postcss@8.4.49): + postcss-merge-rules@7.0.4(postcss@8.5.1): dependencies: browserslist: 4.24.4 caniuse-api: 3.0.0 - cssnano-utils: 5.0.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 5.0.0(postcss@8.5.1) + postcss: 8.5.1 postcss-selector-parser: 6.1.2 - postcss-minify-font-values@7.0.0(postcss@8.4.49): + postcss-minify-font-values@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-minify-gradients@7.0.0(postcss@8.4.49): + postcss-minify-gradients@7.0.0(postcss@8.5.1): dependencies: colord: 2.9.3 - cssnano-utils: 5.0.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 5.0.0(postcss@8.5.1) + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-minify-params@7.0.2(postcss@8.4.49): + postcss-minify-params@7.0.2(postcss@8.5.1): dependencies: browserslist: 4.24.4 - cssnano-utils: 5.0.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 5.0.0(postcss@8.5.1) + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-minify-selectors@7.0.4(postcss@8.4.49): + postcss-minify-selectors@7.0.4(postcss@8.5.1): dependencies: cssesc: 3.0.0 - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 6.1.2 - postcss-nested@6.2.0(postcss@8.4.49): + postcss-nested@6.2.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 6.1.2 - postcss-nesting@13.0.1(postcss@8.4.49): + postcss-nesting@13.0.1(postcss@8.5.1): dependencies: '@csstools/selector-resolve-nested': 3.0.0(postcss-selector-parser@7.0.0) '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.0.0) - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 7.0.0 - postcss-normalize-charset@7.0.0(postcss@8.4.49): + postcss-normalize-charset@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 - postcss-normalize-display-values@7.0.0(postcss@8.4.49): + postcss-normalize-display-values@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-positions@7.0.0(postcss@8.4.49): + postcss-normalize-positions@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@7.0.0(postcss@8.4.49): + postcss-normalize-repeat-style@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-string@7.0.0(postcss@8.4.49): + postcss-normalize-string@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@7.0.0(postcss@8.4.49): + postcss-normalize-timing-functions@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@7.0.2(postcss@8.4.49): + postcss-normalize-unicode@7.0.2(postcss@8.5.1): dependencies: browserslist: 4.24.4 - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-url@7.0.0(postcss@8.4.49): + postcss-normalize-url@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@7.0.0(postcss@8.4.49): + postcss-normalize-whitespace@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-ordered-values@7.0.1(postcss@8.4.49): + postcss-ordered-values@7.0.1(postcss@8.5.1): dependencies: - cssnano-utils: 5.0.0(postcss@8.4.49) - postcss: 8.4.49 + cssnano-utils: 5.0.0(postcss@8.5.1) + postcss: 8.5.1 postcss-value-parser: 4.2.0 - postcss-reduce-initial@7.0.2(postcss@8.4.49): + postcss-reduce-initial@7.0.2(postcss@8.5.1): dependencies: browserslist: 4.24.4 caniuse-api: 3.0.0 - postcss: 8.4.49 + postcss: 8.5.1 - postcss-reduce-transforms@7.0.0(postcss@8.4.49): + postcss-reduce-transforms@7.0.0(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 postcss-selector-parser@6.1.2: @@ -8562,20 +9157,20 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@7.0.1(postcss@8.4.49): + postcss-svgo@7.0.1(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-value-parser: 4.2.0 svgo: 3.3.2 - postcss-unique-selectors@7.0.3(postcss@8.4.49): + postcss-unique-selectors@7.0.3(postcss@8.5.1): dependencies: - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 6.1.2 postcss-value-parser@4.2.0: {} - postcss@8.4.49: + postcss@8.5.1: dependencies: nanoid: 3.3.8 picocolors: 1.1.1 @@ -8583,7 +9178,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.6.9(prettier@3.4.2): + prettier-plugin-tailwindcss@0.6.11(prettier@3.4.2): dependencies: prettier: 3.4.2 @@ -8595,6 +9190,8 @@ snapshots: process@0.11.10: {} + promise-limit@2.7.0: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -8612,15 +9209,13 @@ snapshots: queue-microtask@1.2.3: {} - queue-tick@1.0.1: {} - - radix-vue@1.9.12(vue@3.5.13(typescript@5.7.3)): + radix-vue@1.9.13(vue@3.5.13(typescript@5.7.3)): dependencies: '@floating-ui/dom': 1.6.13 '@floating-ui/vue': 1.1.6(vue@3.5.13(typescript@5.7.3)) - '@internationalized/date': 3.6.0 + '@internationalized/date': 3.7.0 '@internationalized/number': 3.6.0 - '@tanstack/vue-virtual': 3.11.2(vue@3.5.13(typescript@5.7.3)) + '@tanstack/vue-virtual': 3.12.0(vue@3.5.13(typescript@5.7.3)) '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.7.3)) '@vueuse/shared': 10.11.1(vue@3.5.13(typescript@5.7.3)) aria-hidden: 1.2.4 @@ -8687,7 +9282,7 @@ snapshots: dependencies: picomatch: 2.3.1 - readdirp@4.0.2: {} + readdirp@4.1.1: {} redis-errors@1.2.0: {} @@ -8747,38 +9342,38 @@ snapshots: dependencies: glob: 10.4.5 - rollup-plugin-visualizer@5.14.0(rollup@4.30.1): + rollup-plugin-visualizer@5.14.0(rollup@4.34.1): dependencies: open: 8.4.2 picomatch: 4.0.2 source-map: 0.7.4 yargs: 17.7.2 optionalDependencies: - rollup: 4.30.1 + rollup: 4.34.1 - rollup@4.30.1: + rollup@4.34.1: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.30.1 - '@rollup/rollup-android-arm64': 4.30.1 - '@rollup/rollup-darwin-arm64': 4.30.1 - '@rollup/rollup-darwin-x64': 4.30.1 - '@rollup/rollup-freebsd-arm64': 4.30.1 - '@rollup/rollup-freebsd-x64': 4.30.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.30.1 - '@rollup/rollup-linux-arm-musleabihf': 4.30.1 - '@rollup/rollup-linux-arm64-gnu': 4.30.1 - '@rollup/rollup-linux-arm64-musl': 4.30.1 - '@rollup/rollup-linux-loongarch64-gnu': 4.30.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.30.1 - '@rollup/rollup-linux-riscv64-gnu': 4.30.1 - '@rollup/rollup-linux-s390x-gnu': 4.30.1 - '@rollup/rollup-linux-x64-gnu': 4.30.1 - '@rollup/rollup-linux-x64-musl': 4.30.1 - '@rollup/rollup-win32-arm64-msvc': 4.30.1 - '@rollup/rollup-win32-ia32-msvc': 4.30.1 - '@rollup/rollup-win32-x64-msvc': 4.30.1 + '@rollup/rollup-android-arm-eabi': 4.34.1 + '@rollup/rollup-android-arm64': 4.34.1 + '@rollup/rollup-darwin-arm64': 4.34.1 + '@rollup/rollup-darwin-x64': 4.34.1 + '@rollup/rollup-freebsd-arm64': 4.34.1 + '@rollup/rollup-freebsd-x64': 4.34.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.34.1 + '@rollup/rollup-linux-arm-musleabihf': 4.34.1 + '@rollup/rollup-linux-arm64-gnu': 4.34.1 + '@rollup/rollup-linux-arm64-musl': 4.34.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.34.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.34.1 + '@rollup/rollup-linux-riscv64-gnu': 4.34.1 + '@rollup/rollup-linux-s390x-gnu': 4.34.1 + '@rollup/rollup-linux-x64-gnu': 4.34.1 + '@rollup/rollup-linux-x64-musl': 4.34.1 + '@rollup/rollup-win32-arm64-msvc': 4.34.1 + '@rollup/rollup-win32-ia32-msvc': 4.34.1 + '@rollup/rollup-win32-x64-msvc': 4.34.1 fsevents: 2.3.3 run-applescript@7.0.0: {} @@ -8809,7 +9404,7 @@ snapshots: semver@6.3.1: {} - semver@7.6.3: {} + semver@7.7.1: {} send@0.19.0: dependencies: @@ -8900,21 +9495,21 @@ snapshots: spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.21 spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.21 spdx-expression-parse@4.0.0: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 + spdx-license-ids: 3.0.21 - spdx-license-ids@3.0.20: {} + spdx-license-ids@3.0.21: {} speakingurl@14.0.1: {} @@ -8930,13 +9525,12 @@ snapshots: steno@4.0.2: {} - streamx@2.21.1: + streamx@2.22.0: dependencies: fast-fifo: 1.3.2 - queue-tick: 1.0.1 text-decoder: 1.2.3 optionalDependencies: - bare-events: 2.5.3 + bare-events: 2.5.4 string-width@4.2.3: dependencies: @@ -8978,10 +9572,14 @@ snapshots: dependencies: js-tokens: 9.0.1 - stylehacks@7.0.4(postcss@8.4.49): + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + + stylehacks@7.0.4(postcss@8.5.1): dependencies: browserslist: 4.24.4 - postcss: 8.4.49 + postcss: 8.5.1 postcss-selector-parser: 6.1.2 sucrase@3.35.0: @@ -9061,11 +9659,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.4.49 - postcss-import: 15.1.0(postcss@8.4.49) - postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49) - postcss-nested: 6.2.0(postcss@8.4.49) + postcss: 8.5.1 + postcss-import: 15.1.0(postcss@8.5.1) + postcss-js: 4.0.1(postcss@8.5.1) + postcss-load-config: 4.0.2(postcss@8.5.1) + postcss-nested: 6.2.0(postcss@8.5.1) postcss-selector-parser: 6.1.2 resolve: 1.22.10 sucrase: 3.35.0 @@ -9078,7 +9676,7 @@ snapshots: dependencies: b4a: 1.6.7 fast-fifo: 1.3.2 - streamx: 2.21.1 + streamx: 2.22.0 tar@6.2.1: dependencies: @@ -9129,7 +9727,7 @@ snapshots: tinyglobby@0.2.10: dependencies: - fdir: 6.4.2(picomatch@4.0.2) + fdir: 6.4.3(picomatch@4.0.2) picomatch: 4.0.2 to-regex-range@5.0.1: @@ -9144,7 +9742,7 @@ snapshots: tr46@0.0.3: {} - ts-api-utils@2.0.0(typescript@5.7.3): + ts-api-utils@2.0.1(typescript@5.7.3): dependencies: typescript: 5.7.3 @@ -9166,7 +9764,7 @@ snapshots: type-fest@0.8.1: {} - type-fest@4.32.0: {} + type-fest@4.33.0: {} type-is@1.6.18: dependencies: @@ -9192,54 +9790,73 @@ snapshots: unenv@1.10.0: dependencies: - consola: 3.3.3 + consola: 3.4.0 defu: 6.1.4 mime: 3.0.0 - node-fetch-native: 1.6.4 + node-fetch-native: 1.6.6 pathe: 1.1.2 - unhead@1.11.15: + unhead@1.11.18: dependencies: - '@unhead/dom': 1.11.15 - '@unhead/schema': 1.11.15 - '@unhead/shared': 1.11.15 + '@unhead/dom': 1.11.18 + '@unhead/schema': 1.11.18 + '@unhead/shared': 1.11.18 hookable: 5.5.3 unicorn-magic@0.1.0: {} - unimport@3.14.5(rollup@4.30.1): + unimport@3.14.6(rollup@4.34.1): dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) acorn: 8.14.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 fast-glob: 3.3.3 - local-pkg: 0.5.1 + local-pkg: 1.0.0 magic-string: 0.30.17 - mlly: 1.7.3 - pathe: 1.1.2 + mlly: 1.7.4 + pathe: 2.0.2 picomatch: 4.0.2 - pkg-types: 1.3.0 + pkg-types: 1.3.1 scule: 1.3.0 strip-literal: 2.1.1 unplugin: 1.16.1 transitivePeerDependencies: - rollup + unimport@4.0.0(rollup@4.34.1): + dependencies: + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) + acorn: 8.14.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + fast-glob: 3.3.3 + local-pkg: 1.0.0 + magic-string: 0.30.17 + mlly: 1.7.4 + pathe: 2.0.2 + picomatch: 4.0.2 + pkg-types: 1.3.1 + scule: 1.3.0 + strip-literal: 3.0.0 + unplugin: 2.1.2 + transitivePeerDependencies: + - rollup + universalify@2.0.1: {} - unplugin-vue-router@0.10.9(rollup@4.30.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)): + unplugin-vue-router@0.10.9(rollup@4.34.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)): dependencies: - '@babel/types': 7.26.3 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) - '@vue-macros/common': 1.15.1(rollup@4.30.1)(vue@3.5.13(typescript@5.7.3)) + '@babel/types': 7.26.7 + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) + '@vue-macros/common': 1.16.1(vue@3.5.13(typescript@5.7.3)) ast-walker-scope: 0.6.2 chokidar: 3.6.0 fast-glob: 3.3.3 json5: 2.2.3 local-pkg: 0.5.1 magic-string: 0.30.17 - mlly: 1.7.3 + mlly: 1.7.4 pathe: 1.1.2 scule: 1.3.0 unplugin: 2.0.0-beta.1 @@ -9250,6 +9867,28 @@ snapshots: - rollup - vue + unplugin-vue-router@0.11.2(rollup@4.34.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@babel/types': 7.26.7 + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) + '@vue-macros/common': 1.16.1(vue@3.5.13(typescript@5.7.3)) + ast-walker-scope: 0.6.2 + chokidar: 3.6.0 + fast-glob: 3.3.3 + json5: 2.2.3 + local-pkg: 1.0.0 + magic-string: 0.30.17 + mlly: 1.7.4 + pathe: 2.0.2 + scule: 1.3.0 + unplugin: 2.1.2 + yaml: 2.7.0 + optionalDependencies: + vue-router: 4.5.0(vue@3.5.13(typescript@5.7.3)) + transitivePeerDependencies: + - rollup + - vue + unplugin@1.16.1: dependencies: acorn: 8.14.0 @@ -9265,31 +9904,31 @@ snapshots: acorn: 8.14.0 webpack-virtual-modules: 0.6.2 - unstorage@1.14.4(db0@0.2.1)(ioredis@5.4.2): + unstorage@1.14.4(db0@0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)))(ioredis@5.4.2): dependencies: anymatch: 3.1.3 chokidar: 3.6.0 destr: 2.0.3 - h3: 1.13.0 + h3: 1.14.0 lru-cache: 10.4.3 - node-fetch-native: 1.6.4 + node-fetch-native: 1.6.6 ofetch: 1.4.1 ufo: 1.5.4 optionalDependencies: - db0: 0.2.1 + db0: 0.2.3(@libsql/client@0.14.0)(drizzle-orm@0.39.1(@libsql/client@0.14.0)) ioredis: 5.4.2 untun@0.1.3: dependencies: citty: 0.1.6 - consola: 3.3.3 + consola: 3.4.0 pathe: 1.1.2 untyped@1.5.2: dependencies: - '@babel/core': 7.26.0 - '@babel/standalone': 7.26.4 - '@babel/types': 7.26.3 + '@babel/core': 7.26.7 + '@babel/standalone': 7.26.7 + '@babel/types': 7.26.7 citty: 0.1.6 defu: 6.1.4 jiti: 2.4.2 @@ -9302,9 +9941,9 @@ snapshots: dependencies: knitwork: 1.2.0 magic-string: 0.30.17 - mlly: 1.7.3 + mlly: 1.7.4 pathe: 1.1.2 - pkg-types: 1.3.0 + pkg-types: 1.3.1 unplugin: 1.16.1 update-browserslist-db@1.1.2(browserslist@4.24.4): @@ -9332,19 +9971,20 @@ snapshots: vary@1.1.2: {} - vite-hot-client@0.2.4(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): + vite-hot-client@0.2.4(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): dependencies: - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) - vite-node@2.1.8(@types/node@22.10.5)(terser@5.37.0): + vite-node@3.0.5(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0): dependencies: cac: 6.7.14 debug: 4.4.0(supports-color@9.4.0) es-module-lexer: 1.6.0 - pathe: 1.1.2 - vite: 5.4.11(@types/node@22.10.5)(terser@5.37.0) + pathe: 2.0.2 + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' + - jiti - less - lightningcss - sass @@ -9353,8 +9993,10 @@ snapshots: - sugarss - supports-color - terser + - tsx + - yaml - vite-plugin-checker@0.8.0(eslint@9.17.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)): + vite-plugin-checker@0.8.0(eslint@9.19.0(jiti@2.4.2))(optionator@0.9.4)(typescript@5.7.3)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0))(vue-tsc@2.2.0(typescript@5.7.3)): dependencies: '@babel/code-frame': 7.26.2 ansi-escapes: 4.3.2 @@ -9362,71 +10004,61 @@ snapshots: chokidar: 3.6.0 commander: 8.3.0 fast-glob: 3.3.3 - fs-extra: 11.2.0 + fs-extra: 11.3.0 npm-run-path: 4.0.1 strip-ansi: 6.0.1 tiny-invariant: 1.3.3 - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) vscode-languageclient: 7.0.0 vscode-languageserver: 7.0.0 vscode-languageserver-textdocument: 1.0.12 vscode-uri: 3.0.8 optionalDependencies: - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) optionator: 0.9.4 typescript: 5.7.3 vue-tsc: 2.2.0(typescript@5.7.3) - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.1(magicast@0.3.5)(rollup@4.30.1))(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): + vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.34.1))(rollup@4.34.1)(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.30.1) + '@rollup/pluginutils': 5.1.4(rollup@4.34.1) debug: 4.4.0(supports-color@9.4.0) error-stack-parser-es: 0.1.5 - fs-extra: 11.2.0 + fs-extra: 11.3.0 open: 10.1.0 perfect-debounce: 1.0.0 picocolors: 1.1.1 sirv: 3.0.0 - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) optionalDependencies: - '@nuxt/kit': 3.15.1(magicast@0.3.5)(rollup@4.30.1) + '@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.1) transitivePeerDependencies: - rollup - supports-color - vite-plugin-vue-inspector@5.3.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): + vite-plugin-vue-inspector@5.3.1(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0)): dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.26.3(@babel/core@7.26.0) - '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.0) + '@babel/core': 7.26.7 + '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.7) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.7) + '@babel/plugin-transform-typescript': 7.26.7(@babel/core@7.26.7) + '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.7) '@vue/compiler-dom': 3.5.13 kolorist: 1.8.0 magic-string: 0.30.17 - vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) + vite: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0) transitivePeerDependencies: - supports-color - vite@5.4.11(@types/node@22.10.5)(terser@5.37.0): - dependencies: - esbuild: 0.21.5 - postcss: 8.4.49 - rollup: 4.30.1 - optionalDependencies: - '@types/node': 22.10.5 - fsevents: 2.3.3 - terser: 5.37.0 - - vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0): + vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(terser@5.37.0)(yaml@2.7.0): dependencies: esbuild: 0.24.2 - postcss: 8.4.49 - rollup: 4.30.1 + postcss: 8.5.1 + rollup: 4.34.1 optionalDependencies: - '@types/node': 22.10.5 + '@types/node': 22.13.1 fsevents: 2.3.3 jiti: 2.4.2 terser: 5.37.0 @@ -9437,7 +10069,7 @@ snapshots: vscode-languageclient@7.0.0: dependencies: minimatch: 3.1.2 - semver: 7.6.3 + semver: 7.7.1 vscode-languageserver-protocol: 3.16.0 vscode-languageserver-protocol@3.16.0: @@ -9465,16 +10097,16 @@ snapshots: vue-devtools-stub@0.1.0: {} - vue-eslint-parser@9.4.3(eslint@9.17.0(jiti@2.4.2)): + vue-eslint-parser@9.4.3(eslint@9.19.0(jiti@2.4.2)): dependencies: debug: 4.4.0(supports-color@9.4.0) - eslint: 9.17.0(jiti@2.4.2) + eslint: 9.19.0(jiti@2.4.2) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.6.0 lodash: 4.17.21 - semver: 7.6.3 + semver: 7.7.1 transitivePeerDependencies: - supports-color @@ -9496,9 +10128,9 @@ snapshots: '@vue/language-core': 2.2.0(typescript@5.7.3) typescript: 5.7.3 - vue3-apexcharts@1.8.0(apexcharts@4.3.0)(vue@3.5.13(typescript@5.7.3)): + vue3-apexcharts@1.8.0(apexcharts@4.4.0)(vue@3.5.13(typescript@5.7.3)): dependencies: - apexcharts: 4.3.0 + apexcharts: 4.4.0 vue: 3.5.13(typescript@5.7.3) vue@3.5.13(typescript@5.7.3): @@ -9511,6 +10143,8 @@ snapshots: optionalDependencies: typescript: 5.7.3 + web-streams-polyfill@3.3.3: {} + webidl-conversions@3.0.1: {} webpack-virtual-modules@0.6.2: {} diff --git a/src/server/api/admin/general.get.ts b/src/server/api/admin/general.get.ts index 47037145..d27f39f9 100644 --- a/src/server/api/admin/general.get.ts +++ b/src/server/api/admin/general.get.ts @@ -1,4 +1,6 @@ -export default defineEventHandler(async () => { - const system = await Database.system.get(); - return system.general; +export default definePermissionEventHandler(actions.ADMIN, async () => { + const sessionConfig = await Database.general.getSessionConfig(); + return { + sessionTimeout: sessionConfig.sessionTimeout, + }; }); diff --git a/src/server/api/admin/general.post.ts b/src/server/api/admin/general.post.ts index 738c1c41..4a28cf29 100644 --- a/src/server/api/admin/general.post.ts +++ b/src/server/api/admin/general.post.ts @@ -1,8 +1,13 @@ -export default defineEventHandler(async (event) => { - const data = await readValidatedBody( - event, - validateZod(generalUpdateType, event) - ); - await Database.system.updateGeneral(data); - return { success: true }; -}); +import { GeneralUpdateSchema } from '#db/repositories/general/types'; + +export default definePermissionEventHandler( + actions.ADMIN, + async ({ event }) => { + const data = await readValidatedBody( + event, + validateZod(GeneralUpdateSchema, event) + ); + await Database.general.update(data); + return { success: true }; + } +); diff --git a/src/server/api/admin/hooks.get.ts b/src/server/api/admin/hooks.get.ts index 1ff81337..470ba3c2 100644 --- a/src/server/api/admin/hooks.get.ts +++ b/src/server/api/admin/hooks.get.ts @@ -1,4 +1,7 @@ -export default defineEventHandler(async () => { - const system = await Database.system.get(); - return system.hooks; +export default definePermissionEventHandler(actions.ADMIN, async () => { + const hooks = await Database.hooks.get('wg0'); + if (!hooks) { + throw new Error('Hooks not found'); + } + return hooks; }); diff --git a/src/server/api/admin/hooks.post.ts b/src/server/api/admin/hooks.post.ts index 7a0702fd..1a291438 100644 --- a/src/server/api/admin/hooks.post.ts +++ b/src/server/api/admin/hooks.post.ts @@ -1,9 +1,14 @@ -export default defineEventHandler(async (event) => { - const data = await readValidatedBody( - event, - validateZod(hooksUpdateType, event) - ); - await Database.system.updateHooks(data); - await WireGuard.saveConfig(); - return { success: true }; -}); +import { HooksUpdateSchema } from '#db/repositories/hooks/types'; + +export default definePermissionEventHandler( + actions.ADMIN, + async ({ event }) => { + const data = await readValidatedBody( + event, + validateZod(HooksUpdateSchema, event) + ); + await Database.hooks.update('wg0', data); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/admin/hostport.post.ts b/src/server/api/admin/hostport.post.ts deleted file mode 100644 index ab347ad6..00000000 --- a/src/server/api/admin/hostport.post.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default defineEventHandler(async (event) => { - const { host, port } = await readValidatedBody( - event, - validateZod(hostPortType, event) - ); - await Database.system.updateClientsHostPort(host, port); - return { success: true }; -}); diff --git a/src/server/api/admin/interface.get.ts b/src/server/api/admin/interface.get.ts deleted file mode 100644 index 0f7a3f09..00000000 --- a/src/server/api/admin/interface.get.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default defineEventHandler(async () => { - const system = await Database.system.get(); - return system.interface; -}); diff --git a/src/server/api/admin/interface.post.ts b/src/server/api/admin/interface.post.ts deleted file mode 100644 index 92986561..00000000 --- a/src/server/api/admin/interface.post.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default defineEventHandler(async (event) => { - const data = await readValidatedBody( - event, - validateZod(interfaceUpdateType, event) - ); - await Database.system.updateInterface(data); - await WireGuard.saveConfig(); - return { success: true }; -}); diff --git a/src/server/api/admin/interface/cidr.post.ts b/src/server/api/admin/interface/cidr.post.ts new file mode 100644 index 00000000..7df34297 --- /dev/null +++ b/src/server/api/admin/interface/cidr.post.ts @@ -0,0 +1,15 @@ +import { InterfaceCidrUpdateSchema } from '#db/repositories/interface/types'; + +export default definePermissionEventHandler( + actions.ADMIN, + async ({ event }) => { + const data = await readValidatedBody( + event, + validateZod(InterfaceCidrUpdateSchema, event) + ); + + await Database.interfaces.updateCidr('wg0', data); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/admin/interface/index.get.ts b/src/server/api/admin/interface/index.get.ts new file mode 100644 index 00000000..16536d6e --- /dev/null +++ b/src/server/api/admin/interface/index.get.ts @@ -0,0 +1,12 @@ +export default definePermissionEventHandler(actions.ADMIN, async () => { + const wgInterface = await Database.interfaces.get('wg0'); + + if (!wgInterface) { + throw new Error('Interface not found'); + } + + return { + ...wgInterface, + privateKey: undefined, + }; +}); diff --git a/src/server/api/admin/interface/index.post.ts b/src/server/api/admin/interface/index.post.ts new file mode 100644 index 00000000..11538d2e --- /dev/null +++ b/src/server/api/admin/interface/index.post.ts @@ -0,0 +1,14 @@ +import { InterfaceUpdateSchema } from '#db/repositories/interface/types'; + +export default definePermissionEventHandler( + actions.ADMIN, + async ({ event }) => { + const data = await readValidatedBody( + event, + validateZod(InterfaceUpdateSchema, event) + ); + await Database.interfaces.update('wg0', data); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/admin/userconfig.get.ts b/src/server/api/admin/userconfig.get.ts new file mode 100644 index 00000000..d6315be3 --- /dev/null +++ b/src/server/api/admin/userconfig.get.ts @@ -0,0 +1,7 @@ +export default definePermissionEventHandler(actions.ADMIN, async () => { + const userConfig = await Database.userConfigs.get('wg0'); + if (!userConfig) { + throw new Error('User config not found'); + } + return userConfig; +}); diff --git a/src/server/api/admin/userconfig.post.ts b/src/server/api/admin/userconfig.post.ts new file mode 100644 index 00000000..afbc7499 --- /dev/null +++ b/src/server/api/admin/userconfig.post.ts @@ -0,0 +1,14 @@ +import { UserConfigUpdateSchema } from '#db/repositories/userConfig/types'; + +export default definePermissionEventHandler( + actions.ADMIN, + async ({ event }) => { + const data = await readValidatedBody( + event, + validateZod(UserConfigUpdateSchema, event) + ); + await Database.userConfigs.update('wg0', data); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/admin/userconfig/cidr.post.ts b/src/server/api/admin/userconfig/cidr.post.ts deleted file mode 100644 index 5b845aa1..00000000 --- a/src/server/api/admin/userconfig/cidr.post.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default defineEventHandler(async (event) => { - const data = await readValidatedBody( - event, - validateZod(cidrUpdateType, event) - ); - - await WireGuard.updateAddressRange(data); - return { success: true }; -}); diff --git a/src/server/api/admin/userconfig/index.get.ts b/src/server/api/admin/userconfig/index.get.ts deleted file mode 100644 index b7683045..00000000 --- a/src/server/api/admin/userconfig/index.get.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default defineEventHandler(async () => { - const system = await Database.system.get(); - return system.userConfig; -}); diff --git a/src/server/api/admin/userconfig/index.post.ts b/src/server/api/admin/userconfig/index.post.ts deleted file mode 100644 index a6146db8..00000000 --- a/src/server/api/admin/userconfig/index.post.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default defineEventHandler(async (event) => { - const data = await readValidatedBody( - event, - validateZod(userConfigUpdateType, event) - ); - await Database.system.updateUserConfig(data); - await WireGuard.saveConfig(); - return { success: true }; -}); diff --git a/src/server/api/client/[clientId]/configuration.get.ts b/src/server/api/client/[clientId]/configuration.get.ts index 2a404f08..e20645b5 100644 --- a/src/server/api/client/[clientId]/configuration.get.ts +++ b/src/server/api/client/[clientId]/configuration.get.ts @@ -1,20 +1,31 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - const client = await WireGuard.getClient({ clientId }); - const config = await WireGuard.getClientConfiguration({ clientId }); - const configName = client.name - .replace(/[^a-zA-Z0-9_=+.-]/g, '-') - .replace(/(-{2,}|-$)/g, '-') - .replace(/-$/, '') - .substring(0, 32); - setHeader( - event, - 'Content-Disposition', - `attachment; filename="${configName || clientId}.conf"` - ); - setHeader(event, 'Content-Type', 'text/plain'); - return config; -}); +import { ClientGetSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); + const client = await Database.clients.get(clientId); + if (!client) { + throw createError({ + statusCode: 404, + statusMessage: 'Client not found', + }); + } + const config = await WireGuard.getClientConfiguration({ clientId }); + const configName = client.name + .replace(/[^a-zA-Z0-9_=+.-]/g, '-') + .replace(/(-{2,}|-$)/g, '-') + .replace(/-$/, '') + .substring(0, 32); + setHeader( + event, + 'Content-Disposition', + `attachment; filename="${configName || clientId}.conf"` + ); + setHeader(event, 'Content-Type', 'text/plain'); + return config; + } +); diff --git a/src/server/api/client/[clientId]/disable.post.ts b/src/server/api/client/[clientId]/disable.post.ts index 14d1bc68..d4746e2d 100644 --- a/src/server/api/client/[clientId]/disable.post.ts +++ b/src/server/api/client/[clientId]/disable.post.ts @@ -1,8 +1,14 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - await WireGuard.disableClient({ clientId }); - return { success: true }; -}); +import { ClientGetSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); + await Database.clients.toggle(clientId, false); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/client/[clientId]/enable.post.ts b/src/server/api/client/[clientId]/enable.post.ts index 1064a872..d4746e2d 100644 --- a/src/server/api/client/[clientId]/enable.post.ts +++ b/src/server/api/client/[clientId]/enable.post.ts @@ -1,8 +1,14 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - await WireGuard.enableClient({ clientId }); - return { success: true }; -}); +import { ClientGetSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); + await Database.clients.toggle(clientId, false); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/client/[clientId]/generateOneTimeLink.post.ts b/src/server/api/client/[clientId]/generateOneTimeLink.post.ts index dfd861d1..dc4287ad 100644 --- a/src/server/api/client/[clientId]/generateOneTimeLink.post.ts +++ b/src/server/api/client/[clientId]/generateOneTimeLink.post.ts @@ -1,8 +1,13 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - await WireGuard.generateOneTimeLink({ clientId }); - return { success: true }; -}); +import { ClientGetSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); + await Database.oneTimeLinks.generate(clientId); + return { success: true }; + } +); diff --git a/src/server/api/client/[clientId]/index.delete.ts b/src/server/api/client/[clientId]/index.delete.ts index 68a1d678..686a39ac 100644 --- a/src/server/api/client/[clientId]/index.delete.ts +++ b/src/server/api/client/[clientId]/index.delete.ts @@ -1,8 +1,14 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - await WireGuard.deleteClient({ clientId }); - return { success: true }; -}); +import { ClientGetSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); + await Database.clients.delete(clientId); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/client/[clientId]/index.get.ts b/src/server/api/client/[clientId]/index.get.ts index e5a2ca8d..9bdd8302 100644 --- a/src/server/api/client/[clientId]/index.get.ts +++ b/src/server/api/client/[clientId]/index.get.ts @@ -1,7 +1,19 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - return WireGuard.getClient({ clientId }); -}); +import { ClientGetSchema } from '~~/server/database/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema, event) + ); + const result = await Database.clients.get(clientId); + if (!result) { + throw createError({ + statusCode: 404, + statusMessage: 'Client not found', + }); + } + return result; + } +); diff --git a/src/server/api/client/[clientId]/index.post.ts b/src/server/api/client/[clientId]/index.post.ts index 764afdc0..78ff38e3 100644 --- a/src/server/api/client/[clientId]/index.post.ts +++ b/src/server/api/client/[clientId]/index.post.ts @@ -1,18 +1,24 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); +import { + ClientGetSchema, + ClientUpdateSchema, +} from '#db/repositories/client/types'; - const data = await readValidatedBody( - event, - validateZod(clientUpdateType, event) - ); +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); - await WireGuard.updateClient({ - clientId, - client: data, - }); + const data = await readValidatedBody( + event, + validateZod(ClientUpdateSchema, event) + ); - return { success: true }; -}); + await Database.clients.update(clientId, data); + await WireGuard.saveConfig(); + + return { success: true }; + } +); diff --git a/src/server/api/client/[clientId]/qrcode.svg.get.ts b/src/server/api/client/[clientId]/qrcode.svg.get.ts index dc21fb84..381054cd 100644 --- a/src/server/api/client/[clientId]/qrcode.svg.get.ts +++ b/src/server/api/client/[clientId]/qrcode.svg.get.ts @@ -1,9 +1,14 @@ -export default defineEventHandler(async (event) => { - const { clientId } = await getValidatedRouterParams( - event, - validateZod(clientIdType) - ); - const svg = await WireGuard.getClientQRCodeSVG({ clientId }); - setHeader(event, 'Content-Type', 'image/svg+xml'); - return svg; -}); +import { ClientGetSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { clientId } = await getValidatedRouterParams( + event, + validateZod(ClientGetSchema) + ); + const svg = await WireGuard.getClientQRCodeSVG({ clientId }); + setHeader(event, 'Content-Type', 'image/svg+xml'); + return svg; + } +); diff --git a/src/server/api/client/index.get.ts b/src/server/api/client/index.get.ts index adffc9b3..9608b72b 100644 --- a/src/server/api/client/index.get.ts +++ b/src/server/api/client/index.get.ts @@ -1,3 +1,3 @@ -export default defineEventHandler(() => { +export default definePermissionEventHandler(actions.CLIENT, () => { return WireGuard.getClients(); }); diff --git a/src/server/api/client/index.post.ts b/src/server/api/client/index.post.ts index c4dfd4f8..aa461746 100644 --- a/src/server/api/client/index.post.ts +++ b/src/server/api/client/index.post.ts @@ -1,8 +1,14 @@ -export default defineEventHandler(async (event) => { - const { name, expireDate } = await readValidatedBody( - event, - validateZod(createType) - ); - await WireGuard.createClient({ name, expireDate }); - return { success: true }; -}); +import { ClientCreateSchema } from '#db/repositories/client/types'; + +export default definePermissionEventHandler( + actions.CLIENT, + async ({ event }) => { + const { name, expiresAt } = await readValidatedBody( + event, + validateZod(ClientCreateSchema) + ); + await Database.clients.create({ name, expiresAt }); + await WireGuard.saveConfig(); + return { success: true }; + } +); diff --git a/src/server/api/session.get.ts b/src/server/api/session.get.ts index dee40f88..6623c86f 100644 --- a/src/server/api/session.get.ts +++ b/src/server/api/session.get.ts @@ -7,7 +7,7 @@ export default defineEventHandler(async (event) => { statusMessage: 'Not logged in', }); } - const user = await Database.user.findById(session.data.userId); + const user = await Database.users.get(session.data.userId); if (!user) { throw createError({ statusCode: 404, diff --git a/src/server/api/session.post.ts b/src/server/api/session.post.ts index b4e7e9f8..4cfbf35d 100644 --- a/src/server/api/session.post.ts +++ b/src/server/api/session.post.ts @@ -1,11 +1,12 @@ +import { UserLoginSchema } from '#db/repositories/user/types'; + export default defineEventHandler(async (event) => { const { username, password, remember } = await readValidatedBody( event, - validateZod(credentialsType, event) + validateZod(UserLoginSchema, event) ); - const users = await Database.user.findAll(); - const user = users.find((user) => user.username == username); + const user = await Database.users.getByUsername(username); if (!user) throw createError({ statusCode: 400, @@ -21,18 +22,7 @@ export default defineEventHandler(async (event) => { }); } - const system = await Database.system.get(); - - const conf = { ...system.sessionConfig }; - - if (remember) { - conf.cookie = { - ...(system.sessionConfig.cookie ?? {}), - maxAge: system.general.sessionTimeout, - }; - } - - const session = await useSession(event, conf); + const session = await useWGSession(event, remember); const data = await session.update({ userId: user.id, diff --git a/src/server/api/setup/4.post.ts b/src/server/api/setup/4.post.ts index 67a4b28a..0dd73670 100644 --- a/src/server/api/setup/4.post.ts +++ b/src/server/api/setup/4.post.ts @@ -1,17 +1,12 @@ -export default defineEventHandler(async (event) => { - const setupDone = await Database.setup.done(); - if (setupDone) { - throw createError({ - statusCode: 400, - statusMessage: 'Invalid state', - }); - } +import { UserSetupType } from '#db/repositories/user/types'; +export default defineSetupEventHandler(async ({ event }) => { const { username, password } = await readValidatedBody( event, - validateZod(passwordSetupType, event) + validateZod(UserSetupType, event) ); - await Database.user.create(username, password); - await Database.setup.set(5); + + await Database.users.create(username, password); + await Database.general.setSetupStep(5); return { success: true }; }); diff --git a/src/server/api/setup/5.post.ts b/src/server/api/setup/5.post.ts index fa6b9aac..1e0b36d6 100644 --- a/src/server/api/setup/5.post.ts +++ b/src/server/api/setup/5.post.ts @@ -1,17 +1,11 @@ -export default defineEventHandler(async (event) => { - const setupDone = await Database.setup.done(); - if (setupDone) { - throw createError({ - statusCode: 400, - statusMessage: 'Invalid state', - }); - } +import { UserConfigSetupType } from '#db/repositories/userConfig/types'; +export default defineSetupEventHandler(async ({ event }) => { const { host, port } = await readValidatedBody( event, - validateZod(hostPortType, event) + validateZod(UserConfigSetupType, event) ); - await Database.system.updateClientsHostPort(host, port); - await Database.setup.set('success'); + await Database.userConfigs.updateHostPort('wg0', host, port); + await Database.general.setSetupStep(0); return { success: true }; }); diff --git a/src/server/api/setup/migrate.post.ts b/src/server/api/setup/migrate.post.ts index 082dfad6..d5256f9c 100644 --- a/src/server/api/setup/migrate.post.ts +++ b/src/server/api/setup/migrate.post.ts @@ -1,16 +1,10 @@ -import { parseCidr } from 'cidr-tools'; +/*import { parseCidr } from 'cidr-tools'; import { stringifyIp } from 'ip-bigint'; -import { z } from 'zod'; -import type { Database } from '~~/services/database/repositories/database'; +import { z } from 'zod';*/ -export default defineEventHandler(async (event) => { - const setupDone = await Database.setup.done(); - if (setupDone) { - throw createError({ - statusCode: 400, - statusMessage: 'Invalid state', - }); - } +export default defineSetupEventHandler(async (/*{ event }*/) => { + // TODO: Implement + /* const { file } = await readValidatedBody(event, validateZod(fileType, event)); const schema = z.object({ @@ -79,7 +73,7 @@ export default defineEventHandler(async (event) => { address6: address6, mtu: 1420, }); - } + }*/ return { success: true }; }); diff --git a/src/server/api/wireguard/backup.get.ts b/src/server/api/wireguard/backup.get.ts index 97d21ae8..648b95e9 100644 --- a/src/server/api/wireguard/backup.get.ts +++ b/src/server/api/wireguard/backup.get.ts @@ -1,6 +1,9 @@ -export default defineEventHandler(async (event) => { - const config = await WireGuard.backupConfiguration(); - setHeader(event, 'Content-Disposition', 'attachment; filename="wg0.json"'); - setHeader(event, 'Content-Type', 'text/json'); - return config; -}); +export default definePermissionEventHandler( + actions.ADMIN, + async (/*{ event }*/) => { + /*const config = await WireGuard.backupConfiguration(); + setHeader(event, 'Content-Disposition', 'attachment; filename="wg0.json"'); + setHeader(event, 'Content-Type', 'text/json'); + return config;*/ + } +); diff --git a/src/server/api/wireguard/restore.put.ts b/src/server/api/wireguard/restore.put.ts index 0d902c4e..c7a95ba5 100644 --- a/src/server/api/wireguard/restore.put.ts +++ b/src/server/api/wireguard/restore.put.ts @@ -1,5 +1,8 @@ -export default defineEventHandler(async (event) => { - const { file } = await readValidatedBody(event, validateZod(fileType)); - await WireGuard.restoreConfiguration(file); - return { success: true }; -}); +export default definePermissionEventHandler( + actions.ADMIN, + async (/*{ event }*/) => { + /*const { file } = await readValidatedBody(event, validateZod(fileType)); + await WireGuard.restoreConfiguration(file); + return { success: true };*/ + } +); diff --git a/src/server/database/migrations/0000_short_skin.sql b/src/server/database/migrations/0000_short_skin.sql new file mode 100644 index 00000000..64d44bf0 --- /dev/null +++ b/src/server/database/migrations/0000_short_skin.sql @@ -0,0 +1,100 @@ +CREATE TABLE `clients_table` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL, + `ipv4_address` text NOT NULL, + `ipv6_address` text NOT NULL, + `private_key` text NOT NULL, + `public_key` text NOT NULL, + `pre_shared_key` text NOT NULL, + `expires_at` text, + `allowed_ips` text NOT NULL, + `server_allowed_ips` text NOT NULL, + `persistent_keepalive` integer NOT NULL, + `mtu` integer NOT NULL, + `dns` text NOT NULL, + `enabled` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `clients_table_ipv4_address_unique` ON `clients_table` (`ipv4_address`);--> statement-breakpoint +CREATE UNIQUE INDEX `clients_table_ipv6_address_unique` ON `clients_table` (`ipv6_address`);--> statement-breakpoint +CREATE TABLE `general_table` ( + `id` integer PRIMARY KEY DEFAULT 1 NOT NULL, + `setupStep` integer NOT NULL, + `session_password` text NOT NULL, + `session_timeout` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL +); +--> statement-breakpoint +CREATE TABLE `hooks_table` ( + `id` text PRIMARY KEY NOT NULL, + `pre_up` text NOT NULL, + `post_up` text NOT NULL, + `pre_down` text NOT NULL, + `post_down` text NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `interfaces_table` ( + `name` text PRIMARY KEY NOT NULL, + `device` text NOT NULL, + `port` integer NOT NULL, + `private_key` text NOT NULL, + `public_key` text NOT NULL, + `ipv4_cidr` text NOT NULL, + `ipv6_cidr` text NOT NULL, + `mtu` integer NOT NULL, + `enabled` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `interfaces_table_port_unique` ON `interfaces_table` (`port`);--> statement-breakpoint +CREATE TABLE `prometheus_table` ( + `id` text PRIMARY KEY NOT NULL, + `password` text NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `one_time_links_table` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `one_time_link` text NOT NULL, + `expires_at` text NOT NULL, + `clientId` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + FOREIGN KEY (`clientId`) REFERENCES `clients_table`(`id`) ON UPDATE cascade ON DELETE cascade +); +--> statement-breakpoint +CREATE UNIQUE INDEX `one_time_links_table_one_time_link_unique` ON `one_time_links_table` (`one_time_link`);--> statement-breakpoint +CREATE TABLE `users_table` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `username` text NOT NULL, + `password` text NOT NULL, + `email` text, + `name` text NOT NULL, + `role` integer NOT NULL, + `enabled` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `users_table_username_unique` ON `users_table` (`username`);--> statement-breakpoint +CREATE TABLE `user_configs_table` ( + `id` text PRIMARY KEY NOT NULL, + `default_mtu` integer NOT NULL, + `default_persistent_keepalive` integer NOT NULL, + `default_dns` text NOT NULL, + `default_allowed_ips` text NOT NULL, + `host` text NOT NULL, + `port` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade +); diff --git a/src/server/database/migrations/0001_classy_the_stranger.sql b/src/server/database/migrations/0001_classy_the_stranger.sql new file mode 100644 index 00000000..c1dfd3fe --- /dev/null +++ b/src/server/database/migrations/0001_classy_the_stranger.sql @@ -0,0 +1,18 @@ +PRAGMA journal_mode=WAL;--> statement-breakpoint +INSERT INTO `general_table` (`setupStep`, `session_password`, `session_timeout`) +VALUES (1, hex(randomblob(256)), 3600); +--> statement-breakpoint +INSERT INTO `interfaces_table` (`name`, `device`, `port`, `private_key`, `public_key`, `ipv4_cidr`, `ipv6_cidr`, `mtu`, `enabled`) +VALUES ('wg0', 'eth0', 51820, '---default---', '---default---', '10.8.0.0/24', 'fdcc:ad94:bacf:61a4::cafe:0/112', 1420, 1); +--> statement-breakpoint +INSERT INTO `hooks_table` (`id`, `pre_up`, `post_up`, `pre_down`, `post_down`) +VALUES ( + 'wg0', + '', + 'iptables -t nat -A POSTROUTING -s {{ipv4Cidr}} -o {{device}} -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport {{port}} -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -s {{ipv6Cidr}} -o {{device}} -j MASQUERADE; ip6tables -A INPUT -p udp -m udp --dport {{port}} -j ACCEPT; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -A FORWARD -o wg0 -j ACCEPT;', + '', + 'iptables -t nat -D POSTROUTING -s {{ipv4Cidr}} -o {{device}} -j MASQUERADE; iptables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -s {{ipv6Cidr}} -o {{device}} -j MASQUERADE; ip6tables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -D FORWARD -o wg0 -j ACCEPT;' +); +--> statement-breakpoint +INSERT INTO `user_configs_table` (`id`, `default_mtu`, `default_persistent_keepalive`, `default_dns`, `default_allowed_ips`, `host`, `port`) +VALUES ('wg0', 1420, 0, '["1.1.1.1","2606:4700:4700::1111"]', '["0.0.0.0/0","::/0"]', '', 51820) diff --git a/src/server/database/migrations/meta/0000_snapshot.json b/src/server/database/migrations/meta/0000_snapshot.json new file mode 100644 index 00000000..abc6ade7 --- /dev/null +++ b/src/server/database/migrations/meta/0000_snapshot.json @@ -0,0 +1,686 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "25907c5f-be21-4ae6-88c4-1a72b2f335e7", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "clients_table": { + "name": "clients_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv4_address": { + "name": "ipv4_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv6_address": { + "name": "ipv6_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pre_shared_key": { + "name": "pre_shared_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowed_ips": { + "name": "allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "server_allowed_ips": { + "name": "server_allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "persistent_keepalive": { + "name": "persistent_keepalive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dns": { + "name": "dns", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "clients_table_ipv4_address_unique": { + "name": "clients_table_ipv4_address_unique", + "columns": [ + "ipv4_address" + ], + "isUnique": true + }, + "clients_table_ipv6_address_unique": { + "name": "clients_table_ipv6_address_unique", + "columns": [ + "ipv6_address" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "general_table": { + "name": "general_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "setupStep": { + "name": "setupStep", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_password": { + "name": "session_password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_timeout": { + "name": "session_timeout", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "hooks_table": { + "name": "hooks_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "pre_up": { + "name": "pre_up", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_up": { + "name": "post_up", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pre_down": { + "name": "pre_down", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_down": { + "name": "post_down", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "hooks_table_id_interfaces_table_name_fk": { + "name": "hooks_table_id_interfaces_table_name_fk", + "tableFrom": "hooks_table", + "tableTo": "interfaces_table", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "name" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "interfaces_table": { + "name": "interfaces_table", + "columns": { + "name": { + "name": "name", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv4_cidr": { + "name": "ipv4_cidr", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv6_cidr": { + "name": "ipv6_cidr", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "interfaces_table_port_unique": { + "name": "interfaces_table_port_unique", + "columns": [ + "port" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "prometheus_table": { + "name": "prometheus_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "prometheus_table_id_interfaces_table_name_fk": { + "name": "prometheus_table_id_interfaces_table_name_fk", + "tableFrom": "prometheus_table", + "tableTo": "interfaces_table", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "name" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "one_time_links_table": { + "name": "one_time_links_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "one_time_link": { + "name": "one_time_link", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "clientId": { + "name": "clientId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "one_time_links_table_one_time_link_unique": { + "name": "one_time_links_table_one_time_link_unique", + "columns": [ + "one_time_link" + ], + "isUnique": true + } + }, + "foreignKeys": { + "one_time_links_table_clientId_clients_table_id_fk": { + "name": "one_time_links_table_clientId_clients_table_id_fk", + "tableFrom": "one_time_links_table", + "tableTo": "clients_table", + "columnsFrom": [ + "clientId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users_table": { + "name": "users_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "users_table_username_unique": { + "name": "users_table_username_unique", + "columns": [ + "username" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_configs_table": { + "name": "user_configs_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "default_mtu": { + "name": "default_mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_persistent_keepalive": { + "name": "default_persistent_keepalive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_dns": { + "name": "default_dns", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_allowed_ips": { + "name": "default_allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "user_configs_table_id_interfaces_table_name_fk": { + "name": "user_configs_table_id_interfaces_table_name_fk", + "tableFrom": "user_configs_table", + "tableTo": "interfaces_table", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "name" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/server/database/migrations/meta/0001_snapshot.json b/src/server/database/migrations/meta/0001_snapshot.json new file mode 100644 index 00000000..d0d7078b --- /dev/null +++ b/src/server/database/migrations/meta/0001_snapshot.json @@ -0,0 +1,686 @@ +{ + "id": "60af732f-adc0-405d-96cc-2f818585f593", + "prevId": "25907c5f-be21-4ae6-88c4-1a72b2f335e7", + "version": "6", + "dialect": "sqlite", + "tables": { + "clients_table": { + "name": "clients_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv4_address": { + "name": "ipv4_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv6_address": { + "name": "ipv6_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pre_shared_key": { + "name": "pre_shared_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowed_ips": { + "name": "allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "server_allowed_ips": { + "name": "server_allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "persistent_keepalive": { + "name": "persistent_keepalive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dns": { + "name": "dns", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "clients_table_ipv4_address_unique": { + "name": "clients_table_ipv4_address_unique", + "columns": [ + "ipv4_address" + ], + "isUnique": true + }, + "clients_table_ipv6_address_unique": { + "name": "clients_table_ipv6_address_unique", + "columns": [ + "ipv6_address" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "general_table": { + "name": "general_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "setupStep": { + "name": "setupStep", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_password": { + "name": "session_password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_timeout": { + "name": "session_timeout", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "hooks_table": { + "name": "hooks_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "pre_up": { + "name": "pre_up", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_up": { + "name": "post_up", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pre_down": { + "name": "pre_down", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_down": { + "name": "post_down", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "hooks_table_id_interfaces_table_name_fk": { + "name": "hooks_table_id_interfaces_table_name_fk", + "tableFrom": "hooks_table", + "columnsFrom": [ + "id" + ], + "tableTo": "interfaces_table", + "columnsTo": [ + "name" + ], + "onUpdate": "cascade", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "interfaces_table": { + "name": "interfaces_table", + "columns": { + "name": { + "name": "name", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv4_cidr": { + "name": "ipv4_cidr", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv6_cidr": { + "name": "ipv6_cidr", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "interfaces_table_port_unique": { + "name": "interfaces_table_port_unique", + "columns": [ + "port" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "prometheus_table": { + "name": "prometheus_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "prometheus_table_id_interfaces_table_name_fk": { + "name": "prometheus_table_id_interfaces_table_name_fk", + "tableFrom": "prometheus_table", + "columnsFrom": [ + "id" + ], + "tableTo": "interfaces_table", + "columnsTo": [ + "name" + ], + "onUpdate": "cascade", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "one_time_links_table": { + "name": "one_time_links_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "one_time_link": { + "name": "one_time_link", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "clientId": { + "name": "clientId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "one_time_links_table_one_time_link_unique": { + "name": "one_time_links_table_one_time_link_unique", + "columns": [ + "one_time_link" + ], + "isUnique": true + } + }, + "foreignKeys": { + "one_time_links_table_clientId_clients_table_id_fk": { + "name": "one_time_links_table_clientId_clients_table_id_fk", + "tableFrom": "one_time_links_table", + "columnsFrom": [ + "clientId" + ], + "tableTo": "clients_table", + "columnsTo": [ + "id" + ], + "onUpdate": "cascade", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users_table": { + "name": "users_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "users_table_username_unique": { + "name": "users_table_username_unique", + "columns": [ + "username" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_configs_table": { + "name": "user_configs_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "default_mtu": { + "name": "default_mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_persistent_keepalive": { + "name": "default_persistent_keepalive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_dns": { + "name": "default_dns", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_allowed_ips": { + "name": "default_allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "user_configs_table_id_interfaces_table_name_fk": { + "name": "user_configs_table_id_interfaces_table_name_fk", + "tableFrom": "user_configs_table", + "columnsFrom": [ + "id" + ], + "tableTo": "interfaces_table", + "columnsTo": [ + "name" + ], + "onUpdate": "cascade", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/server/database/migrations/meta/_journal.json b/src/server/database/migrations/meta/_journal.json new file mode 100644 index 00000000..0e72d1fe --- /dev/null +++ b/src/server/database/migrations/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1737122352401, + "tag": "0000_short_skin", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1737122356601, + "tag": "0001_classy_the_stranger", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/src/server/database/repositories/client/schema.ts b/src/server/database/repositories/client/schema.ts new file mode 100644 index 00000000..6a38667e --- /dev/null +++ b/src/server/database/repositories/client/schema.ts @@ -0,0 +1,37 @@ +import { sql, relations } from 'drizzle-orm'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +import { oneTimeLink } from '../../schema'; + +export const client = sqliteTable('clients_table', { + id: int().primaryKey({ autoIncrement: true }), + name: text().notNull(), + ipv4Address: text('ipv4_address').notNull().unique(), + ipv6Address: text('ipv6_address').notNull().unique(), + privateKey: text('private_key').notNull(), + publicKey: text('public_key').notNull(), + preSharedKey: text('pre_shared_key').notNull(), + expiresAt: text('expires_at'), + allowedIps: text('allowed_ips', { mode: 'json' }).$type().notNull(), + serverAllowedIps: text('server_allowed_ips', { mode: 'json' }) + .$type() + .notNull(), + persistentKeepalive: int('persistent_keepalive').notNull(), + mtu: int().notNull(), + dns: text({ mode: 'json' }).$type().notNull(), + enabled: int({ mode: 'boolean' }).notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); + +export const clientsRelations = relations(client, ({ one }) => ({ + oneTimeLink: one(oneTimeLink, { + fields: [client.id], + references: [oneTimeLink.clientId], + }), +})); diff --git a/src/server/database/repositories/client/service.ts b/src/server/database/repositories/client/service.ts new file mode 100644 index 00000000..ddd10729 --- /dev/null +++ b/src/server/database/repositories/client/service.ts @@ -0,0 +1,128 @@ +import type { DBType } from '#db/sqlite'; +import { eq, sql } from 'drizzle-orm'; +import { client } from './schema'; +import type { ClientCreateType, UpdateClientType } from './types'; +import type { ID } from '#db/schema'; +import { wgInterface, userConfig } from '#db/schema'; +import { parseCidr } from 'cidr-tools'; + +function createPreparedStatement(db: DBType) { + return { + findAll: db.query.client + .findMany({ + with: { + oneTimeLink: true, + }, + }) + .prepare(), + findById: db.query.client + .findFirst({ where: eq(client.id, sql.placeholder('id')) }) + .prepare(), + toggle: db + .update(client) + .set({ enabled: sql.placeholder('enabled') as never as boolean }) + .where(eq(client.id, sql.placeholder('id'))) + .prepare(), + delete: db + .delete(client) + .where(eq(client.id, sql.placeholder('id'))) + .prepare(), + }; +} + +export class ClientService { + #db: DBType; + #statements: ReturnType; + + constructor(db: DBType) { + this.#db = db; + this.#statements = createPreparedStatement(db); + } + + async getAll() { + const result = await this.#statements.findAll.execute(); + return result.map((row) => ({ + ...row, + createdAt: new Date(row.createdAt), + updatedAt: new Date(row.updatedAt), + })); + } + + get(id: ID) { + return this.#statements.findById.execute({ id }); + } + + async create({ name, expiresAt }: ClientCreateType) { + const privateKey = await wg.generatePrivateKey(); + const publicKey = await wg.getPublicKey(privateKey); + const preSharedKey = await wg.generatePreSharedKey(); + + let parsedExpiresAt = expiresAt; + if (parsedExpiresAt) { + const expiresAtDate = new Date(parsedExpiresAt); + expiresAtDate.setHours(23); + expiresAtDate.setMinutes(59); + expiresAtDate.setSeconds(59); + parsedExpiresAt = expiresAtDate.toISOString(); + } + + return this.#db.transaction(async (tx) => { + const clients = await tx.query.client.findMany().execute(); + const clientInterface = await tx.query.wgInterface + .findFirst({ + where: eq(wgInterface.name, 'wg0'), + }) + .execute(); + + if (!clientInterface) { + throw new Error('WireGuard interface not found'); + } + + const clientConfig = await tx.query.userConfig + .findFirst({ + where: eq(userConfig.id, clientInterface.name), + }) + .execute(); + + if (!clientConfig) { + throw new Error('WireGuard interface configuration not found'); + } + + const ipv4Cidr = parseCidr(clientInterface.ipv4Cidr); + const ipv4Address = nextIP(4, ipv4Cidr, clients); + const ipv6Cidr = parseCidr(clientInterface.ipv6Cidr); + const ipv6Address = nextIP(6, ipv6Cidr, clients); + + await tx + .insert(client) + .values({ + name, + expiresAt: parsedExpiresAt, + privateKey, + publicKey, + preSharedKey, + ipv4Address, + ipv6Address, + mtu: clientConfig.defaultMtu, + allowedIps: clientConfig.defaultAllowedIps, + dns: clientConfig.defaultDns, + persistentKeepalive: clientConfig.defaultPersistentKeepalive, + serverAllowedIps: [], + enabled: true, + }) + .execute(); + }); + } + + toggle(id: ID, enabled: boolean) { + return this.#statements.toggle.execute({ id, enabled }); + } + + delete(id: ID) { + return this.#statements.delete.execute({ id }); + } + + update(id: ID, data: UpdateClientType) { + return this.#db.update(client).set(data).where(eq(client.id, id)).execute(); + } +} diff --git a/src/server/database/repositories/client/types.ts b/src/server/database/repositories/client/types.ts new file mode 100644 index 00000000..68663209 --- /dev/null +++ b/src/server/database/repositories/client/types.ts @@ -0,0 +1,72 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import z from 'zod'; + +import type { client } from './schema'; + +export type ID = string; + +export type ClientType = InferSelectModel; + +export type CreateClientType = Omit< + ClientType, + 'createdAt' | 'updatedAt' | 'id' +>; + +export type UpdateClientType = Omit< + CreateClientType, + 'privateKey' | 'publicKey' | 'preSharedKey' +>; + +const name = z + .string({ message: 'zod.client.name' }) + .min(1, 'zod.client.nameMin') + .pipe(safeStringRefine); + +const expiresAt = z + .string({ message: 'zod.client.expireDate' }) + .min(1, 'zod.client.expireDateMin') + .pipe(safeStringRefine) + .nullable(); + +const address4 = z + .string({ message: 'zod.client.address4' }) + .min(1, { message: 'zod.client.address4Min' }) + .pipe(safeStringRefine); + +const address6 = z + .string({ message: 'zod.client.address6' }) + .min(1, { message: 'zod.client.address6Min' }) + .pipe(safeStringRefine); + +const serverAllowedIps = z.array(AddressSchema, { + message: 'zod.serverAllowedIps', +}); + +export const ClientCreateSchema = z.object({ + name: name, + expiresAt: expiresAt, +}); + +export type ClientCreateType = z.infer; + +export const ClientUpdateSchema = schemaForType()( + z.object({ + name: name, + enabled: EnabledSchema, + expiresAt: expiresAt, + ipv4Address: address4, + ipv6Address: address6, + allowedIps: AllowedIpsSchema, + serverAllowedIps: serverAllowedIps, + mtu: MtuSchema, + persistentKeepalive: PersistentKeepaliveSchema, + dns: DnsSchema, + }) +); + +// TODO: investigate if coerce is bad +const clientId = z.number({ message: 'zod.client.id', coerce: true }); + +export const ClientGetSchema = z.object({ + clientId: clientId, +}); diff --git a/src/server/database/repositories/general/schema.ts b/src/server/database/repositories/general/schema.ts new file mode 100644 index 00000000..a2baec6c --- /dev/null +++ b/src/server/database/repositories/general/schema.ts @@ -0,0 +1,16 @@ +import { sql } from 'drizzle-orm'; +import { sqliteTable, text, int } from 'drizzle-orm/sqlite-core'; + +export const general = sqliteTable('general_table', { + id: int().primaryKey({ autoIncrement: false }).default(1), + setupStep: int().notNull(), + sessionPassword: text('session_password').notNull(), + sessionTimeout: int('session_timeout').notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); diff --git a/src/server/database/repositories/general/service.ts b/src/server/database/repositories/general/service.ts new file mode 100644 index 00000000..af48262d --- /dev/null +++ b/src/server/database/repositories/general/service.ts @@ -0,0 +1,68 @@ +import type { DBType } from '#db/sqlite'; +import { sql } from 'drizzle-orm'; +import { general } from './schema'; +import type { GeneralUpdateType } from './types'; + +function createPreparedStatement(db: DBType) { + return { + find: db.query.general.findFirst().prepare(), + updateSetupStep: db + .update(general) + .set({ + setupStep: sql.placeholder('setupStep') as never as number, + }) + .prepare(), + update: db + .update(general) + .set({ + sessionTimeout: sql.placeholder('sessionTimeout') as never as number, + }) + .prepare(), + }; +} + +export class GeneralService { + #statements: ReturnType; + + constructor(db: DBType) { + this.#statements = createPreparedStatement(db); + } + + /** + * @throws + */ + private async get() { + const result = await this.#statements.find.execute(); + if (!result) { + throw new Error('General Config not found'); + } + return result; + } + + /** + * @throws + */ + async getSetupStep() { + const result = await this.get(); + return { step: result.setupStep, done: result.setupStep === 0 }; + } + + setSetupStep(step: number) { + return this.#statements.updateSetupStep.execute({ setupStep: step }); + } + + /** + * @throws + */ + async getSessionConfig() { + const result = await this.get(); + return { + sessionPassword: result.sessionPassword, + sessionTimeout: result.sessionTimeout, + }; + } + + update(data: GeneralUpdateType) { + return this.#statements.update.execute(data); + } +} diff --git a/src/server/database/repositories/general/types.ts b/src/server/database/repositories/general/types.ts new file mode 100644 index 00000000..05944528 --- /dev/null +++ b/src/server/database/repositories/general/types.ts @@ -0,0 +1,15 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { general } from './schema'; +import z from 'zod'; + +export type GeneralType = InferSelectModel; + +const sessionTimeout = z.number({ message: 'zod.general.sessionTimeout' }); + +export const GeneralUpdateSchema = z.object({ + sessionTimeout: sessionTimeout, +}); + +export type GeneralUpdateType = z.infer; + +export type SetupStepType = { step: number; done: boolean }; diff --git a/src/server/database/repositories/hooks/schema.ts b/src/server/database/repositories/hooks/schema.ts new file mode 100644 index 00000000..dcd28264 --- /dev/null +++ b/src/server/database/repositories/hooks/schema.ts @@ -0,0 +1,24 @@ +import { sql } from 'drizzle-orm'; +import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +import { wgInterface } from '../../schema'; + +export const hooks = sqliteTable('hooks_table', { + id: text() + .primaryKey() + .references(() => wgInterface.name, { + onDelete: 'cascade', + onUpdate: 'cascade', + }), + preUp: text('pre_up').notNull(), + postUp: text('post_up').notNull(), + preDown: text('pre_down').notNull(), + postDown: text('post_down').notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); diff --git a/src/server/database/repositories/hooks/service.ts b/src/server/database/repositories/hooks/service.ts new file mode 100644 index 00000000..64d6c27c --- /dev/null +++ b/src/server/database/repositories/hooks/service.ts @@ -0,0 +1,34 @@ +import type { DBType } from '#db/sqlite'; +import { eq, sql } from 'drizzle-orm'; +import { hooks } from './schema'; +import type { HooksUpdateType } from './types'; + +function createPreparedStatement(db: DBType) { + return { + get: db.query.hooks + .findFirst({ where: eq(hooks.id, sql.placeholder('interface')) }) + .prepare(), + }; +} + +export class HooksService { + #db: DBType; + #statements: ReturnType; + + constructor(db: DBType) { + this.#db = db; + this.#statements = createPreparedStatement(db); + } + + get(infName: string) { + return this.#statements.get.execute({ interface: infName }); + } + + update(infName: string, data: HooksUpdateType) { + return this.#db + .update(hooks) + .set(data) + .where(eq(hooks.id, infName)) + .execute(); + } +} diff --git a/src/server/database/repositories/hooks/types.ts b/src/server/database/repositories/hooks/types.ts new file mode 100644 index 00000000..3e76d045 --- /dev/null +++ b/src/server/database/repositories/hooks/types.ts @@ -0,0 +1,18 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { hooks } from './schema'; +import z from 'zod'; + +export type HooksType = InferSelectModel; + +export type HooksUpdateType = Omit; + +const hook = z.string({ message: 'zod.hook' }).pipe(safeStringRefine); + +export const HooksUpdateSchema = schemaForType()( + z.object({ + preUp: hook, + postUp: hook, + preDown: hook, + postDown: hook, + }) +); diff --git a/src/server/database/repositories/interface/schema.ts b/src/server/database/repositories/interface/schema.ts new file mode 100644 index 00000000..41dd898d --- /dev/null +++ b/src/server/database/repositories/interface/schema.ts @@ -0,0 +1,39 @@ +import { sql, relations } from 'drizzle-orm'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +import { userConfig, hooks, prometheus } from '../../schema'; + +// maybe support multiple interfaces in the future +export const wgInterface = sqliteTable('interfaces_table', { + name: text().primaryKey(), + device: text().notNull(), + port: int().notNull().unique(), + privateKey: text('private_key').notNull(), + publicKey: text('public_key').notNull(), + ipv4Cidr: text('ipv4_cidr').notNull(), + ipv6Cidr: text('ipv6_cidr').notNull(), + mtu: int().notNull(), + enabled: int({ mode: 'boolean' }).notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); + +export const wgInterfaceRelations = relations(wgInterface, ({ one }) => ({ + hooks: one(hooks, { + fields: [wgInterface.name], + references: [hooks.id], + }), + prometheus: one(prometheus, { + fields: [wgInterface.name], + references: [prometheus.id], + }), + userConfig: one(userConfig, { + fields: [wgInterface.name], + references: [userConfig.id], + }), +})); diff --git a/src/server/database/repositories/interface/service.ts b/src/server/database/repositories/interface/service.ts new file mode 100644 index 00000000..7361f617 --- /dev/null +++ b/src/server/database/repositories/interface/service.ts @@ -0,0 +1,90 @@ +import type { DBType } from '#db/sqlite'; +import isCidr from 'is-cidr'; +import { eq, sql } from 'drizzle-orm'; +import { wgInterface } from './schema'; +import type { InterfaceCidrUpdateType, InterfaceUpdateType } from './types'; +import { client as clientSchema } from '#db/schema'; +import { parseCidr } from 'cidr-tools'; + +function createPreparedStatement(db: DBType) { + return { + get: db.query.wgInterface + .findFirst({ where: eq(wgInterface.name, sql.placeholder('interface')) }) + .prepare(), + getAll: db.query.wgInterface.findMany().prepare(), + updateKeyPair: db + .update(wgInterface) + .set({ + privateKey: sql.placeholder('privateKey') as never as string, + publicKey: sql.placeholder('publicKey') as never as string, + }) + .where(eq(wgInterface.name, sql.placeholder('interface'))) + .prepare(), + }; +} + +export class InterfaceService { + #db: DBType; + #statements: ReturnType; + + constructor(db: DBType) { + this.#db = db; + this.#statements = createPreparedStatement(db); + } + + get(infName: string) { + return this.#statements.get.execute({ interface: infName }); + } + + getAll() { + return this.#statements.getAll.execute(); + } + + updateKeyPair(infName: string, privateKey: string, publicKey: string) { + return this.#statements.updateKeyPair.execute({ + interface: infName, + privateKey, + publicKey, + }); + } + + update(infName: string, data: InterfaceUpdateType) { + return this.#db + .update(wgInterface) + .set(data) + .where(eq(wgInterface.name, infName)) + .execute(); + } + + updateCidr(infName: string, data: InterfaceCidrUpdateType) { + if (!isCidr(data.ipv4Cidr) || !isCidr(data.ipv6Cidr)) { + throw new Error('Invalid CIDR'); + } + return this.#db.transaction(async (tx) => { + await tx + .update(wgInterface) + .set(data) + .where(eq(wgInterface.name, infName)) + .execute(); + + const clients = await tx.query.client.findMany().execute(); + + for (const client of clients) { + // TODO: optimize + const clients = await tx.query.client.findMany().execute(); + + const nextIpv4 = nextIP(4, parseCidr(data.ipv4Cidr), clients); + const nextIpv6 = nextIP(6, parseCidr(data.ipv6Cidr), clients); + + await tx + .update(clientSchema) + .set({ + ipv4Address: nextIpv4, + ipv6Address: nextIpv6, + }) + .where(eq(clientSchema.id, client.id)) + .execute(); + } + }); + } +} diff --git a/src/server/database/repositories/interface/types.ts b/src/server/database/repositories/interface/types.ts new file mode 100644 index 00000000..df271333 --- /dev/null +++ b/src/server/database/repositories/interface/types.ts @@ -0,0 +1,49 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { wgInterface } from './schema'; +import z from 'zod'; + +export type InterfaceType = InferSelectModel; + +export type InterfaceCreateType = Omit< + InterfaceType, + 'createdAt' | 'updatedAt' +>; + +export type InterfaceUpdateType = Omit< + InterfaceCreateType, + 'name' | 'createdAt' | 'updatedAt' | 'privateKey' | 'publicKey' +>; + +const device = z + .string({ message: 'zod.interface.device' }) + .min(1, 'zod.interface.deviceMin') + .pipe(safeStringRefine); + +const cidr = z + .string({ message: 'zod.interface.cidr' }) + .min(1, { message: 'zod.interface.cidrMin' }) + .pipe(safeStringRefine); + +export const InterfaceUpdateSchema = schemaForType()( + z.object({ + ipv4Cidr: cidr, + ipv6Cidr: cidr, + mtu: MtuSchema, + port: PortSchema, + device: device, + enabled: EnabledSchema, + }) +); + +export type InterfaceCidrUpdateType = { + ipv4Cidr: string; + ipv6Cidr: string; +}; + +export const InterfaceCidrUpdateSchema = + schemaForType()( + z.object({ + ipv4Cidr: cidr, + ipv6Cidr: cidr, + }) + ); diff --git a/src/server/database/repositories/metrics/schema.ts b/src/server/database/repositories/metrics/schema.ts new file mode 100644 index 00000000..894bc0c3 --- /dev/null +++ b/src/server/database/repositories/metrics/schema.ts @@ -0,0 +1,21 @@ +import { sql } from 'drizzle-orm'; +import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +import { wgInterface } from '../../schema'; + +export const prometheus = sqliteTable('prometheus_table', { + id: text() + .primaryKey() + .references(() => wgInterface.name, { + onDelete: 'cascade', + onUpdate: 'cascade', + }), + password: text().notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); diff --git a/src/server/database/repositories/metrics/service.ts b/src/server/database/repositories/metrics/service.ts new file mode 100644 index 00000000..38685749 --- /dev/null +++ b/src/server/database/repositories/metrics/service.ts @@ -0,0 +1,31 @@ +import type { DBType } from '#db/sqlite'; +import { eq, sql } from 'drizzle-orm'; +import { prometheus } from './schema'; + +function createPreparedStatement(db: DBType) { + return { + get: db.query.prometheus + .findFirst({ where: eq(prometheus.id, sql.placeholder('interface')) }) + .prepare(), + }; +} + +export class PrometheusService { + #statements: ReturnType; + + constructor(db: DBType) { + this.#statements = createPreparedStatement(db); + } + + get(infName: string) { + return this.#statements.get.execute({ interface: infName }); + } +} + +export class MetricsService { + prometheus: PrometheusService; + + constructor(db: DBType) { + this.prometheus = new PrometheusService(db); + } +} diff --git a/src/server/database/repositories/metrics/types.ts b/src/server/database/repositories/metrics/types.ts new file mode 100644 index 00000000..45c4bcad --- /dev/null +++ b/src/server/database/repositories/metrics/types.ts @@ -0,0 +1,4 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { prometheus } from './schema'; + +export type PrometheusType = InferSelectModel; diff --git a/src/server/database/repositories/oneTimeLink/schema.ts b/src/server/database/repositories/oneTimeLink/schema.ts new file mode 100644 index 00000000..dd69c2fd --- /dev/null +++ b/src/server/database/repositories/oneTimeLink/schema.ts @@ -0,0 +1,27 @@ +import { sql, relations } from 'drizzle-orm'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +import { client } from '../../schema'; + +export const oneTimeLink = sqliteTable('one_time_links_table', { + id: int().primaryKey({ autoIncrement: true }), + oneTimeLink: text('one_time_link').notNull().unique(), + expiresAt: text('expires_at').notNull(), + clientId: int() + .notNull() + .references(() => client.id, { onDelete: 'cascade', onUpdate: 'cascade' }), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); + +export const oneTimeLinksRelations = relations(oneTimeLink, ({ one }) => ({ + client: one(client, { + fields: [oneTimeLink.clientId], + references: [client.id], + }), +})); diff --git a/src/server/database/repositories/oneTimeLink/service.ts b/src/server/database/repositories/oneTimeLink/service.ts new file mode 100644 index 00000000..2854d67a --- /dev/null +++ b/src/server/database/repositories/oneTimeLink/service.ts @@ -0,0 +1,52 @@ +import type { DBType } from '#db/sqlite'; +import { eq, sql } from 'drizzle-orm'; +import { oneTimeLink } from './schema'; +import type { ID } from '../../schema'; +import CRC32 from 'crc-32'; + +function createPreparedStatement(db: DBType) { + return { + delete: db + .delete(oneTimeLink) + .where(eq(oneTimeLink.id, sql.placeholder('id'))) + .prepare(), + create: db + .insert(oneTimeLink) + .values({ + clientId: sql.placeholder('id'), + oneTimeLink: sql.placeholder('oneTimeLink'), + expiresAt: sql.placeholder('expiresAt'), + }) + .prepare(), + erase: db + .update(oneTimeLink) + .set({ expiresAt: sql.placeholder('expiresAt') as never as string }) + .where(eq(oneTimeLink.clientId, sql.placeholder('id'))) + .prepare(), + }; +} + +export class OneTimeLinkService { + #statements: ReturnType; + + constructor(db: DBType) { + this.#statements = createPreparedStatement(db); + } + + delete(id: ID) { + return this.#statements.delete.execute({ id }); + } + + generate(id: ID) { + const key = `${id}-${Math.floor(Math.random() * 1000)}`; + const oneTimeLink = Math.abs(CRC32.str(key)).toString(16); + const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString(); + + return this.#statements.create.execute({ id, oneTimeLink, expiresAt }); + } + + erase(id: ID) { + const expiresAt = Date.now() + 10 * 1000; + return this.#statements.erase.execute({ id, expiresAt }); + } +} diff --git a/src/server/database/repositories/oneTimeLink/types.ts b/src/server/database/repositories/oneTimeLink/types.ts new file mode 100644 index 00000000..a2a34968 --- /dev/null +++ b/src/server/database/repositories/oneTimeLink/types.ts @@ -0,0 +1,17 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { oneTimeLink } from './schema'; +import { z } from 'zod'; + +export type OneTimeLinkType = InferSelectModel; + +const oneTimeLinkType = z + .string({ message: 'zod.otl.otl' }) + .min(1, 'zod.otl.otlMin') + .pipe(safeStringRefine); + +export const OneTimeLinkGetSchema = z.object( + { + oneTimeLink: oneTimeLinkType, + }, + { message: objectMessage } +); diff --git a/src/server/database/repositories/user/schema.ts b/src/server/database/repositories/user/schema.ts new file mode 100644 index 00000000..71da8582 --- /dev/null +++ b/src/server/database/repositories/user/schema.ts @@ -0,0 +1,19 @@ +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +export const user = sqliteTable('users_table', { + id: int().primaryKey({ autoIncrement: true }), + username: text().notNull().unique(), + password: text().notNull(), + email: text(), + name: text().notNull(), + role: int().$type().notNull(), + enabled: int({ mode: 'boolean' }).notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); diff --git a/src/server/database/repositories/user/service.ts b/src/server/database/repositories/user/service.ts new file mode 100644 index 00000000..209fe99d --- /dev/null +++ b/src/server/database/repositories/user/service.ts @@ -0,0 +1,63 @@ +import type { DBType } from '#db/sqlite'; +import { eq, sql } from 'drizzle-orm'; +import { user } from './schema'; +import type { ID } from '../../schema'; + +function createPreparedStatement(db: DBType) { + return { + findAll: db.query.user.findMany().prepare(), + findById: db.query.user + .findFirst({ where: eq(user.id, sql.placeholder('id')) }) + .prepare(), + findByUsername: db.query.user + .findFirst({ + where: eq(user.username, sql.placeholder('username')), + }) + .prepare(), + }; +} + +export class UserService { + #db: DBType; + #statements: ReturnType; + + constructor(db: DBType) { + this.#db = db; + this.#statements = createPreparedStatement(db); + } + + async getAll() { + return this.#statements.findAll.execute(); + } + + async get(id: ID) { + return this.#statements.findById.execute({ id }); + } + + async getByUsername(username: string) { + return this.#statements.findByUsername.execute({ username }); + } + + async create(username: string, password: string) { + const hash = await hashPassword(password); + + return this.#db.transaction(async (tx) => { + const oldUser = await this.getByUsername(username); + + if (oldUser) { + throw new Error('User already exists'); + } + + const userCount = await tx.$count(user); + + await tx.insert(user).values({ + password: hash, + username, + email: null, + name: 'Administrator', + role: userCount === 0 ? roles.ADMIN : roles.CLIENT, + enabled: true, + }); + }); + } +} diff --git a/src/server/database/repositories/user/types.ts b/src/server/database/repositories/user/types.ts new file mode 100644 index 00000000..7b629365 --- /dev/null +++ b/src/server/database/repositories/user/types.ts @@ -0,0 +1,43 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { user } from './schema'; +import z from 'zod'; + +export type UserType = InferSelectModel; + +const username = z + .string({ message: 'zod.user.username' }) + .min(8, 'zod.user.usernameMin') + .pipe(safeStringRefine); + +const password = z + .string({ message: 'zod.user.password' }) + .min(12, 'zod.user.passwordMin') + .regex(/[A-Z]/, 'zod.user.passwordUppercase') + .regex(/[a-z]/, 'zod.user.passwordLowercase') + .regex(/\d/, 'zod.user.passwordNumber') + .regex(/[!@#$%^&*(),.?":{}|<>]/, 'zod.user.passwordSpecial') + .pipe(safeStringRefine); + +const remember = z.boolean({ message: 'zod.user.remember' }); + +export const UserLoginSchema = z.object( + { + username: username, + password: password, + remember: remember, + }, + { message: objectMessage } +); + +const accept = z.boolean().refine((val) => val === true, { + message: 'zod.user.accept', +}); + +export const UserSetupType = z.object( + { + username: username, + password: password, + accept: accept, + }, + { message: objectMessage } +); diff --git a/src/server/database/repositories/userConfig/schema.ts b/src/server/database/repositories/userConfig/schema.ts new file mode 100644 index 00000000..0c6430f0 --- /dev/null +++ b/src/server/database/repositories/userConfig/schema.ts @@ -0,0 +1,29 @@ +import { sql } from 'drizzle-orm'; +import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; + +import { wgInterface } from '../../schema'; + +// default* means clients store it themselves +export const userConfig = sqliteTable('user_configs_table', { + id: text() + .primaryKey() + .references(() => wgInterface.name, { + onDelete: 'cascade', + onUpdate: 'cascade', + }), + defaultMtu: int('default_mtu').notNull(), + defaultPersistentKeepalive: int('default_persistent_keepalive').notNull(), + defaultDns: text('default_dns', { mode: 'json' }).$type().notNull(), + defaultAllowedIps: text('default_allowed_ips', { mode: 'json' }) + .$type() + .notNull(), + host: text().notNull(), + port: int().notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), +}); diff --git a/src/server/database/repositories/userConfig/service.ts b/src/server/database/repositories/userConfig/service.ts new file mode 100644 index 00000000..42bdb99b --- /dev/null +++ b/src/server/database/repositories/userConfig/service.ts @@ -0,0 +1,50 @@ +import type { DBType } from '#db/sqlite'; +import { eq, sql } from 'drizzle-orm'; +import { userConfig } from './schema'; +import type { UserConfigUpdateType } from './types'; + +function createPreparedStatement(db: DBType) { + return { + get: db.query.userConfig + .findFirst({ where: eq(userConfig.id, sql.placeholder('interface')) }) + .prepare(), + updateHostPort: db + .update(userConfig) + .set({ + host: sql.placeholder('host') as never as string, + port: sql.placeholder('port') as never as number, + }) + .where(eq(userConfig.id, sql.placeholder('interface'))) + .prepare(), + }; +} + +export class UserConfigService { + #db: DBType; + #statements: ReturnType; + + constructor(db: DBType) { + this.#db = db; + this.#statements = createPreparedStatement(db); + } + + get(infName: string) { + return this.#statements.get.execute({ interface: infName }); + } + + updateHostPort(infName: string, host: string, port: number) { + return this.#statements.updateHostPort.execute({ + interface: infName, + host, + port, + }); + } + + update(infName: string, data: UserConfigUpdateType) { + return this.#db + .update(userConfig) + .set(data) + .where(eq(userConfig.id, infName)) + .execute(); + } +} diff --git a/src/server/database/repositories/userConfig/types.ts b/src/server/database/repositories/userConfig/types.ts new file mode 100644 index 00000000..165f3f27 --- /dev/null +++ b/src/server/database/repositories/userConfig/types.ts @@ -0,0 +1,31 @@ +import type { InferSelectModel } from 'drizzle-orm'; +import type { userConfig } from './schema'; +import z from 'zod'; + +export type UserConfigType = InferSelectModel; + +const host = z + .string({ message: 'zod.userConfig.host' }) + .min(1, 'zod.userConfig.hostMin') + .pipe(safeStringRefine); + +export const UserConfigSetupType = z.object({ + host: host, + port: PortSchema, +}); + +export type UserConfigUpdateType = Omit< + UserConfigType, + 'id' | 'createdAt' | 'updatedAt' +>; + +export const UserConfigUpdateSchema = schemaForType()( + z.object({ + port: PortSchema, + defaultMtu: MtuSchema, + defaultPersistentKeepalive: PersistentKeepaliveSchema, + defaultDns: DnsSchema, + defaultAllowedIps: AllowedIpsSchema, + host: host, + }) +); diff --git a/src/server/database/schema.ts b/src/server/database/schema.ts new file mode 100644 index 00000000..73edce69 --- /dev/null +++ b/src/server/database/schema.ts @@ -0,0 +1,12 @@ +// Make sure to not use any Path Aliases in these files +export * from './repositories/client/schema'; +export * from './repositories/general/schema'; +export * from './repositories/hooks/schema'; +export * from './repositories/interface/schema'; +export * from './repositories/metrics/schema'; +export * from './repositories/oneTimeLink/schema'; +export * from './repositories/user/schema'; +export * from './repositories/userConfig/schema'; + +// TODO: move to types +export type ID = number; diff --git a/src/server/database/sqlite.ts b/src/server/database/sqlite.ts new file mode 100644 index 00000000..738e1192 --- /dev/null +++ b/src/server/database/sqlite.ts @@ -0,0 +1,63 @@ +import { drizzle } from 'drizzle-orm/libsql'; +import { migrate as drizzleMigrate } from 'drizzle-orm/libsql/migrator'; +import { createClient } from '@libsql/client'; +import debug from 'debug'; + +import * as schema from './schema'; +import { ClientService } from './repositories/client/service'; +import { GeneralService } from './repositories/general/service'; +import { UserService } from './repositories/user/service'; +import { UserConfigService } from './repositories/userConfig/service'; +import { InterfaceService } from './repositories/interface/service'; +import { HooksService } from './repositories/hooks/service'; +import { OneTimeLinkService } from './repositories/oneTimeLink/service'; +import { MetricsService } from './repositories/metrics/service'; + +const DB_DEBUG = debug('Database'); + +const client = createClient({ url: 'file:/etc/wireguard/wg0.db' }); +const db = drizzle({ client, schema }); + +export async function connect() { + await migrate(); + return new DBService(db); +} + +class DBService { + clients: ClientService; + general: GeneralService; + users: UserService; + userConfigs: UserConfigService; + interfaces: InterfaceService; + hooks: HooksService; + oneTimeLinks: OneTimeLinkService; + metrics: MetricsService; + + constructor(db: DBType) { + this.clients = new ClientService(db); + this.general = new GeneralService(db); + this.users = new UserService(db); + this.userConfigs = new UserConfigService(db); + this.interfaces = new InterfaceService(db); + this.hooks = new HooksService(db); + this.oneTimeLinks = new OneTimeLinkService(db); + this.metrics = new MetricsService(db); + } +} + +export type DBType = typeof db; +export type DBServiceType = DBService; + +async function migrate() { + try { + DB_DEBUG('Migrating database...'); + await drizzleMigrate(db, { + migrationsFolder: './server/database/migrations', + }); + DB_DEBUG('Migration complete'); + } catch (e) { + if (e instanceof Error) { + DB_DEBUG('Failed to migrate database:', e.message); + } + } +} diff --git a/src/server/middleware/auth.ts b/src/server/middleware/auth.ts deleted file mode 100644 index 2b987b4a..00000000 --- a/src/server/middleware/auth.ts +++ /dev/null @@ -1,35 +0,0 @@ -export default defineEventHandler(async (event) => { - const url = getRequestURL(event); - const session = await useWGSession(event); - - // Api handled by session, Setup handled with setup middleware - if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/setup')) { - return; - } - - if (url.pathname === '/login') { - if (session.data.userId) { - return sendRedirect(event, '/', 302); - } - return; - } - - // Require auth for every page other than Login - // TODO: investigate /__nuxt_error (error page when unauthenticated) - if (!session.data.userId) { - return sendRedirect(event, '/login', 302); - } - - if (url.pathname.startsWith('/admin')) { - const user = await Database.user.findById(session.data.userId); - if (!user) { - return sendRedirect(event, '/login', 302); - } - if (user.role !== 'ADMIN') { - throw createError({ - statusCode: 403, - statusMessage: 'Not allowed to access Admin Panel', - }); - } - } -}); diff --git a/src/server/middleware/session.ts b/src/server/middleware/session.ts deleted file mode 100644 index 92286515..00000000 --- a/src/server/middleware/session.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { User } from '~~/services/database/repositories/user'; - -export default defineEventHandler(async (event) => { - const url = getRequestURL(event); - // If one method of a route is public, every method is public! - // Handle api routes - if ( - !url.pathname.startsWith('/api/') || - url.pathname.startsWith('/api/setup/') || - url.pathname === '/api/session' || - url.pathname === '/api/release' - ) { - return; - } - const system = await Database.system.get(); - - const session = await getSession(event, system.sessionConfig); - const authorization = getHeader(event, 'Authorization'); - - let user: User | undefined = undefined; - if (session.data.userId) { - // Handle if authenticating using Session - user = await Database.user.findById(session.data.userId); - } else if (authorization) { - // Handle if authenticating using Header - const [method, value] = authorization.split(' '); - // Support Basic Authentication - // TODO: support personal access token or similar - if (method !== 'Basic' || !value) { - throw createError({ - statusCode: 401, - statusMessage: 'Session failed', - }); - } - - const basicValue = Buffer.from(value, 'base64').toString('utf-8'); - - // Split by first ":" - const index = basicValue.indexOf(':'); - const username = basicValue.substring(0, index); - const password = basicValue.substring(index + 1); - - if (!username || !password) { - throw createError({ - statusCode: 401, - statusMessage: 'Session failed', - }); - } - - const users = await Database.user.findAll(); - const foundUser = users.find((v) => v.username === username); - - if (!foundUser) { - throw createError({ - statusCode: 401, - statusMessage: 'Session failed', - }); - } - - const userHashPassword = foundUser.password; - const passwordValid = await isPasswordValid(password, userHashPassword); - - if (!passwordValid) { - throw createError({ - statusCode: 401, - statusMessage: 'Incorrect Password', - }); - } - user = foundUser; - } - - if (!user) { - throw createError({ - statusCode: 401, - statusMessage: 'Not logged in', - }); - } - - if (!user.enabled) { - throw createError({ - statusCode: 403, - statusMessage: 'Account is disabled', - }); - } - - if (url.pathname.startsWith('/api/admin')) { - if (user.role !== 'ADMIN') { - throw createError({ - statusCode: 403, - statusMessage: 'Missing Permissions', - }); - } - } -}); diff --git a/src/server/middleware/setup.ts b/src/server/middleware/setup.ts index 78a86858..9cda7b15 100644 --- a/src/server/middleware/setup.ts +++ b/src/server/middleware/setup.ts @@ -7,14 +7,14 @@ export default defineEventHandler(async (event) => { return; } - const setupDone = await Database.setup.done(); - if (!setupDone) { + const { step, done } = await Database.general.getSetupStep(); + if (!done) { const parsedSetup = url.pathname.match(/\/setup\/(\d)/); if (!parsedSetup) { return sendRedirect(event, `/setup/1`, 302); } const [_, currentSetup] = parsedSetup; - const step = await Database.setup.get(); + if (step.toString() === currentSetup) { return; } diff --git a/src/server/routes/cnf/[oneTimeLink].ts b/src/server/routes/cnf/[oneTimeLink].ts index 9afbeed3..1b7c695b 100644 --- a/src/server/routes/cnf/[oneTimeLink].ts +++ b/src/server/routes/cnf/[oneTimeLink].ts @@ -1,7 +1,9 @@ +import { OneTimeLinkGetSchema } from '#db/repositories/oneTimeLink/types'; + export default defineEventHandler(async (event) => { const { oneTimeLink } = await getValidatedRouterParams( event, - validateZod(oneTimeLinkType) + validateZod(OneTimeLinkGetSchema) ); const clients = await WireGuard.getClients(); const client = clients.find( @@ -15,7 +17,7 @@ export default defineEventHandler(async (event) => { } const clientId = client.id; const config = await WireGuard.getClientConfiguration({ clientId }); - await WireGuard.eraseOneTimeLink({ clientId }); + await Database.oneTimeLinks.erase(clientId); setHeader( event, 'Content-Disposition', diff --git a/src/server/routes/metrics/index.get.ts b/src/server/routes/metrics/index.get.ts index 6cd0d46d..427e84ec 100644 --- a/src/server/routes/metrics/index.get.ts +++ b/src/server/routes/metrics/index.get.ts @@ -1,8 +1,8 @@ export default defineEventHandler(async (event) => { // TODO: check password - const system = await Database.system.get(); - if (!system.metrics.prometheus.enabled) { + const prometheus = await Database.metrics.prometheus.get('wg0'); + if (!prometheus) { throw createError({ statusCode: 400, message: 'Prometheus metrics are not enabled', @@ -10,5 +10,5 @@ export default defineEventHandler(async (event) => { } setHeader(event, 'Content-Type', 'text/plain'); - return WireGuard.getMetrics(); + return getPrometheusResponse(); }); diff --git a/src/server/routes/metrics/json.get.ts b/src/server/routes/metrics/json.get.ts index eaef7024..d9211241 100644 --- a/src/server/routes/metrics/json.get.ts +++ b/src/server/routes/metrics/json.get.ts @@ -1,13 +1,13 @@ export default defineEventHandler(async () => { // TODO: check password - const system = await Database.system.get(); - if (!system.metrics.prometheus.enabled) { + const prometheus = await Database.metrics.prometheus.get('wg0'); + if (!prometheus) { throw createError({ statusCode: 400, message: 'Prometheus metrics are not enabled', }); } - return WireGuard.getMetricsJSON(); + return getMetricsJSON(); }); diff --git a/src/server/utils/Database.ts b/src/server/utils/Database.ts index 791b9d15..297eba2c 100644 --- a/src/server/utils/Database.ts +++ b/src/server/utils/Database.ts @@ -2,8 +2,7 @@ * Changing the Database Provider * This design allows for easy swapping of different database implementations. */ - -import LowDb from '~~/services/database/lowdb'; +import { connect, type DBServiceType } from '#db/sqlite'; const nullObject = new Proxy( {}, @@ -15,10 +14,10 @@ const nullObject = new Proxy( ); // eslint-disable-next-line import/no-mutable-exports -let provider = nullObject as never as LowDb; +let provider = nullObject as never as DBServiceType; -LowDb.connect().then((v) => { - provider = v; +connect().then((db) => { + provider = db; WireGuard.Startup(); }); diff --git a/src/server/utils/WireGuard.ts b/src/server/utils/WireGuard.ts index 02427ad5..86cd338e 100644 --- a/src/server/utils/WireGuard.ts +++ b/src/server/utils/WireGuard.ts @@ -1,69 +1,58 @@ import fs from 'node:fs/promises'; import debug from 'debug'; import QRCode from 'qrcode'; -import CRC32 from 'crc-32'; -import isCidr from 'is-cidr'; +import type { ID } from '#db/schema'; -import type { - CreateClient, - UpdateClient, -} from '~~/services/database/repositories/client'; - -const DEBUG = debug('WireGuard'); +const WG_DEBUG = debug('WireGuard'); class WireGuard { /** * Save and sync config */ async saveConfig() { - await this.#saveWireguardConfig(); - await this.#syncWireguardConfig(); + await this.#saveWireguardConfig('wg0'); + await this.#syncWireguardConfig('wg0'); } /** * Generates and saves WireGuard config from database as wg0 */ - async #saveWireguardConfig() { - const system = await Database.system.get(); - const clients = await Database.client.findAll(); + async #saveWireguardConfig(infName: string) { + const wgInterface = await Database.interfaces.get(infName); + const clients = await Database.clients.getAll(); + const hooks = await Database.hooks.get(infName); + + if (!wgInterface || !hooks) { + throw new Error('Interface or Hooks not found'); + } + const result = []; - result.push(wg.generateServerInterface(system)); + result.push(wg.generateServerInterface(wgInterface, hooks)); - for (const client of Object.values(clients)) { + for (const client of clients) { if (!client.enabled) { continue; } result.push(wg.generateServerPeer(client)); } - DEBUG('Saving Config...'); - await fs.writeFile('/etc/wireguard/wg0.conf', result.join('\n\n'), { + WG_DEBUG('Saving Config...'); + await fs.writeFile(`/etc/wireguard/${infName}.conf`, result.join('\n\n'), { mode: 0o600, }); - DEBUG('Config saved successfully.'); + WG_DEBUG('Config saved successfully.'); } - async #syncWireguardConfig() { - DEBUG('Syncing Config...'); - await wg.sync(); - DEBUG('Config synced successfully.'); + async #syncWireguardConfig(infName: string) { + WG_DEBUG('Syncing Config...'); + await wg.sync(infName); + WG_DEBUG('Config synced successfully.'); } async getClients() { - const dbClients = await Database.client.findAll(); - const clients = Object.entries(dbClients).map(([clientId, client]) => ({ - id: clientId, - name: client.name, - enabled: client.enabled, - address4: client.address4, - address6: client.address6, - publicKey: client.publicKey, - createdAt: new Date(client.createdAt), - updatedAt: new Date(client.updatedAt), - expiresAt: client.expiresAt, - allowedIps: client.allowedIps, - oneTimeLink: client.oneTimeLink, - persistentKeepalive: null as string | null, + const dbClients = await Database.clients.getAll(); + const clients = dbClients.map((client) => ({ + ...client, latestHandshakeAt: null as Date | null, endpoint: null as string | null, transferRx: null as number | null, @@ -71,16 +60,9 @@ class WireGuard { })); // Loop WireGuard status - const dump = await wg.dump(); + const dump = await wg.dump('wg0'); dump.forEach( - ({ - publicKey, - latestHandshakeAt, - endpoint, - transferRx, - transferTx, - persistentKeepalive, - }) => { + ({ publicKey, latestHandshakeAt, endpoint, transferRx, transferTx }) => { const client = clients.find((client) => client.publicKey === publicKey); if (!client) { return; @@ -90,33 +72,30 @@ class WireGuard { client.endpoint = endpoint; client.transferRx = transferRx; client.transferTx = transferTx; - client.persistentKeepalive = persistentKeepalive; } ); return clients; } - async getClient({ clientId }: { clientId: string }) { - const client = await Database.client.findById(clientId); - if (!client) { - throw createError({ - statusCode: 404, - statusMessage: `Client Not Found: ${clientId}`, - }); + async getClientConfiguration({ clientId }: { clientId: ID }) { + const wgInterface = await Database.interfaces.get('wg0'); + const userConfig = await Database.userConfigs.get('wg0'); + + if (!wgInterface || !userConfig) { + throw new Error('Interface or UserConfig not found'); } - return client; - } + const client = await Database.clients.get(clientId); - async getClientConfiguration({ clientId }: { clientId: string }) { - const system = await Database.system.get(); - const client = await this.getClient({ clientId }); + if (!client) { + throw new Error('Client not found'); + } - return wg.generateClientConfig(system, client); + return wg.generateClientConfig(wgInterface, userConfig, client); } - async getClientQRCodeSVG({ clientId }: { clientId: string }) { + async getClientQRCodeSVG({ clientId }: { clientId: ID }) { const config = await this.getClientConfiguration({ clientId }); return QRCode.toString(config, { type: 'svg', @@ -124,134 +103,6 @@ class WireGuard { }); } - async createClient({ - name, - expireDate, - }: { - name: string; - expireDate: string | null; - }) { - const system = await Database.system.get(); - const clients = await Database.client.findAll(); - - const privateKey = await wg.generatePrivateKey(); - const publicKey = await wg.getPublicKey(privateKey); - const preSharedKey = await wg.generatePresharedKey(); - - const address4 = nextIPv4(system, clients); - - const address6 = nextIPv6(system, clients); - - const client: CreateClient = { - name, - address4, - address6, - privateKey, - publicKey, - preSharedKey, - oneTimeLink: null, - expiresAt: null, - enabled: true, - allowedIps: [...system.userConfig.allowedIps], - serverAllowedIPs: [], - persistentKeepalive: system.userConfig.persistentKeepalive, - mtu: system.userConfig.mtu, - }; - - if (expireDate) { - const date = new Date(expireDate); - date.setHours(23); - date.setMinutes(59); - date.setSeconds(59); - client.expiresAt = date.toISOString(); - } - - await Database.client.create(client); - - await this.saveConfig(); - - return client; - } - - async deleteClient({ clientId }: { clientId: string }) { - await Database.client.delete(clientId); - await this.saveConfig(); - } - - async enableClient({ clientId }: { clientId: string }) { - await Database.client.toggle(clientId, true); - - await this.saveConfig(); - } - - async generateOneTimeLink({ clientId }: { clientId: string }) { - const key = `${clientId}-${Math.floor(Math.random() * 1000)}`; - const oneTimeLink = Math.abs(CRC32.str(key)).toString(16); - const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString(); - await Database.client.createOneTimeLink(clientId, { - oneTimeLink, - expiresAt, - }); - await this.saveConfig(); - } - - async eraseOneTimeLink({ clientId }: { clientId: string }) { - await Database.client.deleteOneTimeLink(clientId); - await this.saveConfig(); - } - - async disableClient({ clientId }: { clientId: string }) { - await Database.client.toggle(clientId, false); - - await this.saveConfig(); - } - - async updateClient({ - clientId, - client, - }: { - clientId: string; - client: UpdateClient; - }) { - // TODO: validate ipv4, v6, expire date etc - await Database.client.update(clientId, client); - await this.saveConfig(); - } - - async updateAddressRange({ - address4, - address6, - }: { - address4: string; - address6: string; - }) { - // TODO: be able to revert if error - - if (!isCidr(address4) || !isCidr(address6)) { - throw new Error('Invalid CIDR'); - } - - await Database.system.updateAddressRange(address4, address6); - - const systems = await Database.system.get(); - const clients = await Database.client.findAll(); - - for (const _client of Object.values(clients)) { - const clients = await Database.client.findAll(); - - const client = structuredClone(_client) as DeepWriteable; - - client.address4 = nextIPv4(systems, clients); - client.address6 = nextIPv6(systems, clients); - - await Database.client.update(client.id, { - ...client, - }); - } - - await this.saveConfig(); - } - // TODO: reimplement database restore async restoreConfiguration(_config: string) { /* DEBUG('Starting configuration restore process.'); @@ -272,35 +123,58 @@ class WireGuard { } async Startup() { - DEBUG('Starting Wireguard...'); - await this.#saveWireguardConfig(); - await wg.down().catch(() => {}); - await wg.up().catch((err) => { + WG_DEBUG('Starting WireGuard...'); + const wgInterfaces = await Database.interfaces.getAll(); + for (const wgInterface of wgInterfaces) { + if (wgInterface.enabled !== true) { + continue; + } + // default interface has no keys if ( - err && - err.message && - err.message.includes('Cannot find device "wg0"') + wgInterface.privateKey === '---default---' && + wgInterface.publicKey === '---default---' ) { - throw new Error( - 'WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!' + WG_DEBUG('Generating new Wireguard Keys...'); + const privateKey = await wg.generatePrivateKey(); + const publicKey = await wg.getPublicKey(privateKey); + + await Database.interfaces.updateKeyPair( + wgInterface.name, + privateKey, + publicKey ); + WG_DEBUG('New Wireguard Keys generated successfully.'); } + WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`); + await this.#saveWireguardConfig(wgInterface.name); + await wg.down(wgInterface.name).catch(() => {}); + await wg.up(wgInterface.name).catch((err) => { + if ( + err && + err.message && + err.message.includes(`Cannot find device "${wgInterface.name}"`) + ) { + throw new Error( + `WireGuard exited with the error: Cannot find device "${wgInterface.name}"\nThis usually means that your host's kernel does not support WireGuard!`, + { cause: err.message } + ); + } - throw err; - }); - await this.#syncWireguardConfig(); - DEBUG('Wireguard started successfully.'); + throw err; + }); + await this.#syncWireguardConfig(wgInterface.name); + WG_DEBUG(`Wireguard Interface ${wgInterface.name} started successfully.`); + } - DEBUG('Starting Cron Job.'); + WG_DEBUG('Starting Cron Job...'); await this.startCronJob(); - DEBUG('Cron Job started successfully.'); + WG_DEBUG('Cron Job started successfully.'); } // TODO: handle as worker_thread - // would need a better database aswell async startCronJob() { await this.cronJob().catch((err) => { - DEBUG('Running Cron Job failed.'); + WG_DEBUG('Running Cron Job failed.'); console.error(err); }); setTimeout(() => { @@ -310,109 +184,39 @@ class WireGuard { // Shutdown wireguard async Shutdown() { - await wg.down().catch(() => {}); + const wgInterfaces = await Database.interfaces.getAll(); + for (const wgInterface of wgInterfaces) { + await wg.down(wgInterface.name).catch(() => {}); + } } async cronJob() { - const clients = await Database.client.findAll(); + const clients = await Database.clients.getAll(); // Expires Feature - for (const client of Object.values(clients)) { + for (const client of clients) { if (client.enabled !== true) continue; if ( client.expiresAt !== null && new Date() > new Date(client.expiresAt) ) { - DEBUG(`Client ${client.id} expired.`); - await Database.client.toggle(client.id, false); + WG_DEBUG(`Client ${client.id} expired.`); + await Database.clients.toggle(client.id, false); } } // One Time Link Feature - for (const client of Object.values(clients)) { + for (const client of clients) { if ( client.oneTimeLink !== null && new Date() > new Date(client.oneTimeLink.expiresAt) ) { - DEBUG(`Client ${client.id} One Time Link expired.`); - await Database.client.deleteOneTimeLink(client.id); + WG_DEBUG(`Client ${client.id} One Time Link expired.`); + await Database.oneTimeLinks.delete(client.id); } } await this.saveConfig(); } - - async getMetrics() { - const clients = await this.getClients(); - let wireguardPeerCount = 0; - let wireguardEnabledPeersCount = 0; - let wireguardConnectedPeersCount = 0; - let wireguardSentBytes = ''; - let wireguardReceivedBytes = ''; - let wireguardLatestHandshakeSeconds = ''; - for (const client of Object.values(clients)) { - wireguardPeerCount++; - if (client.enabled === true) { - wireguardEnabledPeersCount++; - } - if (client.endpoint !== null) { - wireguardConnectedPeersCount++; - } - wireguardSentBytes += `wireguard_sent_bytes{interface="wg0",enabled="${client.enabled}",address4="${client.address4}",address6="${client.address6}",name="${client.name}"} ${Number(client.transferTx)}\n`; - wireguardReceivedBytes += `wireguard_received_bytes{interface="wg0",enabled="${client.enabled}",address4="${client.address4}",address6="${client.address6}",name="${client.name}"} ${Number(client.transferRx)}\n`; - wireguardLatestHandshakeSeconds += `wireguard_latest_handshake_seconds{interface="wg0",enabled="${client.enabled}",address4="${client.address4}",address6="${client.address6}",name="${client.name}"} ${client.latestHandshakeAt ? (new Date().getTime() - new Date(client.latestHandshakeAt).getTime()) / 1000 : 0}\n`; - } - - let returnText = '# HELP wg-easy and wireguard metrics\n'; - - returnText += '\n# HELP wireguard_configured_peers\n'; - returnText += '# TYPE wireguard_configured_peers gauge\n'; - returnText += `wireguard_configured_peers{interface="wg0"} ${wireguardPeerCount}\n`; - - returnText += '\n# HELP wireguard_enabled_peers\n'; - returnText += '# TYPE wireguard_enabled_peers gauge\n'; - returnText += `wireguard_enabled_peers{interface="wg0"} ${wireguardEnabledPeersCount}\n`; - - returnText += '\n# HELP wireguard_connected_peers\n'; - returnText += '# TYPE wireguard_connected_peers gauge\n'; - returnText += `wireguard_connected_peers{interface="wg0"} ${wireguardConnectedPeersCount}\n`; - - returnText += '\n# HELP wireguard_sent_bytes Bytes sent to the peer\n'; - returnText += '# TYPE wireguard_sent_bytes counter\n'; - returnText += `${wireguardSentBytes}`; - - returnText += - '\n# HELP wireguard_received_bytes Bytes received from the peer\n'; - returnText += '# TYPE wireguard_received_bytes counter\n'; - returnText += `${wireguardReceivedBytes}`; - - returnText += - '\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n'; - returnText += '# TYPE wireguard_latest_handshake_seconds gauge\n'; - returnText += `${wireguardLatestHandshakeSeconds}`; - - return returnText; - } - - async getMetricsJSON() { - const clients = await this.getClients(); - let wireguardPeerCount = 0; - let wireguardEnabledPeersCount = 0; - let wireguardConnectedPeersCount = 0; - for (const client of Object.values(clients)) { - wireguardPeerCount++; - if (client.enabled === true) { - wireguardEnabledPeersCount++; - } - if (client.endpoint !== null) { - wireguardConnectedPeersCount++; - } - } - return { - wireguard_configured_peers: wireguardPeerCount, - wireguard_enabled_peers: wireguardEnabledPeersCount, - wireguard_connected_peers: wireguardConnectedPeersCount, - }; - } } export default new WireGuard(); diff --git a/src/server/utils/cmd.ts b/src/server/utils/cmd.ts index 578e4cce..6fd4ad9b 100644 --- a/src/server/utils/cmd.ts +++ b/src/server/utils/cmd.ts @@ -1,13 +1,16 @@ import childProcess from 'child_process'; +import debug from 'debug'; + +const CMD_DEBUG = debug('CMD'); export function exec( cmd: string, { log }: { log: boolean | string } = { log: true } ) { if (typeof log === 'string') { - console.log(`$ ${log}`); + CMD_DEBUG(`$ ${log}`); } else if (log === true) { - console.log(`$ ${cmd}`); + CMD_DEBUG(`$ ${cmd}`); } if (process.platform !== 'linux') { diff --git a/src/server/utils/crypto.ts b/src/server/utils/crypto.ts deleted file mode 100644 index 51775001..00000000 --- a/src/server/utils/crypto.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function getRandomHex(size: number) { - const array = new Uint8Array(size); - crypto.getRandomValues(array); - return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join( - '' - ); -} diff --git a/src/server/utils/handler.ts b/src/server/utils/handler.ts new file mode 100644 index 00000000..754bb8d3 --- /dev/null +++ b/src/server/utils/handler.ts @@ -0,0 +1,59 @@ +import type { EventHandlerRequest, EventHandlerResponse, H3Event } from 'h3'; +import type { UserType } from '#db/repositories/user/types'; +import type { SetupStepType } from '../database/repositories/general/types'; + +type PermissionHandler< + TReq extends EventHandlerRequest, + TRes extends EventHandlerResponse, +> = { (params: { event: H3Event; user: UserType }): TRes }; + +/** + * check if the user has the permission to perform the action + */ +export const definePermissionEventHandler = < + TReq extends EventHandlerRequest, + TRes extends EventHandlerResponse, +>( + action: Action, + handler: PermissionHandler +) => { + return defineEventHandler(async (event) => { + const user = await getCurrentUser(event); + if (!checkPermissions(action, user)) { + throw createError({ + statusCode: 403, + statusMessage: 'Forbidden', + }); + } + + return await handler({ event, user }); + }); +}; + +type SetupHandler< + TReq extends EventHandlerRequest, + TRes extends EventHandlerResponse, +> = { (params: { event: H3Event; setup: SetupStepType }): TRes }; + +/** + * check if the setup is done, if not, run the handler + */ +export const defineSetupEventHandler = < + TReq extends EventHandlerRequest, + TRes extends EventHandlerResponse, +>( + handler: SetupHandler +) => { + return defineEventHandler(async (event) => { + const setup = await Database.general.getSetupStep(); + + if (setup.done) { + throw createError({ + statusCode: 400, + statusMessage: 'Invalid state', + }); + } + + return await handler({ event, setup }); + }); +}; diff --git a/src/server/utils/ip.ts b/src/server/utils/ip.ts index a2d66e86..0a5bb3dc 100644 --- a/src/server/utils/ip.ts +++ b/src/server/utils/ip.ts @@ -1,36 +1,20 @@ -import { parseCidr } from 'cidr-tools'; +import type { parseCidr } from 'cidr-tools'; import { stringifyIp } from 'ip-bigint'; -import type { DeepReadonly } from 'vue'; -import type { Database } from '~~/services/database/repositories/database'; -export function nextIPv4( - system: DeepReadonly, - clients: DeepReadonly -) { - return nextIP(4, system, clients); -} - -export function nextIPv6( - system: DeepReadonly, - clients: DeepReadonly -) { - return nextIP(6, system, clients); -} +import type { ClientType } from '#db/repositories/client/types'; -// TODO: above functions should probably have a lock -// TODO(general): what happens if multiple users create client at the same time? +type ParsedCidr = ReturnType; -function nextIP( +export function nextIP( version: 4 | 6, - system: DeepReadonly, - clients: DeepReadonly + cidr: ParsedCidr, + clients: ClientType[] ) { - const cidr = parseCidr(system.userConfig[`address${version}Range`]); let address; for (let i = cidr.start + 2n; i <= cidr.end - 1n; i++) { const currentIp = stringifyIp({ number: i, version: version }); - const client = Object.values(clients).find((client) => { - return client[`address${version}`] === currentIp; + const client = clients.find((client) => { + return client[`ipv${version}Address`] === currentIp; }); if (!client) { @@ -40,10 +24,8 @@ function nextIP( } if (!address) { - throw createError({ - statusCode: 409, - statusMessage: 'Maximum number of clients reached.', - data: { cause: `IPv${version} Address Pool exhausted` }, + throw new Error('Maximum number of clients reached', { + cause: `IPv${version} Address Pool exhausted`, }); } diff --git a/src/server/utils/metrics.ts b/src/server/utils/metrics.ts new file mode 100644 index 00000000..9c007c66 --- /dev/null +++ b/src/server/utils/metrics.ts @@ -0,0 +1,74 @@ +// TODO: rewrite + +export async function getPrometheusResponse() { + const clients = await WireGuard.getClients(); + let wireguardPeerCount = 0; + let wireguardEnabledPeersCount = 0; + let wireguardConnectedPeersCount = 0; + let wireguardSentBytes = ''; + let wireguardReceivedBytes = ''; + let wireguardLatestHandshakeSeconds = ''; + for (const client of clients) { + wireguardPeerCount++; + if (client.enabled === true) { + wireguardEnabledPeersCount++; + } + if (client.endpoint !== null) { + wireguardConnectedPeersCount++; + } + wireguardSentBytes += `wireguard_sent_bytes{interface="wg0",enabled="${client.enabled}",ipv4Address="${client.ipv4Address}",ipv6Address="${client.ipv6Address}",name="${client.name}"} ${Number(client.transferTx)}\n`; + wireguardReceivedBytes += `wireguard_received_bytes{interface="wg0",enabled="${client.enabled}",ipv4Address="${client.ipv4Address}",ipv6Address="${client.ipv6Address}",name="${client.name}"} ${Number(client.transferRx)}\n`; + wireguardLatestHandshakeSeconds += `wireguard_latest_handshake_seconds{interface="wg0",enabled="${client.enabled}",ipv4Address="${client.ipv4Address}",ipv6Address="${client.ipv6Address}",name="${client.name}"} ${client.latestHandshakeAt ? (new Date().getTime() - new Date(client.latestHandshakeAt).getTime()) / 1000 : 0}\n`; + } + + let returnText = '# HELP wg-easy and wireguard metrics\n'; + + returnText += '\n# HELP wireguard_configured_peers\n'; + returnText += '# TYPE wireguard_configured_peers gauge\n'; + returnText += `wireguard_configured_peers{interface="wg0"} ${wireguardPeerCount}\n`; + + returnText += '\n# HELP wireguard_enabled_peers\n'; + returnText += '# TYPE wireguard_enabled_peers gauge\n'; + returnText += `wireguard_enabled_peers{interface="wg0"} ${wireguardEnabledPeersCount}\n`; + + returnText += '\n# HELP wireguard_connected_peers\n'; + returnText += '# TYPE wireguard_connected_peers gauge\n'; + returnText += `wireguard_connected_peers{interface="wg0"} ${wireguardConnectedPeersCount}\n`; + + returnText += '\n# HELP wireguard_sent_bytes Bytes sent to the peer\n'; + returnText += '# TYPE wireguard_sent_bytes counter\n'; + returnText += `${wireguardSentBytes}`; + + returnText += + '\n# HELP wireguard_received_bytes Bytes received from the peer\n'; + returnText += '# TYPE wireguard_received_bytes counter\n'; + returnText += `${wireguardReceivedBytes}`; + + returnText += + '\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n'; + returnText += '# TYPE wireguard_latest_handshake_seconds gauge\n'; + returnText += `${wireguardLatestHandshakeSeconds}`; + + return returnText; +} + +export async function getMetricsJSON() { + const clients = await WireGuard.getClients(); + let wireguardPeerCount = 0; + let wireguardEnabledPeersCount = 0; + let wireguardConnectedPeersCount = 0; + for (const client of clients) { + wireguardPeerCount++; + if (client.enabled === true) { + wireguardEnabledPeersCount++; + } + if (client.endpoint !== null) { + wireguardConnectedPeersCount++; + } + } + return { + wireguard_configured_peers: wireguardPeerCount, + wireguard_enabled_peers: wireguardEnabledPeersCount, + wireguard_connected_peers: wireguardConnectedPeersCount, + }; +} diff --git a/src/server/utils/session.ts b/src/server/utils/session.ts index 1058f9cc..d15f9755 100644 --- a/src/server/utils/session.ts +++ b/src/server/utils/session.ts @@ -1,10 +1,103 @@ import type { H3Event } from 'h3'; +import type { ID } from '#db/schema'; +import type { UserType } from '#db/repositories/user/types'; export type WGSession = Partial<{ - userId: string; + userId: ID; }>; -export async function useWGSession(event: H3Event) { - const system = await Database.system.get(); - return useSession(event, system.sessionConfig); +const name = 'wg-easy'; + +export async function useWGSession(event: H3Event, rememberMe = false) { + const sessionConfig = await Database.general.getSessionConfig(); + return useSession(event, { + password: sessionConfig.sessionPassword, + name, + cookie: { maxAge: rememberMe ? sessionConfig.sessionTimeout : undefined }, + }); +} + +export async function getWGSession(event: H3Event) { + const sessionConfig = await Database.general.getSessionConfig(); + return getSession(event, { + password: sessionConfig.sessionPassword, + name, + cookie: {}, + }); +} + +/** + * @throws + */ +export async function getCurrentUser(event: H3Event) { + const session = await getWGSession(event); + + const authorization = getHeader(event, 'Authorization'); + + let user: UserType | undefined = undefined; + if (session.data.userId) { + // Handle if authenticating using Session + user = await Database.users.get(session.data.userId); + } else if (authorization) { + // Handle if authenticating using Header + const [method, value] = authorization.split(' '); + // Support Basic Authentication + // TODO: support personal access token or similar + if (method !== 'Basic' || !value) { + throw createError({ + statusCode: 401, + statusMessage: 'Session failed', + }); + } + + const basicValue = Buffer.from(value, 'base64').toString('utf-8'); + + // Split by first ":" + const index = basicValue.indexOf(':'); + const username = basicValue.substring(0, index); + const password = basicValue.substring(index + 1); + + if (!username || !password) { + throw createError({ + statusCode: 401, + statusMessage: 'Session failed', + }); + } + + const foundUser = await Database.users.getByUsername(username); + + if (!foundUser) { + throw createError({ + statusCode: 401, + statusMessage: 'Session failed', + }); + } + + const userHashPassword = foundUser.password; + const passwordValid = await isPasswordValid(password, userHashPassword); + + if (!passwordValid) { + throw createError({ + statusCode: 401, + statusMessage: 'Incorrect Password', + }); + } + user = foundUser; + } + + if (!user) { + throw createError({ + statusCode: 401, + statusMessage: 'Session failed. User not found', + }); + } + + if (!user.enabled) { + throw createError({ + statusCode: 403, + statusMessage: 'User is disabled', + }); + } + + return user; } diff --git a/src/server/utils/template.ts b/src/server/utils/template.ts index fb5e06ac..43fc6927 100644 --- a/src/server/utils/template.ts +++ b/src/server/utils/template.ts @@ -1,5 +1,4 @@ -import type { DeepReadonly } from 'vue'; -import type { System } from '~~/services/database/repositories/system'; +import type { InterfaceType } from '#db/repositories/interface/types'; /** * Replace all {{key}} in the template with the values[key] @@ -12,16 +11,16 @@ export function template(templ: string, values: Record) { /** * Available keys: - * - address4: IPv4 address range - * - address6: IPv6 address range + * - ipv4Cidr: IPv4 CIDR + * - ipv6Cidr: IPv6 CIDR * - device: Network device * - port: Port number */ -export function iptablesTemplate(templ: string, system: DeepReadonly) { +export function iptablesTemplate(templ: string, wgInterface: InterfaceType) { return template(templ, { - address4: system.userConfig.address4Range, - address6: system.userConfig.address6Range, - device: system.interface.device, - port: system.interface.port.toString(), + ipv4Cidr: wgInterface.ipv4Cidr, + ipv6Cidr: wgInterface.ipv6Cidr, + device: wgInterface.device, + port: wgInterface.port.toString(), }); } diff --git a/src/server/utils/types.ts b/src/server/utils/types.ts index 00474854..41607b52 100644 --- a/src/server/utils/types.ts +++ b/src/server/utils/types.ts @@ -1,220 +1,57 @@ -import type { ZodSchema, ZodTypeDef } from 'zod'; -import { z, ZodError } from 'zod'; +import type { ZodSchema } from 'zod'; +import z from 'zod'; import type { H3Event, EventHandlerRequest } from 'h3'; -const objectMessage = 'zod.body'; +export const objectMessage = 'zod.body'; -const safeStringRefine = z +export const safeStringRefine = z .string() .refine( (v) => v !== '__proto__' && v !== 'constructor' && v !== 'prototype', { message: 'zod.stringMalformed' } ); -const host = z - .string({ message: 'zod.host' }) - .min(1, 'zod.hostMin') - .pipe(safeStringRefine); - -const port = z - .number({ message: 'zod.port' }) - .min(1, 'zod.portMin') - .max(65535, 'zod.portMax'); - -export const hostPortType = z.object({ - host: host, - port: port, -}); - -const id = z.string().uuid('zod.id').pipe(safeStringRefine); - -export const clientIdType = z.object( - { - clientId: id, - }, - { message: objectMessage } -); - -const oneTimeLink = z - .string({ message: 'zod.otl' }) - .min(1, 'zod.otlMin') - .pipe(safeStringRefine); +// TODO: create custom getValidatedRouterParams and readValidatedBody wrapper -export const oneTimeLinkType = z.object( - { - oneTimeLink: oneTimeLink, - }, - { message: objectMessage } -); - -const name = z - .string({ message: 'zod.name' }) - .min(1, 'zod.nameMin') - .pipe(safeStringRefine); - -const expireDate = z - .string({ message: 'zod.expireDate' }) - .min(1, 'zod.expireDateMin') - .pipe(safeStringRefine) - .nullable(); - -export const createType = z.object( - { - name: name, - expireDate: expireDate, - }, - { message: objectMessage } -); - -const file = z.string({ message: 'zod.file' }).pipe(safeStringRefine); -const file_ = z.instanceof(File, { message: 'zod.file' }); - -export const fileType = z.object( - { - file: file, - }, - { message: objectMessage } -); -export const fileType_ = z.object( - { - file: file_, - }, - { message: objectMessage } -); - -const username = z - .string({ message: 'zod.username' }) - .min(8, 'zod.usernameMin') - .pipe(safeStringRefine); +export const EnabledSchema = z.boolean({ message: 'zod.enabled' }); -const password = z - .string({ message: 'zod.password' }) - .min(12, 'zod.passwordMin') - .regex(/[A-Z]/, 'zod.passwordUppercase') - .regex(/[a-z]/, 'zod.passwordLowercase') - .regex(/\d/, 'zod.passwordNumber') - .regex(/[!@#$%^&*(),.?":{}|<>]/, 'zod.passwordSpecial') - .pipe(safeStringRefine); - -const remember = z.boolean({ message: 'zod.remember' }); - -export const credentialsType = z.object( - { - username: username, - password: password, - remember: remember, - }, - { message: objectMessage } -); - -export const passwordType = z.object( - { - username: username, - password: password, - }, - { message: objectMessage } -); - -const accept = z.boolean().refine((val) => val === true, { - message: 'zod.accept', -}); - -export const passwordSetupType = z.object( - { - username: username, - password: password, - accept: accept, - }, - { message: objectMessage } -); - -const address = z - .string({ message: 'zod.address' }) - .min(1, { message: 'zod.addressMin' }) - .pipe(safeStringRefine); - -const address4 = z - .string({ message: 'zod.address4' }) - .min(1, { message: 'zod.address4Min' }) - .pipe(safeStringRefine); - -const address6 = z - .string({ message: 'zod.address6' }) - .min(1, { message: 'zod.address6Min' }) - .pipe(safeStringRefine); - -const allowedIps = z - .array(address, { message: 'zod.allowedIps' }) - .min(1, { message: 'zod.allowedIpsMin' }); - -const mtu = z +export const MtuSchema = z .number({ message: 'zod.mtu' }) .min(1280, { message: 'zod.mtuMin' }) .max(9000, { message: 'zod.mtuMax' }); -const persistentKeepalive = z +export const PortSchema = z + .number({ message: 'zod.port' }) + .min(1, { message: 'zod.portMin' }) + .max(65535, { message: 'zod.portMax' }); + +export const PersistentKeepaliveSchema = z .number({ message: 'zod.persistentKeepalive' }) .min(0, 'zod.persistentKeepaliveMin') .max(65535, 'zod.persistentKeepaliveMax'); -export const clientUpdateType = z.object({ - name: name, - enabled: z.boolean(), - expiresAt: expireDate, - address4: address4, - address6: address6, - allowedIps: allowedIps, - serverAllowedIPs: z.array(address, { message: 'zod.serverAllowedIPs' }), - mtu: mtu, - persistentKeepalive: persistentKeepalive, -}); - -export const generalUpdateType = z.object({ - sessionTimeout: z.number({ message: 'zod.sessionTimeout' }), -}); - -const device = z - .string({ message: 'zod.device' }) - .min(1, 'zod.deviceMin') +export const AddressSchema = z + .string({ message: 'zod.address' }) + .min(1, { message: 'zod.addressMin' }) .pipe(safeStringRefine); -export const interfaceUpdateType = z.object({ - mtu: mtu, - port: port, - device: device, -}); - -export const userConfigUpdateType = z.object({ - host: host, - port: port, - allowedIps: allowedIps, - defaultDns: z.array(address, { message: 'zod.dns' }), - mtu: mtu, - persistentKeepalive: persistentKeepalive, -}); - -const hook = z.string({ message: 'zod.hook' }).pipe(safeStringRefine); - -export const hooksUpdateType = z.object({ - PreUp: hook, - PostUp: hook, - PreDown: hook, - PostDown: hook, -}); - -export const cidrUpdateType = z.object({ - address4: address, - address6: address, -}); - -// from https://github.com/airjp73/rvf/blob/7e7c35d98015ea5ecff5affaf89f78296e84e8b9/packages/zod-form-data/src/helpers.ts#L117 -type FormDataLikeInput = { - [Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>; - entries(): IterableIterator<[string, FormDataEntryValue]>; -}; +export const DnsSchema = z + .array(AddressSchema, { message: 'zod.dns' }) + .min(1, 'zod.dnsMin'); + +export const AllowedIpsSchema = z + .array(AddressSchema, { message: 'zod.allowedIps' }) + .min(1, { message: 'zod.allowedIpsMin' }); + +export const schemaForType = + () => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + >(arg: S) => { + return arg; + }; export function validateZod( - schema: ZodSchema | ZodSchema, + schema: ZodSchema, event?: H3Event ) { return async (data: unknown) => { @@ -228,7 +65,7 @@ export function validateZod( return await schema.parseAsync(data); } catch (error) { let message = 'Unexpected Error'; - if (error instanceof ZodError) { + if (error instanceof z.ZodError) { message = error.issues .map((v) => { let m = v.message; @@ -245,7 +82,3 @@ export function validateZod( } }; } - -export type DeepWriteable = { - -readonly [P in keyof T]: DeepWriteable; -}; diff --git a/src/server/utils/wgHelper.ts b/src/server/utils/wgHelper.ts index 76e3f049..42ac16af 100644 --- a/src/server/utils/wgHelper.ts +++ b/src/server/utils/wgHelper.ts @@ -1,16 +1,16 @@ import { parseCidr } from 'cidr-tools'; -import type { DeepReadonly } from 'vue'; -import type { Client } from '~~/services/database/repositories/client'; -import type { System } from '~~/services/database/repositories/system'; - -// TODO: replace wg0 with parameter (to allow multi interface design) +import type { ClientType } from '#db/repositories/client/types'; +import type { InterfaceType } from '#db/repositories/interface/types'; +import { stringifyIp } from 'ip-bigint'; +import type { UserConfigType } from '#db/repositories/userConfig/types'; +import type { HooksType } from '#db/repositories/hooks/types'; export const wg = { - generateServerPeer: (client: DeepReadonly) => { + generateServerPeer: (client: Omit) => { const allowedIps = [ - `${client.address4}/32`, - `${client.address6}/128`, - ...(client.serverAllowedIPs ?? []), + `${client.ipv4Address}/32`, + `${client.ipv6Address}/128`, + ...(client.serverAllowedIps ?? []), ]; return `# Client: ${client.name} (${client.id}) @@ -20,44 +20,47 @@ PresharedKey = ${client.preSharedKey} AllowedIPs = ${allowedIps.join(', ')}`; }, - generateServerInterface: (system: DeepReadonly) => { - const cidr4Block = parseCidr(system.userConfig.address4Range).prefix; - const cidr6Block = parseCidr(system.userConfig.address6Range).prefix; + generateServerInterface: (wgInterface: InterfaceType, hooks: HooksType) => { + const cidr4 = parseCidr(wgInterface.ipv4Cidr); + const cidr6 = parseCidr(wgInterface.ipv6Cidr); + const ipv4Addr = stringifyIp({ number: cidr4.start + 1n, version: 4 }); + const ipv6Addr = stringifyIp({ number: cidr6.start + 1n, version: 6 }); return `# Note: Do not edit this file directly. # Your changes will be overwritten! # Server [Interface] -PrivateKey = ${system.interface.privateKey} -Address = ${system.interface.address4}/${cidr4Block}, ${system.interface.address6}/${cidr6Block} -ListenPort = ${system.interface.port} -MTU = ${system.interface.mtu} -PreUp = ${iptablesTemplate(system.hooks.PreUp, system)} -PostUp = ${iptablesTemplate(system.hooks.PostUp, system)} -PreDown = ${iptablesTemplate(system.hooks.PreDown, system)} -PostDown = ${iptablesTemplate(system.hooks.PostDown, system)}`; +PrivateKey = ${wgInterface.privateKey} +Address = ${ipv4Addr}/${cidr4.prefix}, ${ipv6Addr}/${cidr6.prefix} +ListenPort = ${wgInterface.port} +MTU = ${wgInterface.mtu} +PreUp = ${iptablesTemplate(hooks.preUp, wgInterface)} +PostUp = ${iptablesTemplate(hooks.postUp, wgInterface)} +PreDown = ${iptablesTemplate(hooks.preDown, wgInterface)} +PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`; }, generateClientConfig: ( - system: DeepReadonly, - client: DeepReadonly + wgInterface: InterfaceType, + userConfig: UserConfigType, + client: ClientType ) => { - const cidr4Block = parseCidr(system.userConfig.address4Range).prefix; - const cidr6Block = parseCidr(system.userConfig.address6Range).prefix; + const cidr4Block = parseCidr(wgInterface.ipv4Cidr).prefix; + const cidr6Block = parseCidr(wgInterface.ipv6Cidr).prefix; return `[Interface] PrivateKey = ${client.privateKey} -Address = ${client.address4}/${cidr4Block}, ${client.address6}/${cidr6Block} -DNS = ${system.userConfig.defaultDns.join(', ')} +Address = ${client.ipv4Address}/${cidr4Block}, ${client.ipv6Address}/${cidr6Block} +DNS = ${client.dns.join(', ')} MTU = ${client.mtu} [Peer] -PublicKey = ${system.interface.publicKey} +PublicKey = ${wgInterface.publicKey} PresharedKey = ${client.preSharedKey} AllowedIPs = ${client.allowedIps.join(', ')} PersistentKeepalive = ${client.persistentKeepalive} -Endpoint = ${system.userConfig.host}:${system.userConfig.port}`; +Endpoint = ${userConfig.host}:${userConfig.port}`; }, generatePrivateKey: () => { @@ -70,24 +73,24 @@ Endpoint = ${system.userConfig.host}:${system.userConfig.port}`; }); }, - generatePresharedKey: () => { + generatePreSharedKey: () => { return exec('wg genpsk'); }, - up: () => { - return exec('wg-quick up wg0'); + up: (infName: string) => { + return exec(`wg-quick up ${infName}`); }, - down: () => { - return exec('wg-quick down wg0'); + down: (infName: string) => { + return exec(`wg-quick down ${infName}`); }, - sync: () => { - return exec('wg syncconf wg0 <(wg-quick strip wg0)'); + sync: (infName: string) => { + return exec(`wg syncconf ${infName} <(wg-quick strip ${infName})`); }, - dump: async () => { - const rawDump = await exec('wg show wg0 dump', { + dump: async (infName: string) => { + const rawDump = await exec(`wg show ${infName} dump`, { log: false, }); diff --git a/src/services/database/lowdb.ts b/src/services/database/lowdb.ts deleted file mode 100644 index 77bcd344..00000000 --- a/src/services/database/lowdb.ts +++ /dev/null @@ -1,356 +0,0 @@ -import crypto from 'node:crypto'; -import debug from 'debug'; -import { JSONFilePreset } from 'lowdb/node'; -import type { Low } from 'lowdb'; -import type { DeepReadonly } from 'vue'; -import { parseCidr } from 'cidr-tools'; -import { stringifyIp } from 'ip-bigint'; - -import { - DatabaseProvider, - DatabaseError, - DEFAULT_DATABASE, -} from './repositories/database'; -import { UserRepository, type User } from './repositories/user'; -import type { Database } from './repositories/database'; -import { migrationRunner } from './migrations'; -import { - ClientRepository, - type UpdateClient, - type CreateClient, - type OneTimeLink, -} from './repositories/client'; -import { - SystemRepository, - type General, - type UpdateWGConfig, - type UpdateWGInterface, - type WGHooks, -} from './repositories/system'; -import { SetupRepository, type Steps } from './repositories/setup'; - -const DEBUG = debug('LowDB'); - -export class LowDBSetup extends SetupRepository { - #db: Low; - constructor(db: Low) { - super(); - this.#db = db; - } - async done() { - if (this.#db.data.setup === 'success') { - return true; - } - return false; - } - - async get() { - return this.#db.data.setup; - } - - async set(step: Steps) { - this.#db.update((v) => { - v.setup = step; - }); - } -} - -/** - * deep copies object and - * makes readonly on type level - */ -function makeReadonly(a: T): DeepReadonly { - return structuredClone(a) as DeepReadonly; -} - -class LowDBSystem extends SystemRepository { - #db: Low; - constructor(db: Low) { - super(); - this.#db = db; - } - - async get() { - DEBUG('Get System'); - const system = this.#db.data.system; - // system is only null if migration failed - if (system === null) { - throw new DatabaseError(DatabaseError.ERROR_INIT); - } - return makeReadonly(system); - } - - async updateClientsHostPort(host: string, port: number): Promise { - DEBUG('Update Clients Host and Port endpoint'); - this.#db.update((v) => { - v.system.userConfig.host = host; - v.system.userConfig.port = port; - }); - } - - async updateGeneral(general: General) { - DEBUG('Update General'); - this.#db.update((v) => { - v.system.general = general; - }); - } - - async updateInterface(wgInterface: UpdateWGInterface) { - DEBUG('Update Interface'); - this.#db.update((v) => { - const oldInterface = v.system.interface; - v.system.interface = { - ...oldInterface, - ...wgInterface, - }; - }); - } - - async updateUserConfig(userConfig: UpdateWGConfig) { - DEBUG('Update User Config'); - this.#db.update((v) => { - const oldUserConfig = v.system.userConfig; - v.system.userConfig = { - ...oldUserConfig, - ...userConfig, - }; - }); - } - - async updateHooks(hooks: WGHooks) { - DEBUG('Update Hooks'); - this.#db.update((v) => { - v.system.hooks = hooks; - }); - } - - /** - * updates the address range and the interface address - */ - async updateAddressRange(address4Range: string, address6Range: string) { - DEBUG('Update Address Range'); - const cidr4 = parseCidr(address4Range); - const cidr6 = parseCidr(address6Range); - this.#db.update((v) => { - v.system.userConfig.address4Range = address4Range; - v.system.userConfig.address6Range = address6Range; - v.system.interface.address4 = stringifyIp({ - number: cidr4.start + 1n, - version: 4, - }); - v.system.interface.address6 = stringifyIp({ - number: cidr6.start + 1n, - version: 6, - }); - }); - } -} - -class LowDBUser extends UserRepository { - #db: Low; - constructor(db: Low) { - super(); - this.#db = db; - } - - async findAll() { - return makeReadonly(this.#db.data.users); - } - - async findById(id: string) { - DEBUG('Get User'); - return makeReadonly(this.#db.data.users.find((user) => user.id === id)); - } - - async create(username: string, password: string) { - DEBUG('Create User'); - - const isUserExist = this.#db.data.users.find( - (user) => user.username === username - ); - if (isUserExist) { - throw createError({ - statusCode: 409, - statusMessage: 'Username already taken', - }); - } - - const now = new Date().toISOString(); - const isUserEmpty = this.#db.data.users.length === 0; - - const hash = await hashPassword(password); - - const newUser: User = { - id: crypto.randomUUID(), - password: hash, - username, - email: null, - name: 'Administrator', - role: isUserEmpty ? 'ADMIN' : 'CLIENT', - enabled: true, - createdAt: now, - updatedAt: now, - }; - - await this.#db.update((data) => data.users.push(newUser)); - } - - async update(user: User) { - // TODO: avoid mutation, prefer .update, updatedAt - let oldUser = await this.findById(user.id); - if (oldUser) { - DEBUG('Update User'); - oldUser = user; - await this.#db.write(); - } - } - - async delete(id: string) { - DEBUG('Delete User'); - const idx = this.#db.data.users.findIndex((user) => user.id === id); - if (idx !== -1) { - await this.#db.update((data) => data.users.splice(idx, 1)); - } - } -} - -class LowDBClient extends ClientRepository { - #db: Low; - constructor(db: Low) { - super(); - this.#db = db; - } - async findAll() { - DEBUG('GET Clients'); - return makeReadonly(this.#db.data.clients); - } - - async findById(id: string) { - DEBUG('Get Client'); - return makeReadonly(this.#db.data.clients[id]); - } - - async create(client: CreateClient) { - DEBUG('Create Client'); - const id = crypto.randomUUID(); - const now = new Date().toISOString(); - const newClient = { ...client, createdAt: now, updatedAt: now, id }; - await this.#db.update((data) => { - data.clients[id] = newClient; - }); - } - - async delete(id: string) { - DEBUG('Delete Client'); - await this.#db.update((data) => { - // TODO: find something better than delete - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete data.clients[id]; - }); - } - - async toggle(id: string, enable: boolean) { - DEBUG('Toggle Client'); - await this.#db.update((data) => { - if (data.clients[id]) { - data.clients[id].enabled = enable; - } - }); - } - - async updateExpirationDate(id: string, expirationDate: string | null) { - DEBUG('Update Client Expiration Date'); - await this.#db.update((data) => { - if (data.clients[id]) { - data.clients[id].expiresAt = expirationDate; - } - }); - } - - async deleteOneTimeLink(id: string) { - DEBUG('Delete Client One Time Link'); - await this.#db.update((data) => { - if (data.clients[id]) { - if (data.clients[id].oneTimeLink) { - // Bug where Client makes 2 requests - data.clients[id].oneTimeLink.expiresAt = new Date( - Date.now() + 10 * 1000 - ).toISOString(); - } - } - }); - } - - async createOneTimeLink(id: string, oneTimeLink: OneTimeLink) { - DEBUG('Create Client One Time Link'); - await this.#db.update((data) => { - if (data.clients[id]) { - data.clients[id].oneTimeLink = oneTimeLink; - } - }); - } - - async update(id: string, client: UpdateClient) { - DEBUG('Create Client'); - const now = new Date().toISOString(); - await this.#db.update((data) => { - const oldClient = data.clients[id]; - if (!oldClient) { - return; - } - data.clients[id] = { - ...oldClient, - ...client, - updatedAt: now, - }; - }); - } -} - -export default class LowDB extends DatabaseProvider { - #db: Low; - - setup: LowDBSetup; - system: LowDBSystem; - user: LowDBUser; - client: LowDBClient; - - private constructor(db: Low) { - super(); - this.#db = db; - this.setup = new LowDBSetup(this.#db); - this.system = new LowDBSystem(this.#db); - this.user = new LowDBUser(this.#db); - this.client = new LowDBClient(this.#db); - } - - async runMigrations() { - await migrationRunner(this.#db); - } - - /** - * @throws - */ - static override async connect() { - try { - DEBUG('Connecting...'); - const db = await JSONFilePreset( - '/etc/wireguard/db.json', - DEFAULT_DATABASE - ); - const inst = new LowDB(db); - DEBUG('Running Migrations...'); - await inst.runMigrations(); - DEBUG('Migrations ran successfully.'); - DEBUG('Connected successfully.'); - return inst; - } catch (e) { - DEBUG(e); - throw new Error('Failed to initialize Database'); - } - } - - async disconnect() { - DEBUG('Disconnected successfully'); - } -} diff --git a/src/services/database/migrations/1.ts b/src/services/database/migrations/1.ts deleted file mode 100644 index 63df5a43..00000000 --- a/src/services/database/migrations/1.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { Low } from 'lowdb'; -import type { Database } from '../repositories/database'; -import { parseCidr } from 'cidr-tools'; -import { stringifyIp } from 'ip-bigint'; - -export async function run1(db: Low) { - const privateKey = await wg.generatePrivateKey(); - const publicKey = await wg.getPublicKey(privateKey); - - const address4Range = '10.8.0.0/24'; - const address6Range = 'fdcc:ad94:bacf:61a4::cafe:0/112'; - const cidr4 = parseCidr(address4Range); - const cidr6 = parseCidr(address6Range); - - const database: Database = { - migrations: [], - setup: 1, - system: { - general: { - sessionTimeout: 3600, // 1 hour - }, - // Config to configure Server - interface: { - privateKey: privateKey, - publicKey: publicKey, - address4: stringifyIp({ number: cidr4.start + 1n, version: 4 }), - address6: stringifyIp({ number: cidr6.start + 1n, version: 6 }), - mtu: 1420, - port: 51820, - device: 'eth0', - }, - // Config to configure Peer & Client Config - userConfig: { - mtu: 1420, - persistentKeepalive: 0, - address4Range: address4Range, - address6Range: address6Range, - defaultDns: ['1.1.1.1', '2606:4700:4700::1111'], - allowedIps: ['0.0.0.0/0', '::/0'], - host: '', - port: 51820, - }, - // Config to configure Firewall or general hooks - hooks: { - PreUp: '', - PostUp: [ - 'iptables -t nat -A POSTROUTING -s {{address4}} -o {{device}} -j MASQUERADE;', - 'iptables -A INPUT -p udp -m udp --dport {{port}} -j ACCEPT;', - 'iptables -A FORWARD -i wg0 -j ACCEPT;', - 'iptables -A FORWARD -o wg0 -j ACCEPT;', - 'ip6tables -t nat -A POSTROUTING -s {{address6}} -o {{device}} -j MASQUERADE;', - 'ip6tables -A INPUT -p udp -m udp --dport {{port}} -j ACCEPT;', - 'ip6tables -A FORWARD -i wg0 -j ACCEPT;', - 'ip6tables -A FORWARD -o wg0 -j ACCEPT;', - ].join(' '), - PreDown: '', - PostDown: [ - 'iptables -t nat -D POSTROUTING -s {{address4}} -o {{device}} -j MASQUERADE;', - 'iptables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT;', - 'iptables -D FORWARD -i wg0 -j ACCEPT;', - 'iptables -D FORWARD -o wg0 -j ACCEPT;', - 'ip6tables -t nat -D POSTROUTING -s {{address6}} -o {{device}} -j MASQUERADE;', - 'ip6tables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT;', - 'ip6tables -D FORWARD -i wg0 -j ACCEPT;', - 'ip6tables -D FORWARD -o wg0 -j ACCEPT;', - ].join(' '), - }, - metrics: { - prometheus: { - enabled: false, - password: null, - }, - }, - sessionConfig: { - // TODO: be able to invalidate all sessions - password: getRandomHex(256), - name: 'wg-easy', - cookie: {}, - }, - }, - users: [], - clients: {}, - }; - - db.data = database; - db.write(); -} diff --git a/src/services/database/migrations/index.ts b/src/services/database/migrations/index.ts deleted file mode 100644 index f1ef433e..00000000 --- a/src/services/database/migrations/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Low } from 'lowdb'; -import type { Database } from '../repositories/database'; -import { run1 } from './1'; - -export type MIGRATION_FN = (db: Low) => Promise; - -const MIGRATION_LIST = [ - // Adds Initial Database Structure - { id: '1', fn: run1 }, -] satisfies { id: string; fn: MIGRATION_FN }[]; - -/** - * Runs all migrations - * @throws - */ -export async function migrationRunner(db: Low) { - const ranMigrations = db.data.migrations; - for (const migration of MIGRATION_LIST) { - if (ranMigrations.includes(migration.id)) { - continue; - } - try { - await migration.fn(db); - db.data.migrations.push(migration.id); - } catch (e) { - throw new Error(`Failed to run Migration ${migration.id}: ${e}`); - } - } - await db.write(); -} diff --git a/src/services/database/repositories/client.ts b/src/services/database/repositories/client.ts deleted file mode 100644 index e6876c81..00000000 --- a/src/services/database/repositories/client.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { DeepReadonly } from 'vue'; - -export type OneTimeLink = { - oneTimeLink: string; - /** ISO String */ - expiresAt: string; -}; - -export type Client = { - id: string; - name: string; - address4: string; - address6: string; - privateKey: string; - publicKey: string; - preSharedKey: string; - /** ISO String */ - expiresAt: string | null; - allowedIps: string[]; - serverAllowedIPs: string[]; - oneTimeLink: OneTimeLink | null; - /** ISO String */ - createdAt: string; - /** ISO String */ - updatedAt: string; - enabled: boolean; - persistentKeepalive: number; - mtu: number; -}; - -export type CreateClient = Omit; - -export type UpdateClient = Omit< - Client, - | 'createdAt' - | 'updatedAt' - | 'id' - | 'oneTimeLink' - | 'privateKey' - | 'publicKey' - | 'preSharedKey' ->; - -/** - * Interface for client-related database operations. - * This interface provides methods for managing client data. - */ -export abstract class ClientRepository { - abstract findAll(): Promise>>; - abstract findById(id: string): Promise>; - - abstract create(client: CreateClient): Promise; - abstract delete(id: string): Promise; - abstract toggle(id: string, enable: boolean): Promise; - abstract deleteOneTimeLink(id: string): Promise; - abstract createOneTimeLink( - id: string, - oneTimeLink: OneTimeLink - ): Promise; - - abstract update(id: string, client: UpdateClient): Promise; -} diff --git a/src/services/database/repositories/database.ts b/src/services/database/repositories/database.ts deleted file mode 100644 index 7ce50dca..00000000 --- a/src/services/database/repositories/database.ts +++ /dev/null @@ -1,81 +0,0 @@ -import type { ClientRepository, Client } from './client'; -import type { SetupRepository, Steps } from './setup'; -import type { System, SystemRepository } from './system'; -import type { User, UserRepository } from './user'; - -// Represent data structure -export type Database = { - migrations: string[]; - setup: Steps; - system: System; - users: User[]; - clients: Record; -}; - -export const DEFAULT_DATABASE: Database = { - migrations: [], - setup: 1, - system: null as never, - users: [], - clients: {}, -}; - -/** - * Abstract class for database operations. - * Provides methods to connect, disconnect, and interact with system and user data. - */ -export abstract class DatabaseProvider { - /** - * Connects to the database. - */ - static connect(): Promise { - throw new Error('Not implemented'); - } - - /** - * Disconnects from the database. - */ - abstract disconnect(): Promise; - - abstract setup: SetupRepository; - abstract system: SystemRepository; - abstract user: UserRepository; - abstract client: ClientRepository; -} - -/** - * Represents a specialized error class for database-related operations. - * This class is designed to work with internationalization (i18n) by using message keys. - * The actual error messages are expected to be retrieved using these keys from an i18n system. - * - * ### Usage: - * When throwing a `DatabaseError`, you provide an i18n key as the message. - * The key will be used by the i18n system to retrieve the corresponding localized error message. - * - * Example: - * ```typescript - * throw new DatabaseError(DatabaseError.ERROR_INIT); - * ... - * // event handler routes - * if (error instanceof DatabaseError) { - * const t = await useTranslation(event); - * throw createError({ - * statusCode: 400, - * statusMessage: t(error.message), - * message: error.message, - * }); - * } else { - * throw createError('Something happened !'); - * } - * ``` - * - * @extends {Error} - */ -export class DatabaseError extends Error { - static readonly ERROR_INIT = 'errorInit'; - - constructor(message: string) { - super(message); - this.name = 'DatabaseError'; - } -} diff --git a/src/services/database/repositories/setup.ts b/src/services/database/repositories/setup.ts deleted file mode 100644 index a6adeba8..00000000 --- a/src/services/database/repositories/setup.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type Steps = 1 | 2 | 3 | 4 | 5 | 'success'; - -/** - * Interface for setup-related database operations. - * This interface provides methods for managing setup data. - */ -export abstract class SetupRepository { - abstract done(): Promise; - abstract get(): Promise; - abstract set(step: Steps): Promise; -} diff --git a/src/services/database/repositories/system.ts b/src/services/database/repositories/system.ts deleted file mode 100644 index 3cc9eba2..00000000 --- a/src/services/database/repositories/system.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { SessionConfig } from 'h3'; -import type { DeepReadonly } from 'vue'; - -export type WGHooks = { - PreUp: string; - PostUp: string; - PreDown: string; - PostDown: string; -}; - -export type WGInterface = { - privateKey: string; - publicKey: string; - address4: string; - address6: string; - mtu: number; - port: number; - device: string; -}; - -export type WGConfig = { - mtu: number; - persistentKeepalive: number; - address4Range: string; - address6Range: string; - defaultDns: string[]; - allowedIps: string[]; - host: string; - port: number; -}; - -export enum ChartType { - None = 0, - Line = 1, - Area = 2, - Bar = 3, -} - -export type Prometheus = { - enabled: boolean; - password: string | null; -}; - -export type Metrics = { - prometheus: Prometheus; -}; - -export type General = { - sessionTimeout: number; -}; - -export type System = { - general: General; - - interface: WGInterface; - - userConfig: WGConfig; - - hooks: WGHooks; - - metrics: Metrics; - - sessionConfig: SessionConfig; -}; - -export type UpdateWGInterface = Omit< - WGInterface, - 'privateKey' | 'publicKey' | 'address4' | 'address6' ->; - -export type UpdateWGConfig = Omit; - -/** - * Interface for system-related database operations. - * This interface provides methods for retrieving system configuration data - * and specific system properties, such as the language setting, from the database. - */ -export abstract class SystemRepository { - abstract get(): Promise>; - - abstract updateClientsHostPort(host: string, port: number): Promise; - - abstract updateGeneral(general: General): Promise; - - abstract updateInterface(wgInterface: UpdateWGInterface): Promise; - - abstract updateUserConfig(userConfig: UpdateWGConfig): Promise; - - abstract updateHooks(hooks: WGHooks): Promise; -} diff --git a/src/services/database/repositories/user.ts b/src/services/database/repositories/user.ts deleted file mode 100644 index 995f826c..00000000 --- a/src/services/database/repositories/user.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { DeepReadonly } from 'vue'; - -/** - * Represents user roles within the application, each with specific permissions : - * - * - `ADMIN`: Full permissions to all resources, including the app, database, etc - * - `EDITOR`: Granted write and read permissions on their own resources as well as - * `CLIENT` resources, but without `ADMIN` privileges - * - `CLIENT`: Granted write and read permissions only on their own resources. - */ -export type ROLE = 'ADMIN' | 'EDITOR' | 'CLIENT'; - -/** - * Representing a user data structure. - */ -export type User = { - id: string; - role: ROLE; - username: string; - password: string; - name: string; - email: string | null; - /** ISO String */ - createdAt: string; - /** ISO String */ - updatedAt: string; - enabled: boolean; -}; - -/** - * Interface for user-related database operations. - * This interface provides methods for managing user data. - */ -export abstract class UserRepository { - abstract findAll(): Promise>; - abstract findById(id: string): Promise>; - - abstract create(username: string, password: string): Promise; - abstract update(user: User): Promise; - abstract delete(id: string): Promise; -} diff --git a/src/shared/utils/permissions.ts b/src/shared/utils/permissions.ts new file mode 100644 index 00000000..3b7c5762 --- /dev/null +++ b/src/shared/utils/permissions.ts @@ -0,0 +1,31 @@ +// TODO: implement ABAC + +export const actions = { + ADMIN: 'ADMIN', + CLIENT: 'CLIENT', +} as const; + +export type Role = number & { readonly __role: unique symbol }; + +export const roles = { + ADMIN: 1 as Role, + CLIENT: 2 as Role, +} as const; + +export type Action = keyof typeof actions; + +type MATRIX = { + readonly [key in keyof typeof actions]: readonly (typeof roles)[keyof typeof roles][]; +}; + +export const MATRIX: MATRIX = { + [actions.ADMIN]: [roles.ADMIN] as const, + [actions.CLIENT]: [roles.CLIENT, roles.ADMIN] as const, +} as const; + +export const checkPermissions = (action: Action, user: { role: Role }) => { + if (!MATRIX[action].includes(user.role)) { + return false; + } + return true; +};