From ae7b4dacf181b8aded261b58b7d62b247b416f21 Mon Sep 17 00:00:00 2001 From: dicedtomato <35403473+diced@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:13:54 -0700 Subject: [PATCH] feat: remove next.js in favor of client-side only (#857) * feat: start removing next.js * feat: working ssr + dev + prod env * feat: all functionality added + client/ -> src/client/ * fix: build process * fix: caching on pnpm action * fix: ignores + cache action * fix: docker + exdev error * fix: generate prisma before types * fix: remove node@20 from actions * feat: dynamic import optimizations + titled pages * fix: removed unused vars * feat: small ui fixes and improvements * feat: small ui improvements * fix: linting error * fix: regex when adding domains --- .dockerignore | 1 - .github/ISSUE_TEMPLATE/bug.yml | 9 +- .github/workflows/build.yml | 19 +- .gitignore | 10 +- Dockerfile | 11 +- eslint.config.mjs | 22 +- next.config.js | 24 - package.json | 34 +- pnpm-lock.yaml | 1791 ++++++++++------- prisma/schema.prisma | 5 +- src/client/Root.tsx | 47 + src/client/error/DashboardErrorBoundary.tsx | 11 + src/client/error/GenericError.tsx | 27 + src/client/error/RootErrorBoundary.tsx | 11 + src/client/index.html | 12 + src/client/main.tsx | 18 + src/{ => client}/pages/404.tsx | 12 +- src/{ => client}/pages/auth/login.tsx | 176 +- src/{ => client}/pages/auth/logout.tsx | 22 +- src/client/pages/auth/register.tsx | 260 +++ src/{pages => client/pages/auth}/setup.tsx | 58 +- src/client/pages/auth/tos.tsx | 41 + src/client/pages/dashboard/admin/invites.tsx | 10 + src/client/pages/dashboard/admin/settings.tsx | 10 + .../dashboard/admin/users/[id]/files.tsx | 23 + .../pages/dashboard/admin/users/index.tsx | 10 + src/client/pages/dashboard/files.tsx | 10 + src/client/pages/dashboard/folders.tsx | 10 + src/client/pages/dashboard/index.tsx | 10 + src/client/pages/dashboard/metrics.tsx | 10 + src/client/pages/dashboard/settings.tsx | 10 + src/client/pages/dashboard/upload/file.tsx | 10 + src/client/pages/dashboard/upload/text.tsx | 10 + src/client/pages/dashboard/urls.tsx | 10 + src/client/pages/folder/[id]/index.tsx | 57 + src/client/pages/folder/[id]/upload.tsx | 55 + src/client/pages/view/[id].tsx | 245 +++ src/client/pages/view/url/[id].tsx | 65 + src/client/routes.tsx | 114 ++ src/client/ssr-view-url/client.tsx | 25 + src/client/ssr-view-url/index.html | 12 + src/client/ssr-view-url/routes.tsx | 18 + src/client/ssr-view-url/server.tsx | 95 + src/client/ssr-view/client.tsx | 25 + src/client/ssr-view/index.html | 12 + src/client/ssr-view/routes.tsx | 18 + src/client/ssr-view/server.tsx | 287 +++ src/{ => client}/styles/global.css | 0 src/components/ConfigProvider.tsx | 21 +- src/components/Layout.tsx | 38 +- src/components/ThemeProvider.tsx | 24 +- src/components/ZiplineSSRProvider.tsx | 19 + src/components/file/DashboardFileType.tsx | 7 +- src/components/file/actions.tsx | 4 +- src/components/pages/dashboard/index.tsx | 11 +- .../pages/files/PendingFilesButton.tsx | 7 +- src/components/pages/files/index.tsx | 6 +- .../pages/files/tags/TagsButton.tsx | 5 +- .../pages/files/views/FavoriteFiles.tsx | 20 +- .../pages/files/views/FileTable.tsx | 49 +- src/components/pages/files/views/Files.tsx | 25 +- .../pages/folders/FavoriteFiles.tsx | 19 +- .../pages/folders/ViewFilesModal.tsx | 10 +- src/components/pages/folders/actions.tsx | 4 +- src/components/pages/folders/index.tsx | 4 +- src/components/pages/invites/actions.tsx | 4 +- src/components/pages/invites/index.tsx | 16 +- .../pages/login/ExternalAuthButton.tsx | 3 +- src/components/pages/metrics/index.tsx | 11 +- src/components/pages/serverSettings/index.tsx | 120 +- .../pages/serverSettings/parts/Chunks.tsx | 7 +- .../pages/serverSettings/parts/Core.tsx | 7 +- .../pages/serverSettings/parts/Discord.tsx | 8 +- .../pages/serverSettings/parts/Domains.tsx | 14 +- .../pages/serverSettings/parts/Features.tsx | 7 +- .../pages/serverSettings/parts/Files.tsx | 7 +- .../serverSettings/parts/HttpWebhook.tsx | 7 +- .../pages/serverSettings/parts/Invites.tsx | 7 +- .../pages/serverSettings/parts/Mfa.tsx | 7 +- .../pages/serverSettings/parts/Oauth.tsx | 77 +- .../pages/serverSettings/parts/PWA.tsx | 11 +- .../pages/serverSettings/parts/Ratelimit.tsx | 9 +- .../pages/serverSettings/parts/Tasks.tsx | 7 +- .../pages/serverSettings/parts/Urls.tsx | 7 +- .../pages/serverSettings/parts/Website.tsx | 7 +- .../pages/serverSettings/settingsOnSubmit.tsx | 8 +- src/components/pages/settings/index.tsx | 45 +- .../settings/parts/SettingsDashboard.tsx | 2 +- .../pages/settings/parts/SettingsExports.tsx | 96 +- .../pages/settings/parts/SettingsFileView.tsx | 6 +- .../SettingsGenerators/GeneratorButton.tsx | 4 +- .../parts/SettingsGenerators/index.tsx | 28 +- .../parts/SettingsMfa/PasskeyButton.tsx | 2 +- .../parts/SettingsMfa/TwoFAButton.tsx | 8 +- .../settings/parts/SettingsOAuth/index.tsx | 5 +- .../pages/settings/parts/SettingsSessions.tsx | 4 +- .../pages/settings/parts/SettingsUser.tsx | 8 +- src/components/pages/upload/File/index.tsx | 16 +- src/components/pages/upload/Text/index.tsx | 21 +- .../pages/upload/UploadOptionsButton.tsx | 7 +- src/components/pages/upload/uploadFiles.tsx | 6 +- .../pages/upload/uploadPartialFiles.tsx | 10 +- src/components/pages/urls/actions.tsx | 4 +- src/components/pages/urls/index.tsx | 10 +- src/components/pages/users/UserCard.tsx | 14 +- src/components/pages/users/ViewUserFiles.tsx | 14 +- src/components/pages/users/index.tsx | 4 +- .../pages/users/views/UserTableView.tsx | 4 +- src/components/render/Render.tsx | 5 +- src/components/render/code/HighlightCode.tsx | 18 +- src/lib/api/response.ts | 9 +- src/lib/db/index.ts | 4 +- src/lib/db/models/folder.ts | 2 +- src/lib/db/models/incompleteFile.ts | 2 +- src/lib/db/models/invite.ts | 2 +- src/lib/db/models/url.ts | 2 +- src/lib/db/models/user.ts | 2 +- src/lib/hooks/useLogin.ts | 13 +- src/lib/hooks/useQueryState.ts | 37 + src/lib/hooks/useTitle.ts | 14 + src/lib/middleware/combine.ts | 15 - src/lib/middleware/cors.ts | 19 - src/lib/middleware/file.ts | 23 - src/lib/middleware/functions.ts | 80 - src/lib/middleware/method.ts | 19 - src/lib/middleware/next/withSafeConfig.ts | 40 - src/lib/middleware/ziplineAuth.ts | 95 - src/lib/oauth/providerUtil.ts | 2 +- src/lib/response.ts | 23 - src/lib/role.ts | 2 +- src/lib/ssr/constants.ts | 4 + src/lib/ssr/createZiplineSsr.ts | 5 + src/lib/ssr/renderHtml.tsx | 32 + src/lib/version.ts | 2 - src/pages/500.tsx | 44 - src/pages/_app.tsx | 72 - src/pages/_document.tsx | 15 - src/pages/auth/register.tsx | 279 --- src/pages/auth/tos.tsx | 34 - src/pages/dashboard/admin/invites.tsx | 52 - src/pages/dashboard/admin/settings.tsx | 51 - .../dashboard/admin/users/[id]/files.tsx | 78 - src/pages/dashboard/admin/users/index.tsx | 52 - src/pages/dashboard/files.tsx | 23 - src/pages/dashboard/folders.tsx | 23 - src/pages/dashboard/index.tsx | 19 - src/pages/dashboard/metrics.tsx | 32 - src/pages/dashboard/settings.tsx | 23 - src/pages/dashboard/upload/file.tsx | 36 - src/pages/dashboard/upload/text.tsx | 51 - src/pages/dashboard/urls.tsx | 23 - src/pages/folder/[id]/index.tsx | 83 - src/pages/folder/[id]/upload.tsx | 71 - src/pages/index.tsx | 34 - src/pages/reload.tsx | 45 - src/pages/view/[id].tsx | 506 ----- src/pages/view/url/[id].tsx | 153 -- src/server/index.ts | 63 +- src/server/middleware/user.ts | 7 +- src/server/plugins/next.ts | 49 - src/server/plugins/oauth.ts | 2 +- src/server/plugins/vite.ts | 131 ++ src/server/routes/api/auth/invites/[id].ts | 2 +- src/server/routes/api/auth/invites/web.ts | 62 + src/server/routes/api/auth/oauth/index.ts | 2 +- src/server/routes/api/healthcheck.ts | 4 +- src/server/routes/api/server/folder.ts | 51 + src/server/routes/api/server/public.ts | 95 + .../server/{settings.ts => settings/index.ts} | 30 +- src/server/routes/api/server/settings/web.ts | 44 + src/server/routes/api/server/themes.ts | 24 + src/server/routes/api/upload/index.ts | 2 +- src/server/routes/api/upload/partial.ts | 2 +- src/server/routes/api/user/export.ts | 2 +- .../routes/api/user/files/[id]/index.ts | 2 +- src/server/routes/api/user/files/index.ts | 2 +- src/server/routes/api/user/mfa/passkey.ts | 2 +- src/server/routes/api/users/[id].ts | 2 +- src/server/routes/api/users/index.ts | 2 +- src/server/routes/files.dy.ts | 42 +- src/server/routes/index.ts | 2 +- src/server/routes/invites.ts | 16 + src/server/routes/manifest.json.ts | 10 +- src/server/routes/raw/[id].ts | 16 +- src/server/routes/robots.txt.ts | 5 +- src/server/routes/urls.dy.ts | 9 +- tsconfig.json | 4 +- tsup.config.ts | 9 +- vite-env.d.ts | 1 + vite.config.ts | 52 + 190 files changed, 4035 insertions(+), 3707 deletions(-) delete mode 100755 next.config.js create mode 100644 src/client/Root.tsx create mode 100644 src/client/error/DashboardErrorBoundary.tsx create mode 100644 src/client/error/GenericError.tsx create mode 100644 src/client/error/RootErrorBoundary.tsx create mode 100644 src/client/index.html create mode 100644 src/client/main.tsx rename src/{ => client}/pages/404.tsx (64%) rename src/{ => client}/pages/auth/login.tsx (71%) mode change 100755 => 100644 rename src/{ => client}/pages/auth/logout.tsx (64%) mode change 100755 => 100644 create mode 100644 src/client/pages/auth/register.tsx rename src/{pages => client/pages/auth}/setup.tsx (88%) mode change 100755 => 100644 create mode 100644 src/client/pages/auth/tos.tsx create mode 100644 src/client/pages/dashboard/admin/invites.tsx create mode 100644 src/client/pages/dashboard/admin/settings.tsx create mode 100644 src/client/pages/dashboard/admin/users/[id]/files.tsx create mode 100644 src/client/pages/dashboard/admin/users/index.tsx create mode 100644 src/client/pages/dashboard/files.tsx create mode 100644 src/client/pages/dashboard/folders.tsx create mode 100644 src/client/pages/dashboard/index.tsx create mode 100644 src/client/pages/dashboard/metrics.tsx create mode 100644 src/client/pages/dashboard/settings.tsx create mode 100644 src/client/pages/dashboard/upload/file.tsx create mode 100644 src/client/pages/dashboard/upload/text.tsx create mode 100644 src/client/pages/dashboard/urls.tsx create mode 100644 src/client/pages/folder/[id]/index.tsx create mode 100644 src/client/pages/folder/[id]/upload.tsx create mode 100644 src/client/pages/view/[id].tsx create mode 100644 src/client/pages/view/url/[id].tsx create mode 100644 src/client/routes.tsx create mode 100644 src/client/ssr-view-url/client.tsx create mode 100644 src/client/ssr-view-url/index.html create mode 100644 src/client/ssr-view-url/routes.tsx create mode 100644 src/client/ssr-view-url/server.tsx create mode 100644 src/client/ssr-view/client.tsx create mode 100644 src/client/ssr-view/index.html create mode 100644 src/client/ssr-view/routes.tsx create mode 100644 src/client/ssr-view/server.tsx rename src/{ => client}/styles/global.css (100%) create mode 100644 src/components/ZiplineSSRProvider.tsx create mode 100644 src/lib/hooks/useQueryState.ts create mode 100644 src/lib/hooks/useTitle.ts delete mode 100755 src/lib/middleware/combine.ts delete mode 100755 src/lib/middleware/cors.ts delete mode 100755 src/lib/middleware/file.ts delete mode 100755 src/lib/middleware/functions.ts delete mode 100755 src/lib/middleware/method.ts delete mode 100755 src/lib/middleware/next/withSafeConfig.ts delete mode 100755 src/lib/middleware/ziplineAuth.ts create mode 100644 src/lib/ssr/constants.ts create mode 100644 src/lib/ssr/createZiplineSsr.ts create mode 100644 src/lib/ssr/renderHtml.tsx delete mode 100644 src/pages/500.tsx delete mode 100755 src/pages/_app.tsx delete mode 100755 src/pages/_document.tsx delete mode 100755 src/pages/auth/register.tsx delete mode 100644 src/pages/auth/tos.tsx delete mode 100755 src/pages/dashboard/admin/invites.tsx delete mode 100644 src/pages/dashboard/admin/settings.tsx delete mode 100755 src/pages/dashboard/admin/users/[id]/files.tsx delete mode 100755 src/pages/dashboard/admin/users/index.tsx delete mode 100755 src/pages/dashboard/files.tsx delete mode 100755 src/pages/dashboard/folders.tsx delete mode 100755 src/pages/dashboard/index.tsx delete mode 100755 src/pages/dashboard/metrics.tsx delete mode 100755 src/pages/dashboard/settings.tsx delete mode 100755 src/pages/dashboard/upload/file.tsx delete mode 100755 src/pages/dashboard/upload/text.tsx delete mode 100755 src/pages/dashboard/urls.tsx delete mode 100755 src/pages/folder/[id]/index.tsx delete mode 100644 src/pages/folder/[id]/upload.tsx delete mode 100755 src/pages/index.tsx delete mode 100644 src/pages/reload.tsx delete mode 100755 src/pages/view/[id].tsx delete mode 100755 src/pages/view/url/[id].tsx delete mode 100755 src/server/plugins/next.ts create mode 100644 src/server/plugins/vite.ts create mode 100644 src/server/routes/api/auth/invites/web.ts create mode 100644 src/server/routes/api/server/folder.ts create mode 100644 src/server/routes/api/server/public.ts rename src/server/routes/api/server/{settings.ts => settings/index.ts} (95%) create mode 100644 src/server/routes/api/server/settings/web.ts create mode 100644 src/server/routes/api/server/themes.ts create mode 100644 src/server/routes/invites.ts create mode 100644 vite-env.d.ts create mode 100644 vite.config.ts diff --git a/.dockerignore b/.dockerignore index 534032de..295152d0 100755 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,4 @@ .github -.next build node_modules uploads* diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 8351b331..83cd6132 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -17,10 +17,8 @@ body: label: Version description: What version (or docker image) of Zipline are you using? options: - - Latest v4 release (ghcr.io/diced/zipline or ghcr.io/diced/zipline:latest) - - Latest v4 commit (ghcr.io/diced/zipline:trunk) - - Latest v3 release (ghcr.io/diced/zipline:v3) - - Latest v3 commit (ghcr.io/diced/zipline:v3-trunk) + - Latest release (ghcr.io/diced/zipline or ghcr.io/diced/zipline:latest) + - Latest commit (ghcr.io/diced/zipline:trunk) - other (provide version in additional info) validations: required: true @@ -33,13 +31,14 @@ body: - Firefox - Chromium-based (Chrome, Edge, Brave, Opera, mobile chrome/chromium based, etc) - Safari + - Chromium-based Mobile (Chrome, Edge, Brave, Android WebView, etc) - Firefox Mobile - Safari Mobile - type: textarea id: zipline-logs attributes: label: Zipline Logs - description: Please copy and paste any relevant log output. Not seeing anything interesting? Try adding the `DEBUG=zipline` (v4) or `DEBUG=true` (v3) environment variable to see more logs, make sure to review the output and remove any sensitive information as it can be VERY verbose at times. + description: Please copy and paste any relevant log output. Not seeing anything interesting? Try adding the `DEBUG=zipline` (v4) environment variable to see more logs, make sure to review the output and remove any sensitive information as it can be VERY verbose at times. render: shell - type: textarea id: browser-logs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b8a800d4..aac1b2bf 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: build: strategy: matrix: - node: [20.x, 22.x, 24.x] + node: [22.x, 24.x] arch: [amd64, arm64] runs-on: ubuntu-24.04${{ matrix.arch == 'arm64' && '-arm' || '' }} @@ -37,16 +37,23 @@ jobs: with: path: | ${{ steps.pnpm-cache.outputs.store_path }} - ${{ github.workspace }}/.next/cache - key: ${{ runner.os }}-pnpm-next-store-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} + key: ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.node }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} restore-keys: | - ${{ runner.os }}-pnpm-next-store-${{ hashFiles('**/package-lock.json') }}- + ${{ runner.os }}-${{ matrix.arch }}-${{ matrix.node }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}- - name: Install run: pnpm install + - name: Lint + run: pnpm lint + + - name: Generate Prisma + run: pnpm build:prisma + + - name: Type Check + run: pnpm build:types + - name: Build env: ZIPLINE_BUILD: 'true' - NEXT_TELEMETRY_DISABLED: '1' - run: pnpm build + run: pnpm build:skip diff --git a/.gitignore b/.gitignore index e62a093b..7b1ddaf4 100755 --- a/.gitignore +++ b/.gitignore @@ -13,17 +13,14 @@ # testing /coverage -# next.js -/.next/ -/out/ - # production -/build +build/ # misc .DS_Store *.pem .idea +.vscode # debug npm-debug.log* @@ -38,7 +35,6 @@ yarn-error.log* # typescript *.tsbuildinfo -next-env.d.ts # eslint .eslintcache @@ -52,4 +48,4 @@ next-env.d.ts uploads*/ *.crt *.key -generated \ No newline at end of file +src/prisma \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9ef427b7..6b4f5f54 100755 --- a/Dockerfile +++ b/Dockerfile @@ -20,11 +20,17 @@ FROM base AS builder RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile COPY src ./src -COPY next.config.js ./next.config.js +COPY .gitignore ./.gitignore + +COPY postcss.config.cjs ./postcss.config.cjs +COPY prettier.config.cjs ./prettier.config.cjs +COPY eslint.config.mjs ./eslint.config.mjs +COPY vite.config.ts ./vite.config.ts COPY tsup.config.ts ./tsup.config.ts COPY tsconfig.json ./tsconfig.json COPY mimes.json ./mimes.json COPY code.json ./code.json +COPY vite-env.d.ts ./vite-env.d.ts ENV NEXT_TELEMETRY_DISABLED=1 \ NODE_ENV=production @@ -36,12 +42,9 @@ FROM base COPY --from=deps /zipline/node_modules ./node_modules COPY --from=builder /zipline/build ./build -COPY --from=builder /zipline/.next ./.next COPY --from=builder /zipline/mimes.json ./mimes.json COPY --from=builder /zipline/code.json ./code.json -COPY --from=builder /zipline/generated ./generated - RUN pnpm build:prisma diff --git a/eslint.config.mjs b/eslint.config.mjs index 7d79d693..321a0dce 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,9 +2,9 @@ import unusedImports from 'eslint-plugin-unused-imports'; import tseslint from 'typescript-eslint'; import prettier from 'eslint-plugin-prettier'; import prettierConfig from 'eslint-config-prettier'; -import nextConfig from '@next/eslint-plugin-next'; import reactHooksPlugin from 'eslint-plugin-react-hooks'; import reactPlugin from 'eslint-plugin-react'; +import reactRefreshPlugin from 'eslint-plugin-react-refresh'; import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -23,7 +23,13 @@ const gitignorePatterns = gitignoreContent export default tseslint.config( { ignores: gitignorePatterns }, - ...tseslint.configs.recommended, + { + extends: [ + tseslint.configs.recommended, + reactHooksPlugin.configs['recommended-latest'], + reactRefreshPlugin.configs.vite, + ], + }, { files: ['**/*.{js,mjs,cjs,ts,tsx}'], @@ -39,19 +45,12 @@ export default tseslint.config( plugins: { 'unused-imports': unusedImports, prettier: prettier, - '@next/next': nextConfig, - 'react-hooks': reactHooksPlugin, react: reactPlugin, 'jsx-a11y': jsxA11yPlugin, }, rules: { ...reactPlugin.configs.recommended.rules, - ...reactHooksPlugin.configs.recommended.rules, - - ...nextConfig.configs.recommended.rules, - ...nextConfig.configs['core-web-vitals'].rules, - ...prettierConfig.rules, 'prettier/prettier': [ 'error', @@ -60,7 +59,6 @@ export default tseslint.config( fileInfoOptions: { withNodeModules: false, }, - ignoreFileExtensions: ['pnpm-lock.yaml'], }, ], @@ -78,6 +76,7 @@ export default tseslint.config( 'react/prop-types': 'off', 'react-hooks/rules-of-hooks': 'off', 'react-hooks/exhaustive-deps': 'off', + 'react-refresh/only-export-components': 'off', 'react/jsx-uses-react': 'warn', 'react/jsx-uses-vars': 'warn', 'react/no-danger-with-children': 'warn', @@ -110,9 +109,6 @@ export default tseslint.config( react: { version: 'detect', }, - next: { - rootDir: __dirname, - }, }, }, ); diff --git a/next.config.js b/next.config.js deleted file mode 100755 index ed42c49f..00000000 --- a/next.config.js +++ /dev/null @@ -1,24 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { - reactStrictMode: true, - rewrites: async () => [ - { - source: '/invite/:code', - destination: '/auth/register?code=:code', - }, - ], - redirects: async () => [ - { - source: '/r/:id', - destination: '/raw/:id', - permanent: true, - }, - ], - webpack: (config) => { - config.resolve.fallback = { worker_threads: false }; - - return config; - }, -}; - -module.exports = nextConfig; diff --git a/package.json b/package.json index fdd54adb..f0182a5f 100755 --- a/package.json +++ b/package.json @@ -4,14 +4,19 @@ "license": "MIT", "version": "4.2.3", "scripts": { - "build": "cross-env pnpm run --stream \"/^build:.*/\"", + "lint": "eslint .", + "build:skip": "pnpm run --stream build:prisma && pnpm run --stream build:server && pnpm run --stream build:client", + "build": "pnpm run --stream lint && pnpm run --stream build:types && pnpm run --stream build:prisma && pnpm run --stream build:server && pnpm run --stream build:client", + "build:types": "tsc", "build:prisma": "prisma generate --no-hints", - "build:next": "ZIPLINE_BUILD=true next build", "build:server": "tsup", - "dev": "cross-env TURBOPACK=1 NODE_ENV=development DEBUG=zipline tsx --require dotenv/config --enable-source-maps ./src/server", - "dev:nd": "cross-env TURBOPACK=1 NODE_ENV=development tsx --require dotenv/config --enable-source-maps ./src/server", - "dev:inspector": "cross-env TURBOPACK=1 NODE_ENV=development DEBUG=zipline tsx --require dotenv/config --inspect=0.0.0.0:9229 --enable-source-maps ./src/server", - "start": "cross-env NODE_ENV=production node --trace-warnings --require dotenv/config --enable-source-maps ./build/server", + "build:client": "vite build && pnpm run --stream \"/^build-ssr:.*/\"", + "build-ssr:view": "vite build --ssr ssr-view/server.tsx -m ssr-view --outDir ../../build/ssr --emptyOutDir=false", + "build-ssr:view-url": "vite build --ssr ssr-view-url/server.tsx -m ssr-view-url --outDir ../../build/ssr --emptyOutDir=false", + "dev": "cross-env NODE_ENV=development DEBUG=zipline tsx --require dotenv/config --enable-source-maps ./src/server", + "dev:nd": "cross-env NODE_ENV=development tsx --require dotenv/config --enable-source-maps ./src/server", + "dev:inspector": "cross-env NODE_ENV=development DEBUG=zipline tsx --require dotenv/config --inspect=0.0.0.0:9229 --enable-source-maps ./src/server", + "start": "cross-env NODE_ENV=production node --trace-warnings --require dotenv/config ./build/server", "start:inspector": "cross-env NODE_ENV=production node --require dotenv/config --inspect=0.0.0.0:9229 --enable-source-maps ./build/server", "ctl": "NODE_ENV=production node --require dotenv/config --enable-source-maps ./build/ctl", "validate": "pnpm run --stream \"/^validate:.*/\"", @@ -55,6 +60,7 @@ "clsx": "^2.1.1", "colorette": "^2.0.20", "commander": "^14.0.0", + "cookie": "^1.0.2", "cross-env": "^10.0.0", "dayjs": "^1.11.13", "dotenv": "^17.2.1", @@ -70,45 +76,45 @@ "mantine-datatable": "^8.2.0", "ms": "^2.1.3", "multer": "2.0.2", - "next": "^15.4.5", - "nuqs": "^2.4.3", "otplib": "^12.0.1", "prisma": "^6.13.0", "qrcode": "^1.5.4", "react": "^19.1.1", "react-dom": "^19.1.1", "react-markdown": "^10.1.0", + "react-router-dom": "^7.7.1", "remark-gfm": "^4.0.1", "sharp": "^0.34.3", "swr": "^2.3.4", - "typescript-eslint": "^8.38.0", + "typescript-eslint": "^8.39.0", + "vite": "^7.1.0", "zod": "^3.25.67", "zustand": "^5.0.7" }, "devDependencies": { - "@next/eslint-plugin-next": "^15.4.5", "@types/bytes": "^3.1.5", "@types/fluent-ffmpeg": "^2.1.27", "@types/katex": "^0.16.7", "@types/ms": "^2.1.0", "@types/multer": "^2.0.0", - "@types/node": "^24.1.0", + "@types/node": "^24.2.0", "@types/qrcode": "^1.5.5", "@types/react": "^19.1.9", "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.0", "eslint": "^9.32.0", - "eslint-config-next": "^15.4.5", "eslint-config-prettier": "^10.1.8", "eslint-plugin-jsx-a11y": "^6.10.2", - "eslint-plugin-prettier": "^5.5.3", + "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", "eslint-plugin-unused-imports": "^4.1.4", "postcss": "^8.5.6", "postcss-preset-mantine": "^1.18.0", "postcss-simple-vars": "^7.0.1", "prettier": "^3.6.2", - "sass": "^1.89.2", + "sass": "^1.90.0", "tsc-alias": "^1.8.16", "tsup": "^8.5.0", "tsx": "^4.20.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06065a99..70dd731e 100755 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,6 +95,9 @@ importers: commander: specifier: ^14.0.0 version: 14.0.0 + cookie: + specifier: ^1.0.2 + version: 1.0.2 cross-env: specifier: ^10.0.0 version: 10.0.0 @@ -140,12 +143,6 @@ importers: multer: specifier: 2.0.2 version: 2.0.2 - next: - specifier: ^15.4.5 - version: 15.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.89.2) - nuqs: - specifier: ^2.4.3 - version: 2.4.3(next@15.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.89.2))(react@19.1.1) otplib: specifier: ^12.0.1 version: 12.0.1 @@ -164,6 +161,9 @@ importers: react-markdown: specifier: ^10.1.0 version: 10.1.0(@types/react@19.1.9)(react@19.1.1) + react-router-dom: + specifier: ^7.7.1 + version: 7.7.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) remark-gfm: specifier: ^4.0.1 version: 4.0.1 @@ -174,8 +174,11 @@ importers: specifier: ^2.3.4 version: 2.3.4(react@19.1.1) typescript-eslint: - specifier: ^8.38.0 - version: 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + specifier: ^8.39.0 + version: 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + vite: + specifier: ^7.1.0 + version: 7.1.0(@types/node@24.2.0)(jiti@2.5.1)(sass@1.90.0)(sugarss@5.0.1(postcss@8.5.6))(tsx@4.20.3) zod: specifier: ^3.25.67 version: 3.25.67 @@ -183,9 +186,6 @@ importers: specifier: ^5.0.7 version: 5.0.7(@types/react@19.1.9)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) devDependencies: - '@next/eslint-plugin-next': - specifier: ^15.4.5 - version: 15.4.5 '@types/bytes': specifier: ^3.1.5 version: 3.1.5 @@ -202,8 +202,8 @@ importers: specifier: ^2.0.0 version: 2.0.0 '@types/node': - specifier: ^24.1.0 - version: 24.1.0 + specifier: ^24.2.0 + version: 24.2.0 '@types/qrcode': specifier: ^1.5.5 version: 1.5.5 @@ -213,12 +213,12 @@ importers: '@types/react-dom': specifier: ^19.1.7 version: 19.1.7(@types/react@19.1.9) + '@vitejs/plugin-react': + specifier: ^5.0.0 + version: 5.0.0(vite@7.1.0(@types/node@24.2.0)(jiti@2.5.1)(sass@1.90.0)(sugarss@5.0.1(postcss@8.5.6))(tsx@4.20.3)) eslint: specifier: ^9.32.0 version: 9.32.0(jiti@2.5.1) - eslint-config-next: - specifier: ^15.4.5 - version: 15.4.5(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint-config-prettier: specifier: ^10.1.8 version: 10.1.8(eslint@9.32.0(jiti@2.5.1)) @@ -226,17 +226,20 @@ importers: specifier: ^6.10.2 version: 6.10.2(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-prettier: - specifier: ^5.5.3 - version: 5.5.3(eslint-config-prettier@10.1.8(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1))(prettier@3.6.2) + specifier: ^5.5.4 + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1))(prettier@3.6.2) eslint-plugin-react: specifier: ^7.37.5 version: 7.37.5(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-react-hooks: specifier: ^5.2.0 version: 5.2.0(eslint@9.32.0(jiti@2.5.1)) + eslint-plugin-react-refresh: + specifier: ^0.4.20 + version: 0.4.20(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-unused-imports: specifier: ^4.1.4 - version: 4.1.4(@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1)) + version: 4.1.4(@typescript-eslint/eslint-plugin@8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1)) postcss: specifier: ^8.5.6 version: 8.5.6 @@ -250,8 +253,8 @@ importers: specifier: ^3.6.2 version: 3.6.2 sass: - specifier: ^1.89.2 - version: 1.89.2 + specifier: ^1.90.0 + version: 1.90.0 tsc-alias: specifier: ^1.8.16 version: 1.8.16 @@ -267,6 +270,10 @@ importers: packages: + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@antfu/ni@0.21.12': resolution: {integrity: sha512-2aDL3WUv8hMJb2L3r/PIQWsTLyq7RQr3v9xD16fiz6O8ys1xEyLhhTOv8gxtZvJiTzjTF5pHoArvRdesGL1DMQ==} hasBin: true @@ -435,14 +442,89 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.0': + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.0': + resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.0': + resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.2': + resolution: {integrity: sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.0': + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.2': resolution: {integrity: sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==} engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.0': + resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + '@csstools/color-helpers@5.0.2': resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} engines: {node: '>=18'} @@ -471,15 +553,9 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@emnapi/core@1.4.5': - resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - '@emnapi/runtime@1.4.5': resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} - '@emnapi/wasi-threads@1.0.4': - resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} - '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -489,150 +565,306 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.8': + resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.5': resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.25.8': + resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.5': resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.25.8': + resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.5': resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.25.8': + resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.5': resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.25.8': + resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.5': resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.25.8': + resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.5': resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.25.8': + resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.5': resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.8': + resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.5': resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.25.8': + resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.5': resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.25.8': + resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.5': resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.25.8': + resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.5': resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.25.8': + resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.5': resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.25.8': + resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.5': resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.25.8': + resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.5': resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.25.8': + resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.5': resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.25.8': + resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.5': resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.25.8': + resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.5': resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.25.8': + resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.5': resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.8': + resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.5': resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.25.8': + resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.5': resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.8': + resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.8': + resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.5': resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.25.8': + resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.5': resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.25.8': + resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.5': resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.25.8': + resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.5': resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.25.8': + resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.7.0': resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -898,6 +1130,9 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.12': + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} @@ -913,9 +1148,15 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.4': + resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.29': + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@lukeed/ms@2.0.2': resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} engines: {node: '>=8'} @@ -992,63 +1233,6 @@ packages: peerDependencies: react: ^18.x || ^19.x - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - - '@next/env@15.4.5': - resolution: {integrity: sha512-ruM+q2SCOVCepUiERoxOmZY9ZVoecR3gcXNwCYZRvQQWRjhOiPJGmQ2fAiLR6YKWXcSAh7G79KEFxN3rwhs4LQ==} - - '@next/eslint-plugin-next@15.4.5': - resolution: {integrity: sha512-YhbrlbEt0m4jJnXHMY/cCUDBAWgd5SaTa5mJjzOt82QwflAFfW/h3+COp2TfVSzhmscIZ5sg2WXt3MLziqCSCw==} - - '@next/swc-darwin-arm64@15.4.5': - resolution: {integrity: sha512-84dAN4fkfdC7nX6udDLz9GzQlMUwEMKD7zsseXrl7FTeIItF8vpk1lhLEnsotiiDt+QFu3O1FVWnqwcRD2U3KA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@15.4.5': - resolution: {integrity: sha512-CL6mfGsKuFSyQjx36p2ftwMNSb8PQog8y0HO/ONLdQqDql7x3aJb/wB+LA651r4we2pp/Ck+qoRVUeZZEvSurA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@15.4.5': - resolution: {integrity: sha512-1hTVd9n6jpM/thnDc5kYHD1OjjWYpUJrJxY4DlEacT7L5SEOXIifIdTye6SQNNn8JDZrcN+n8AWOmeJ8u3KlvQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@15.4.5': - resolution: {integrity: sha512-4W+D/nw3RpIwGrqpFi7greZ0hjrCaioGErI7XHgkcTeWdZd146NNu1s4HnaHonLeNTguKnL2Urqvj28UJj6Gqw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@15.4.5': - resolution: {integrity: sha512-N6Mgdxe/Cn2K1yMHge6pclffkxzbSGOydXVKYOjYqQXZYjLCfN/CuFkaYDeDHY2VBwSHyM2fUjYBiQCIlxIKDA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@15.4.5': - resolution: {integrity: sha512-YZ3bNDrS8v5KiqgWE0xZQgtXgCTUacgFtnEgI4ccotAASwSvcMPDLua7BWLuTfucoRv6mPidXkITJLd8IdJplQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@15.4.5': - resolution: {integrity: sha512-9Wr4t9GkZmMNcTVvSloFtjzbH4vtT4a8+UHqDoVnxA5QyfWe6c5flTH1BIWPGNWSUlofc8dVJAE7j84FQgskvQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@15.4.5': - resolution: {integrity: sha512-voWk7XtGvlsP+w8VBz7lqp8Y+dYw/MTI4KeS0gTVtfdhdJ5QwhXLmNrndFOin/MDoCvUaLWMkYKATaCoUkt2/A==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1061,10 +1245,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - '@otplib/core@12.0.1': resolution: {integrity: sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA==} @@ -1256,111 +1436,208 @@ packages: '@prisma/ts-builders@6.13.0': resolution: {integrity: sha512-/8AiAvzzTxZI1PKM7dFb8kO6f4BB6eW5HI2e854ZzGS0hCiz8/ksQ6KhNWXv+isF0jsqqh1ChVdhsJSj1Odk1g==} + '@rolldown/pluginutils@1.0.0-beta.30': + resolution: {integrity: sha512-whXaSoNUFiyDAjkUF8OBpOm77Szdbk5lGNqFe6CbVbJFrhCCPinCbRA3NjawwlNHla1No7xvXXh+CpSxnPfUEw==} + '@rollup/rollup-android-arm-eabi@4.44.0': resolution: {integrity: sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==} cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.46.2': + resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.44.0': resolution: {integrity: sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.46.2': + resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.44.0': resolution: {integrity: sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.46.2': + resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.44.0': resolution: {integrity: sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.46.2': + resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.44.0': resolution: {integrity: sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.46.2': + resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.44.0': resolution: {integrity: sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.46.2': + resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.44.0': resolution: {integrity: sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.44.0': resolution: {integrity: sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.44.0': resolution: {integrity: sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.46.2': + resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-arm64-musl@4.44.0': resolution: {integrity: sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-musl@4.46.2': + resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.44.0': resolution: {integrity: sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==} cpu: [loong64] os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + cpu: [loong64] + os: [linux] + '@rollup/rollup-linux-powerpc64le-gnu@4.44.0': resolution: {integrity: sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==} cpu: [ppc64] os: [linux] + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + cpu: [ppc64] + os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.44.0': resolution: {integrity: sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.44.0': resolution: {integrity: sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.46.2': + resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.44.0': resolution: {integrity: sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==} cpu: [s390x] os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.46.2': + resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + cpu: [s390x] + os: [linux] + '@rollup/rollup-linux-x64-gnu@4.44.0': resolution: {integrity: sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-gnu@4.46.2': + resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} + cpu: [x64] + os: [linux] + '@rollup/rollup-linux-x64-musl@4.44.0': resolution: {integrity: sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-musl@4.46.2': + resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + cpu: [x64] + os: [linux] + '@rollup/rollup-win32-arm64-msvc@4.44.0': resolution: {integrity: sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.46.2': + resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.44.0': resolution: {integrity: sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.46.2': + resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + cpu: [ia32] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.44.0': resolution: {integrity: sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==} cpu: [x64] os: [win32] - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@rushstack/eslint-patch@1.12.0': - resolution: {integrity: sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==} + '@rollup/rollup-win32-x64-msvc@4.46.2': + resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + cpu: [x64] + os: [win32] '@smithy/abort-controller@4.0.4': resolution: {integrity: sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==} @@ -1577,9 +1854,6 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@tabler/icons-react@3.34.1': resolution: {integrity: sha512-Ld6g0NqOO05kyyHsfU8h787PdHBm7cFmOycQSIrGp45XcXYDuOK2Bs0VC4T2FWSKZ6bx5g04imfzazf/nqtk1A==} peerDependencies: @@ -1588,8 +1862,17 @@ packages: '@tabler/icons@3.34.1': resolution: {integrity: sha512-9gTnUvd7Fd/DmQgr3MKY+oJLa1RfNsQo8c/ir3TJAWghOuZXodbtbVp0QBY2DxWuuvrSZFys0HEbv1CoiI5y6A==} - '@tybys/wasm-util@0.10.0': - resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -1654,9 +1937,6 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/katex@0.16.7': resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} @@ -1672,8 +1952,8 @@ packages: '@types/multer@2.0.0': resolution: {integrity: sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==} - '@types/node@24.1.0': - resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==} + '@types/node@24.2.0': + resolution: {integrity: sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1713,162 +1993,73 @@ packages: '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@typescript-eslint/eslint-plugin@8.38.0': - resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} + '@typescript-eslint/eslint-plugin@8.39.0': + resolution: {integrity: sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.38.0 + '@typescript-eslint/parser': ^8.39.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.38.0': - resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} + '@typescript-eslint/parser@8.39.0': + resolution: {integrity: sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.38.0': - resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} + '@typescript-eslint/project-service@8.39.0': + resolution: {integrity: sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.38.0': - resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} + '@typescript-eslint/scope-manager@8.39.0': + resolution: {integrity: sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.38.0': - resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} + '@typescript-eslint/tsconfig-utils@8.39.0': + resolution: {integrity: sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.38.0': - resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} + '@typescript-eslint/type-utils@8.39.0': + resolution: {integrity: sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.38.0': - resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} + '@typescript-eslint/types@8.39.0': + resolution: {integrity: sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.38.0': - resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} + '@typescript-eslint/typescript-estree@8.39.0': + resolution: {integrity: sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.38.0': - resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} + '@typescript-eslint/utils@8.39.0': + resolution: {integrity: sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.38.0': - resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} + '@typescript-eslint/visitor-keys@8.39.0': + resolution: {integrity: sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} - cpu: [arm] - os: [android] - - '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} - cpu: [arm64] - os: [android] - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} - cpu: [arm64] - os: [darwin] - - '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} - cpu: [x64] - os: [darwin] - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} - cpu: [x64] - os: [freebsd] - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} - cpu: [arm64] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} - cpu: [arm64] - os: [linux] - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} - cpu: [ppc64] - os: [linux] - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} - cpu: [riscv64] - os: [linux] - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} - cpu: [riscv64] - os: [linux] - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} - cpu: [s390x] - os: [linux] - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} - cpu: [x64] - os: [linux] - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} - cpu: [x64] - os: [linux] - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} - cpu: [arm64] - os: [win32] - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} - cpu: [ia32] - os: [win32] - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} - cpu: [x64] - os: [win32] + '@vitejs/plugin-react@5.0.0': + resolution: {integrity: sha512-Jx9JfsTa05bYkS9xo0hkofp2dCmp1blrKjw9JONs5BTHOvJCgLbaPSuZLGSVJW6u2qe0tc4eevY0+gSNNi0YCw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -1957,10 +2148,6 @@ packages: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - array.prototype.flat@1.3.3: resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} @@ -2036,6 +2223,11 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.25.1: + resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2129,9 +2321,6 @@ packages: citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -2196,6 +2385,9 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -2291,14 +2483,6 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -2400,6 +2584,9 @@ packages: effect@3.16.12: resolution: {integrity: sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==} + electron-to-chromium@1.5.198: + resolution: {integrity: sha512-G5COfnp3w+ydVu80yprgWSfmfQaYRh9DOxfhAxstLyetKaLyl55QrNjx8C38Pc/C+RaDmb1M0Lk8wPEMQ+bGgQ==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2451,6 +2638,15 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.25.8: + resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -2462,76 +2658,20 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-next@15.4.5: - resolution: {integrity: sha512-IMijiXaZ43qFB+Gcpnb374ipTKD8JIyVNR+6VsifFQ/LHyx+A9wgcgSIhCX5PYSjwOoSYD5LtNHKlM5uc23eww==} - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 - typescript: '>=3.3.1' - peerDependenciesMeta: - typescript: - optional: true - eslint-config-prettier@10.1.8: resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true peerDependencies: eslint: '>=7.0.0' - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-import-resolver-typescript@3.10.1: - resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-import@2.32.0: - resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint-plugin-jsx-a11y@6.10.2: resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} engines: {node: '>=4.0'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-prettier@5.5.3: - resolution: {integrity: sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==} + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -2550,6 +2690,11 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + eslint-plugin-react-refresh@0.4.20: + resolution: {integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==} + peerDependencies: + eslint: '>=8.40' + eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} @@ -2640,10 +2785,6 @@ packages: resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==} engines: {node: '>=6.0.0'} - fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -2769,6 +2910,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2985,9 +3130,6 @@ packages: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} - is-bun-module@2.0.0: - resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -3134,6 +3276,11 @@ packages: canvas: optional: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -3149,8 +3296,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} hasBin: true jsonfile@6.1.0: @@ -3235,6 +3383,9 @@ packages: resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} engines: {node: 20 || >=22} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -3426,9 +3577,6 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -3455,35 +3603,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - napi-postinstall@0.3.2: - resolution: {integrity: sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true - natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.4.5: - resolution: {integrity: sha512-nJ4v+IO9CPmbmcvsPebIoX3Q+S7f6Fu08/dEWu0Ttfa+wVwQRh9epcmsyCPjmL2b8MxC+CkBR97jgDhUUztI3g==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -3498,6 +3620,9 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + normalize-package-data@6.0.2: resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} engines: {node: ^16.14.0 || >=18.0.0} @@ -3506,24 +3631,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - nuqs@2.4.3: - resolution: {integrity: sha512-BgtlYpvRwLYiJuWzxt34q2bXu/AIS66sLU1QePIMr2LWkb+XH0vKXdbLSgn9t6p7QKzwI7f38rX3Wl9llTXQ8Q==} - peerDependencies: - '@remix-run/react': '>=2' - next: '>=14.2.0' - react: '>=18.2.0 || ^19.0.0-0' - react-router: ^6 || ^7 - react-router-dom: ^6 || ^7 - peerDependenciesMeta: - '@remix-run/react': - optional: true - next: - optional: true - react-router: - optional: true - react-router-dom: - optional: true - nwsapi@2.2.21: resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} @@ -3556,10 +3663,6 @@ packages: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - object.values@1.2.1: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} @@ -3701,6 +3804,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} @@ -3792,10 +3899,6 @@ packages: peerDependencies: postcss: ^8.2.1 - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -3913,6 +4016,10 @@ packages: react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -3933,6 +4040,23 @@ packages: '@types/react': optional: true + react-router-dom@7.7.1: + resolution: {integrity: sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.7.1: + resolution: {integrity: sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react-smooth@4.0.4: resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} peerDependencies: @@ -4041,11 +4165,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true @@ -4066,6 +4185,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.46.2: + resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -4097,8 +4221,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.89.2: - resolution: {integrity: sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==} + sass@1.90.0: + resolution: {integrity: sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==} engines: {node: '>=14.0.0'} hasBin: true @@ -4217,9 +4341,6 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - stable-hash@0.0.5: - resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} - statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -4280,10 +4401,6 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4297,19 +4414,6 @@ packages: style-to-object@1.0.9: resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} - styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -4428,9 +4532,6 @@ packages: engines: {node: '>=16.20.2'} hasBin: true - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -4489,12 +4590,12 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.38.0: - resolution: {integrity: sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==} + typescript-eslint@8.39.0: + resolution: {integrity: sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} @@ -4511,8 +4612,8 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici-types@7.8.0: - resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} @@ -4540,8 +4641,11 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - unrs-resolver@1.11.1: - resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -4621,6 +4725,46 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vite@7.1.0: + resolution: {integrity: sha512-3jdAy3NhBJYsa/lCFcnRfbK4kNkO/bhijFCnv5ByUQk/eekYagoV2yQSISUrhpV+5JiY5hmwOh7jNnQ68dFMuQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -4717,6 +4861,9 @@ packages: y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -4755,6 +4902,11 @@ packages: snapshots: + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + '@antfu/ni@0.21.12': {} '@asamuzakjp/css-color@3.2.0': @@ -5248,10 +5400,114 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/compat-data@7.28.0': {} + + '@babel/core@7.28.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helpers': 7.28.2 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.2 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.0': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.2 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.2': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + + '@babel/parser@7.28.0': + dependencies: + '@babel/types': 7.28.2 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/runtime@7.28.2': {} + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + + '@babel/traverse@7.28.0': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@csstools/color-helpers@5.0.2': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -5272,99 +5528,166 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} - '@emnapi/core@1.4.5': - dependencies: - '@emnapi/wasi-threads': 1.0.4 - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.4.5': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.0.4': - dependencies: - tslib: 2.8.1 - optional: true - '@epic-web/invariant@1.0.0': {} '@esbuild/aix-ppc64@0.25.5': optional: true + '@esbuild/aix-ppc64@0.25.8': + optional: true + '@esbuild/android-arm64@0.25.5': optional: true + '@esbuild/android-arm64@0.25.8': + optional: true + '@esbuild/android-arm@0.25.5': optional: true + '@esbuild/android-arm@0.25.8': + optional: true + '@esbuild/android-x64@0.25.5': optional: true + '@esbuild/android-x64@0.25.8': + optional: true + '@esbuild/darwin-arm64@0.25.5': optional: true + '@esbuild/darwin-arm64@0.25.8': + optional: true + '@esbuild/darwin-x64@0.25.5': optional: true + '@esbuild/darwin-x64@0.25.8': + optional: true + '@esbuild/freebsd-arm64@0.25.5': optional: true + '@esbuild/freebsd-arm64@0.25.8': + optional: true + '@esbuild/freebsd-x64@0.25.5': optional: true + '@esbuild/freebsd-x64@0.25.8': + optional: true + '@esbuild/linux-arm64@0.25.5': optional: true + '@esbuild/linux-arm64@0.25.8': + optional: true + '@esbuild/linux-arm@0.25.5': optional: true + '@esbuild/linux-arm@0.25.8': + optional: true + '@esbuild/linux-ia32@0.25.5': optional: true + '@esbuild/linux-ia32@0.25.8': + optional: true + '@esbuild/linux-loong64@0.25.5': optional: true + '@esbuild/linux-loong64@0.25.8': + optional: true + '@esbuild/linux-mips64el@0.25.5': optional: true + '@esbuild/linux-mips64el@0.25.8': + optional: true + '@esbuild/linux-ppc64@0.25.5': optional: true + '@esbuild/linux-ppc64@0.25.8': + optional: true + '@esbuild/linux-riscv64@0.25.5': optional: true + '@esbuild/linux-riscv64@0.25.8': + optional: true + '@esbuild/linux-s390x@0.25.5': optional: true + '@esbuild/linux-s390x@0.25.8': + optional: true + '@esbuild/linux-x64@0.25.5': optional: true + '@esbuild/linux-x64@0.25.8': + optional: true + '@esbuild/netbsd-arm64@0.25.5': optional: true + '@esbuild/netbsd-arm64@0.25.8': + optional: true + '@esbuild/netbsd-x64@0.25.5': optional: true + '@esbuild/netbsd-x64@0.25.8': + optional: true + '@esbuild/openbsd-arm64@0.25.5': optional: true + '@esbuild/openbsd-arm64@0.25.8': + optional: true + '@esbuild/openbsd-x64@0.25.5': optional: true + '@esbuild/openbsd-x64@0.25.8': + optional: true + + '@esbuild/openharmony-arm64@0.25.8': + optional: true + '@esbuild/sunos-x64@0.25.5': optional: true + '@esbuild/sunos-x64@0.25.8': + optional: true + '@esbuild/win32-arm64@0.25.5': optional: true + '@esbuild/win32-arm64@0.25.8': + optional: true + '@esbuild/win32-ia32@0.25.5': optional: true + '@esbuild/win32-ia32@0.25.8': + optional: true + '@esbuild/win32-x64@0.25.5': optional: true + '@esbuild/win32-x64@0.25.8': + optional: true + '@eslint-community/eslint-utils@4.7.0(eslint@9.32.0(jiti@2.5.1))': dependencies: eslint: 9.32.0(jiti@2.5.1) @@ -5630,6 +5953,11 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.12': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 @@ -5642,11 +5970,18 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.4': {} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.29': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.4 + '@lukeed/ms@2.0.2': {} '@mantine/charts@8.2.2(@mantine/core@8.2.2(@mantine/hooks@8.2.2(react@19.1.1))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mantine/hooks@8.2.2(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(recharts@2.15.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))': @@ -5727,43 +6062,6 @@ snapshots: dependencies: react: 19.1.1 - '@napi-rs/wasm-runtime@0.2.12': - dependencies: - '@emnapi/core': 1.4.5 - '@emnapi/runtime': 1.4.5 - '@tybys/wasm-util': 0.10.0 - optional: true - - '@next/env@15.4.5': {} - - '@next/eslint-plugin-next@15.4.5': - dependencies: - fast-glob: 3.3.1 - - '@next/swc-darwin-arm64@15.4.5': - optional: true - - '@next/swc-darwin-x64@15.4.5': - optional: true - - '@next/swc-linux-arm64-gnu@15.4.5': - optional: true - - '@next/swc-linux-arm64-musl@15.4.5': - optional: true - - '@next/swc-linux-x64-gnu@15.4.5': - optional: true - - '@next/swc-linux-x64-musl@15.4.5': - optional: true - - '@next/swc-win32-arm64-msvc@15.4.5': - optional: true - - '@next/swc-win32-x64-msvc@15.4.5': - optional: true - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5776,8 +6074,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@nolyfill/is-core-module@1.0.39': {} - '@otplib/core@12.0.1': {} '@otplib/plugin-crypto@12.0.1': @@ -6045,69 +6341,127 @@ snapshots: - magicast - typescript + '@rolldown/pluginutils@1.0.0-beta.30': {} + '@rollup/rollup-android-arm-eabi@4.44.0': optional: true + '@rollup/rollup-android-arm-eabi@4.46.2': + optional: true + '@rollup/rollup-android-arm64@4.44.0': optional: true + '@rollup/rollup-android-arm64@4.46.2': + optional: true + '@rollup/rollup-darwin-arm64@4.44.0': optional: true + '@rollup/rollup-darwin-arm64@4.46.2': + optional: true + '@rollup/rollup-darwin-x64@4.44.0': optional: true + '@rollup/rollup-darwin-x64@4.46.2': + optional: true + '@rollup/rollup-freebsd-arm64@4.44.0': optional: true + '@rollup/rollup-freebsd-arm64@4.46.2': + optional: true + '@rollup/rollup-freebsd-x64@4.44.0': optional: true + '@rollup/rollup-freebsd-x64@4.46.2': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.44.0': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.44.0': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.44.0': optional: true + '@rollup/rollup-linux-arm64-gnu@4.46.2': + optional: true + '@rollup/rollup-linux-arm64-musl@4.44.0': optional: true + '@rollup/rollup-linux-arm64-musl@4.46.2': + optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.44.0': optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + optional: true + '@rollup/rollup-linux-powerpc64le-gnu@4.44.0': optional: true + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.44.0': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + optional: true + '@rollup/rollup-linux-riscv64-musl@4.44.0': optional: true + '@rollup/rollup-linux-riscv64-musl@4.46.2': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.44.0': optional: true + '@rollup/rollup-linux-s390x-gnu@4.46.2': + optional: true + '@rollup/rollup-linux-x64-gnu@4.44.0': optional: true + '@rollup/rollup-linux-x64-gnu@4.46.2': + optional: true + '@rollup/rollup-linux-x64-musl@4.44.0': optional: true + '@rollup/rollup-linux-x64-musl@4.46.2': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.44.0': optional: true + '@rollup/rollup-win32-arm64-msvc@4.46.2': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.44.0': optional: true + '@rollup/rollup-win32-ia32-msvc@4.46.2': + optional: true + '@rollup/rollup-win32-x64-msvc@4.44.0': optional: true - '@rtsao/scc@1.1.0': {} - - '@rushstack/eslint-patch@1.12.0': {} + '@rollup/rollup-win32-x64-msvc@4.46.2': + optional: true '@smithy/abort-controller@4.0.4': dependencies: @@ -6444,10 +6798,6 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - '@tabler/icons-react@3.34.1(react@19.1.1)': dependencies: '@tabler/icons': 3.34.1 @@ -6455,21 +6805,37 @@ snapshots: '@tabler/icons@3.34.1': {} - '@tybys/wasm-util@0.10.0': + '@types/babel__core@7.20.5': dependencies: - tslib: 2.8.1 - optional: true + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.2 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.2 '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/bytes@3.1.5': {} '@types/connect@3.4.38': dependencies: - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/d3-array@3.2.1': {} @@ -6507,7 +6873,7 @@ snapshots: '@types/express-serve-static-core@5.0.7': dependencies: - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 0.17.5 @@ -6520,7 +6886,7 @@ snapshots: '@types/fluent-ffmpeg@2.1.27': dependencies: - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/hast@3.0.4': dependencies: @@ -6530,8 +6896,6 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/json5@0.0.29': {} - '@types/katex@0.16.7': {} '@types/mdast@4.0.4': @@ -6546,15 +6910,15 @@ snapshots: dependencies: '@types/express': 5.0.3 - '@types/node@24.1.0': + '@types/node@24.2.0': dependencies: - undici-types: 7.8.0 + undici-types: 7.10.0 '@types/normalize-package-data@2.4.4': {} '@types/qrcode@1.5.5': dependencies: - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/qs@6.14.0': {} @@ -6571,12 +6935,12 @@ snapshots: '@types/send@0.17.5': dependencies: '@types/mime': 1.3.5 - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/serve-static@1.15.8': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 24.1.0 + '@types/node': 24.2.0 '@types/send': 0.17.5 '@types/trusted-types@2.0.7': @@ -6588,14 +6952,14 @@ snapshots: '@types/uuid@9.0.8': {} - '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/type-utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/type-utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.39.0 eslint: 9.32.0(jiti@2.5.1) graphemer: 1.4.0 ignore: 7.0.5 @@ -6605,41 +6969,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.39.0 debug: 4.4.1 eslint: 9.32.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.38.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.39.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 debug: 4.4.1 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.38.0': + '@typescript-eslint/scope-manager@8.39.0': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 - '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.39.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) debug: 4.4.1 eslint: 9.32.0(jiti@2.5.1) ts-api-utils: 2.1.0(typescript@5.9.2) @@ -6647,14 +7011,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.38.0': {} + '@typescript-eslint/types@8.39.0': {} - '@typescript-eslint/typescript-estree@8.38.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.39.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.38.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/project-service': 8.39.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 @@ -6665,82 +7029,35 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/utils@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0(jiti@2.5.1)) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.38.0': + '@typescript-eslint/visitor-keys@8.39.0': dependencies: - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/types': 8.39.0 eslint-visitor-keys: 4.2.1 '@ungap/structured-clone@1.3.0': {} - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - optional: true - - '@unrs/resolver-binding-android-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': + '@vitejs/plugin-react@5.0.0(vite@7.1.0(@types/node@24.2.0)(jiti@2.5.1)(sass@1.90.0)(sugarss@5.0.1(postcss@8.5.6))(tsx@4.20.3))': dependencies: - '@napi-rs/wasm-runtime': 0.2.12 - optional: true - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - optional: true + '@babel/core': 7.28.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.0) + '@rolldown/pluginutils': 1.0.0-beta.30 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.1.0(@types/node@24.2.0)(jiti@2.5.1)(sass@1.90.0)(sugarss@5.0.1(postcss@8.5.6))(tsx@4.20.3) + transitivePeerDependencies: + - supports-color abstract-logging@2.0.1: {} @@ -6828,16 +7145,6 @@ snapshots: es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 - array.prototype.findlastindex@1.2.6: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - array.prototype.flat@1.3.3: dependencies: call-bind: 1.0.8 @@ -6916,6 +7223,13 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.25.1: + dependencies: + caniuse-lite: 1.0.30001731 + electron-to-chromium: 1.5.198 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.1) + buffer-from@1.1.2: {} buffer@5.6.0: @@ -7013,8 +7327,6 @@ snapshots: dependencies: consola: 3.4.2 - client-only@0.0.1: {} - cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -7070,6 +7382,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + convert-source-map@2.0.0: {} + cookie@0.7.2: {} cookie@1.0.2: {} @@ -7159,10 +7473,6 @@ snapshots: dayjs@1.11.13: {} - debug@3.2.7: - dependencies: - ms: 2.1.3 - debug@4.4.1: dependencies: ms: 2.1.3 @@ -7248,6 +7558,8 @@ snapshots: '@standard-schema/spec': 1.0.0 fast-check: 3.23.2 + electron-to-chromium@1.5.198: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -7385,99 +7697,47 @@ snapshots: '@esbuild/win32-ia32': 0.25.5 '@esbuild/win32-x64': 0.25.5 + esbuild@0.25.8: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.8 + '@esbuild/android-arm': 0.25.8 + '@esbuild/android-arm64': 0.25.8 + '@esbuild/android-x64': 0.25.8 + '@esbuild/darwin-arm64': 0.25.8 + '@esbuild/darwin-x64': 0.25.8 + '@esbuild/freebsd-arm64': 0.25.8 + '@esbuild/freebsd-x64': 0.25.8 + '@esbuild/linux-arm': 0.25.8 + '@esbuild/linux-arm64': 0.25.8 + '@esbuild/linux-ia32': 0.25.8 + '@esbuild/linux-loong64': 0.25.8 + '@esbuild/linux-mips64el': 0.25.8 + '@esbuild/linux-ppc64': 0.25.8 + '@esbuild/linux-riscv64': 0.25.8 + '@esbuild/linux-s390x': 0.25.8 + '@esbuild/linux-x64': 0.25.8 + '@esbuild/netbsd-arm64': 0.25.8 + '@esbuild/netbsd-x64': 0.25.8 + '@esbuild/openbsd-arm64': 0.25.8 + '@esbuild/openbsd-x64': 0.25.8 + '@esbuild/openharmony-arm64': 0.25.8 + '@esbuild/sunos-x64': 0.25.8 + '@esbuild/win32-arm64': 0.25.8 + '@esbuild/win32-ia32': 0.25.8 + '@esbuild/win32-x64': 0.25.8 + + escalade@3.2.0: {} + escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} - eslint-config-next@15.4.5(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2): - dependencies: - '@next/eslint-plugin-next': 15.4.5 - '@rushstack/eslint-patch': 1.12.0 - '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.32.0(jiti@2.5.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-react: 7.37.5(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.32.0(jiti@2.5.1)) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - eslint-config-prettier@10.1.8(eslint@9.32.0(jiti@2.5.1)): dependencies: eslint: 9.32.0(jiti@2.5.1) - eslint-import-resolver-node@0.3.9: - dependencies: - debug: 3.2.7 - is-core-module: 2.16.1 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color - - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1 - eslint: 9.32.0(jiti@2.5.1) - get-tsconfig: 4.10.1 - is-bun-module: 2.0.0 - stable-hash: 0.0.5 - tinyglobby: 0.2.14 - unrs-resolver: 1.11.1 - optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.32.0(jiti@2.5.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)) - transitivePeerDependencies: - - supports-color - - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 9.32.0(jiti@2.5.1) - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.32.0(jiti@2.5.1)): dependencies: aria-query: 5.3.2 @@ -7497,7 +7757,7 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-prettier@5.5.3(eslint-config-prettier@10.1.8(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1))(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1))(prettier@3.6.2): dependencies: eslint: 9.32.0(jiti@2.5.1) prettier: 3.6.2 @@ -7510,6 +7770,10 @@ snapshots: dependencies: eslint: 9.32.0(jiti@2.5.1) + eslint-plugin-react-refresh@0.4.20(eslint@9.32.0(jiti@2.5.1)): + dependencies: + eslint: 9.32.0(jiti@2.5.1) + eslint-plugin-react@7.37.5(eslint@9.32.0(jiti@2.5.1)): dependencies: array-includes: 3.1.9 @@ -7532,11 +7796,11 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1)): + eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1)): dependencies: eslint: 9.32.0(jiti@2.5.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint-scope@8.4.0: dependencies: @@ -7629,14 +7893,6 @@ snapshots: fast-equals@5.2.2: {} - fast-glob@3.3.1: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -7698,6 +7954,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.4.6(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + fflate@0.8.2: {} file-entry-cache@8.0.0: @@ -7785,6 +8045,8 @@ snapshots: functions-have-names@1.2.3: {} + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} get-intrinsic@1.3.0: @@ -8039,10 +8301,6 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-bun-module@2.0.0: - dependencies: - semver: 7.7.2 - is-callable@1.2.7: {} is-core-module@2.16.1: @@ -8207,6 +8465,8 @@ snapshots: - supports-color - utf-8-validate + jsesc@3.1.0: {} + json-buffer@3.0.1: {} json-schema-ref-resolver@2.0.1: @@ -8219,9 +8479,7 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json5@1.0.2: - dependencies: - minimist: 1.2.8 + json5@2.2.3: {} jsonfile@6.1.0: dependencies: @@ -8300,6 +8558,10 @@ snapshots: lru-cache@11.1.0: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -8693,8 +8955,6 @@ snapshots: minipass@7.1.2: {} - mitt@3.0.1: {} - mkdirp@0.5.6: dependencies: minimist: 1.2.8 @@ -8728,34 +8988,8 @@ snapshots: nanoid@3.3.11: {} - napi-postinstall@0.3.2: {} - natural-compare@1.4.0: {} - next@15.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.89.2): - dependencies: - '@next/env': 15.4.5 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001731 - postcss: 8.4.31 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - styled-jsx: 5.1.6(react@19.1.1) - optionalDependencies: - '@next/swc-darwin-arm64': 15.4.5 - '@next/swc-darwin-x64': 15.4.5 - '@next/swc-linux-arm64-gnu': 15.4.5 - '@next/swc-linux-arm64-musl': 15.4.5 - '@next/swc-linux-x64-gnu': 15.4.5 - '@next/swc-linux-x64-musl': 15.4.5 - '@next/swc-win32-arm64-msvc': 15.4.5 - '@next/swc-win32-x64-msvc': 15.4.5 - sass: 1.89.2 - sharp: 0.34.3 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - node-addon-api@7.1.1: optional: true @@ -8765,6 +8999,8 @@ snapshots: node-gyp-build@4.8.4: {} + node-releases@2.0.19: {} + normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 @@ -8773,13 +9009,6 @@ snapshots: normalize-path@3.0.0: {} - nuqs@2.4.3(next@15.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.89.2))(react@19.1.1): - dependencies: - mitt: 3.0.1 - react: 19.1.1 - optionalDependencies: - next: 15.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(sass@1.89.2) - nwsapi@2.2.21: {} nypm@0.6.1: @@ -8819,12 +9048,6 @@ snapshots: es-abstract: 1.24.0 es-object-atoms: 1.1.1 - object.groupby@1.0.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - object.values@1.2.1: dependencies: call-bind: 1.0.8 @@ -8970,6 +9193,8 @@ snapshots: picomatch@4.0.2: {} + picomatch@4.0.3: {} + pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 @@ -9059,12 +9284,6 @@ snapshots: dependencies: postcss: 8.5.6 - postcss@8.4.31: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -9177,6 +9396,8 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) + react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.1.9)(react@19.1.1): dependencies: react: 19.1.1 @@ -9196,6 +9417,20 @@ snapshots: optionalDependencies: '@types/react': 19.1.9 + react-router-dom@7.7.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-router: 7.7.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + + react-router@7.7.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + cookie: 1.0.2 + react: 19.1.1 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + react-smooth@4.0.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: fast-equals: 5.2.2 @@ -9343,12 +9578,6 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.5: dependencies: is-core-module: 2.16.1 @@ -9387,6 +9616,32 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.44.0 fsevents: 2.3.3 + rollup@4.46.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.46.2 + '@rollup/rollup-android-arm64': 4.46.2 + '@rollup/rollup-darwin-arm64': 4.46.2 + '@rollup/rollup-darwin-x64': 4.46.2 + '@rollup/rollup-freebsd-arm64': 4.46.2 + '@rollup/rollup-freebsd-x64': 4.46.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 + '@rollup/rollup-linux-arm-musleabihf': 4.46.2 + '@rollup/rollup-linux-arm64-gnu': 4.46.2 + '@rollup/rollup-linux-arm64-musl': 4.46.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 + '@rollup/rollup-linux-ppc64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-musl': 4.46.2 + '@rollup/rollup-linux-s390x-gnu': 4.46.2 + '@rollup/rollup-linux-x64-gnu': 4.46.2 + '@rollup/rollup-linux-x64-musl': 4.46.2 + '@rollup/rollup-win32-arm64-msvc': 4.46.2 + '@rollup/rollup-win32-ia32-msvc': 4.46.2 + '@rollup/rollup-win32-x64-msvc': 4.46.2 + fsevents: 2.3.3 + rrweb-cssom@0.8.0: {} run-parallel@1.2.0: @@ -9422,7 +9677,7 @@ snapshots: safer-buffer@2.1.2: {} - sass@1.89.2: + sass@1.90.0: dependencies: chokidar: 4.0.3 immutable: 5.1.3 @@ -9573,8 +9828,6 @@ snapshots: split2@4.2.0: {} - stable-hash@0.0.5: {} - statuses@2.0.1: {} stop-iteration-iterator@1.1.0: @@ -9668,8 +9921,6 @@ snapshots: dependencies: ansi-regex: 6.1.0 - strip-bom@3.0.0: {} - strip-json-comments@3.1.1: {} strnum@2.1.1: {} @@ -9682,11 +9933,6 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - styled-jsx@5.1.6(react@19.1.1): - dependencies: - client-only: 0.0.1 - react: 19.1.1 - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -9796,13 +10042,6 @@ snapshots: normalize-path: 3.0.0 plimit-lit: 1.6.1 - tsconfig-paths@3.15.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - tslib@2.8.1: {} tsup@8.5.0(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.9.2): @@ -9886,12 +10125,12 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2): + typescript-eslint@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: @@ -9910,7 +10149,7 @@ snapshots: uncrypto@0.1.3: {} - undici-types@7.8.0: {} + undici-types@7.10.0: {} unicorn-magic@0.1.0: {} @@ -9949,29 +10188,11 @@ snapshots: universalify@2.0.1: {} - unrs-resolver@1.11.1: + update-browserslist-db@1.1.3(browserslist@4.25.1): dependencies: - napi-postinstall: 0.3.2 - optionalDependencies: - '@unrs/resolver-binding-android-arm-eabi': 1.11.1 - '@unrs/resolver-binding-android-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-x64': 1.11.1 - '@unrs/resolver-binding-freebsd-x64': 1.11.1 - '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 - '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 - '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-musl': 1.11.1 - '@unrs/resolver-binding-wasm32-wasi': 1.11.1 - '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 - '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 - '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + browserslist: 4.25.1 + escalade: 3.2.0 + picocolors: 1.1.1 uri-js@4.4.1: dependencies: @@ -10053,6 +10274,22 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vite@7.1.0(@types/node@24.2.0)(jiti@2.5.1)(sass@1.90.0)(sugarss@5.0.1(postcss@8.5.6))(tsx@4.20.3): + dependencies: + esbuild: 0.25.8 + fdir: 6.4.6(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.46.2 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 24.2.0 + fsevents: 2.3.3 + jiti: 2.5.1 + sass: 1.90.0 + sugarss: 5.0.1(postcss@8.5.6) + tsx: 4.20.3 + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -10159,6 +10396,8 @@ snapshots: y18n@4.0.3: {} + yallist@3.1.1: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 561b9a99..1b447125 100755 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,6 +1,7 @@ generator client { - provider = "prisma-client-js" - output = "../generated/client" + provider = "prisma-client" + output = "../src/prisma" + moduleFormat = "cjs" previewFeatures = ["queryCompiler", "driverAdapters"] } diff --git a/src/client/Root.tsx b/src/client/Root.tsx new file mode 100644 index 00000000..beb7fdee --- /dev/null +++ b/src/client/Root.tsx @@ -0,0 +1,47 @@ +import { ModalsProvider } from '@mantine/modals'; +import { Notifications } from '@mantine/notifications'; +import { Outlet } from 'react-router-dom'; +import { SWRConfig } from 'swr'; +import ThemeProvider from '@/components/ThemeProvider'; +import { type ZiplineTheme } from '@/lib/theme'; +import { type Config } from '@/lib/config/validate'; + +export default function Root({ + themes, + defaultTheme, +}: { + themes?: ZiplineTheme[]; + defaultTheme?: Config['website']['theme']; +}) { + return ( + { + const res = await fetch(url); + + if (!res.ok) { + const json = await res.json(); + + throw new Error(json.message); + } + + return res.json(); + }, + }} + > + + + + + + + + ); +} diff --git a/src/client/error/DashboardErrorBoundary.tsx b/src/client/error/DashboardErrorBoundary.tsx new file mode 100644 index 00000000..d89aed18 --- /dev/null +++ b/src/client/error/DashboardErrorBoundary.tsx @@ -0,0 +1,11 @@ +import GenericError from './GenericError'; + +export default function DashboardErrorBoundary(props: Record) { + return ( + + ); +} diff --git a/src/client/error/GenericError.tsx b/src/client/error/GenericError.tsx new file mode 100644 index 00000000..c0854b03 --- /dev/null +++ b/src/client/error/GenericError.tsx @@ -0,0 +1,27 @@ +import { Container, Paper, Stack, Text, Title } from '@mantine/core'; + +export default function GenericError({ + title, + message, + details, +}: { + title?: string; + message?: string; + details?: Record; +}) { + return ( + + + {title || 'An error occurred'} + + {message || 'Something went wrong. Please try again later, or report this issue if it persists.'} + + {details && ( + +
{JSON.stringify(details, null, 2)}
+
+ )} +
+
+ ); +} diff --git a/src/client/error/RootErrorBoundary.tsx b/src/client/error/RootErrorBoundary.tsx new file mode 100644 index 00000000..d4d206a6 --- /dev/null +++ b/src/client/error/RootErrorBoundary.tsx @@ -0,0 +1,11 @@ +import GenericError from './GenericError'; + +export default function RootErrorBoundary(props: Record) { + return ( + + ); +} diff --git a/src/client/index.html b/src/client/index.html new file mode 100644 index 00000000..1faf8e2c --- /dev/null +++ b/src/client/index.html @@ -0,0 +1,12 @@ + + + + + + Zipline + + +
+ + + diff --git a/src/client/main.tsx b/src/client/main.tsx new file mode 100644 index 00000000..23cb79ee --- /dev/null +++ b/src/client/main.tsx @@ -0,0 +1,18 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { RouterProvider } from 'react-router-dom'; +import { router } from './routes'; + +import '@mantine/charts/styles.css'; +import '@mantine/core/styles.css'; +import '@mantine/dates/styles.css'; +import '@mantine/dropzone/styles.css'; +import '@mantine/notifications/styles.css'; +import 'mantine-datatable/styles.css'; +import './styles/global.css'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/src/pages/404.tsx b/src/client/pages/404.tsx similarity index 64% rename from src/pages/404.tsx rename to src/client/pages/404.tsx index ae2ff7eb..7c5d8020 100644 --- a/src/pages/404.tsx +++ b/src/client/pages/404.tsx @@ -1,6 +1,6 @@ import { Button, Center, Stack, Text, Title } from '@mantine/core'; import { IconArrowLeft } from '@tabler/icons-react'; -import Link from 'next/link'; +import { Link } from 'react-router-dom'; export default function FourOhFour() { return ( @@ -11,12 +11,16 @@ export default function FourOhFour() { Page not found - ); } - -FourOhFour.title = '404'; diff --git a/src/pages/auth/login.tsx b/src/client/pages/auth/login.tsx old mode 100755 new mode 100644 similarity index 71% rename from src/pages/auth/login.tsx rename to src/client/pages/auth/login.tsx index 61e97476..a39d33b2 --- a/src/pages/auth/login.tsx +++ b/src/client/pages/auth/login.tsx @@ -1,11 +1,8 @@ import ExternalAuthButton from '@/components/pages/login/ExternalAuthButton'; import { Response } from '@/lib/api/response'; -import { SafeConfig } from '@/lib/config/safe'; -import { getZipline } from '@/lib/db/models/zipline'; import { fetchApi } from '@/lib/fetchApi'; -import { withSafeConfig } from '@/lib/middleware/next/withSafeConfig'; +import useLogin from '@/lib/hooks/useLogin'; import { authenticateWeb } from '@/lib/passkey'; -import { eitherTrue } from '@/lib/primitive'; import { Button, Center, @@ -34,28 +31,43 @@ import { IconUserPlus, IconX, } from '@tabler/icons-react'; -import { InferGetServerSidePropsType } from 'next'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; +import { Link, redirect, useLocation, useNavigate } from 'react-router-dom'; import useSWR from 'swr'; +import GenericError from '../../error/GenericError'; +import { useTitle } from '@/lib/hooks/useTitle'; -export default function Login({ config }: InferGetServerSidePropsType) { - const router = useRouter(); - const { data, isLoading, mutate } = useSWR('/api/user', { - refreshInterval: 120000, +export default function Login() { + useTitle('Login'); + + const location = useLocation(); + const query = new URLSearchParams(location.search); + const { user, mutate } = useLogin(); + + const navigate = useNavigate(); + + const { + data: config, + error: configError, + isLoading: configLoading, + } = useSWR('/api/server/public', { + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenHidden: false, + revalidateIfStale: false, }); const showLocalLogin = - router.query.local === 'true' || + query.get('local') === 'true' || !( - config.oauth.bypassLocalLogin && Object.values(config.oauthEnabled).filter((x) => x === true).length > 0 + config?.oauth?.bypassLocalLogin && + Object.values(config?.oauthEnabled ?? {}).filter((x) => x === true).length > 0 ); const willRedirect = - config.oauth.bypassLocalLogin && - Object.values(config.oauthEnabled).filter((x) => x === true).length === 1 && - router.query.local !== 'true'; + config?.oauth?.bypassLocalLogin && + Object.values(config?.oauthEnabled ?? {}).filter((x) => x === true).length === 1 && + query.get('local') !== 'true'; const [totpOpen, setTotpOpen] = useState(false); const [pinDisabled, setPinDisabled] = useState(false); @@ -65,12 +77,6 @@ export default function Login({ config }: InferGetServerSidePropsType { - if (data?.user) { - router.push('/dashboard'); - } - }, [data]); - const form = useForm({ initialValues: { username: '', @@ -123,7 +129,6 @@ export default function Login({ config }: InferGetServerSidePropsType('/api/auth/webauthn', 'POST', { auth: res.toJSON(), }); @@ -146,16 +151,22 @@ export default function Login({ config }: InferGetServerSidePropsType { - if (willRedirect) { + if (user) { + navigate('/dashboard'); + } + }, [user]); + + useEffect(() => { + if (willRedirect && config) { const provider = Object.keys(config.oauthEnabled).find( - (x) => config.oauthEnabled[x as keyof SafeConfig['oauthEnabled']] === true, + (x) => config.oauthEnabled[x as keyof typeof config.oauthEnabled] === true, ); if (provider) { - router.push(`/api/auth/oauth/${provider}`); + redirect(`/api/auth/oauth/${provider.toLowerCase()}`); } } - }, []); + }, [willRedirect, config]); useEffect(() => { if (passkeyErrored) { @@ -172,6 +183,23 @@ export default function Login({ config }: InferGetServerSidePropsType { + if (config?.firstSetup) navigate('/auth/setup'); + }, [config]); + + if (configLoading) return ; + + if (configError) + return ( + + ); + + if (!config) return ; + return ( <> {willRedirect && !showLocalLogin && } @@ -255,7 +283,10 @@ export default function Login({ config }: InferGetServerSidePropsType {config.website.title ?? 'Zipline'} @@ -263,47 +294,45 @@ export default function Login({ config }: InferGetServerSidePropsType {showLocalLogin && ( - <> -
onSubmit(v))}> - - + onSubmit(v))}> + + - + - - - - + +
+ )} - {eitherTrue(config.features.oauthRegistration, config.features.userRegistration) && ( + {(config.features.oauthRegistration || config.features.userRegistration) && ( )} @@ -324,7 +353,7 @@ export default function Login({ config }: InferGetServerSidePropsType )} + {config.oauthEnabled.discord && ( ); } - -export const getServerSideProps = withSafeConfig(async () => { - const { firstSetup } = await getZipline(); - - if (firstSetup) - return { - redirect: { - destination: '/setup', - permanent: false, - }, - }; - - return {}; -}); - -Login.title = 'Login'; diff --git a/src/pages/auth/logout.tsx b/src/client/pages/auth/logout.tsx old mode 100755 new mode 100644 similarity index 64% rename from src/pages/auth/logout.tsx rename to src/client/pages/auth/logout.tsx index add8f24b..950715a4 --- a/src/pages/auth/logout.tsx +++ b/src/client/pages/auth/logout.tsx @@ -1,35 +1,35 @@ +import { useTitle } from '@/lib/hooks/useTitle'; import { useUserStore } from '@/lib/store/user'; import { LoadingOverlay } from '@mantine/core'; -import { useRouter } from 'next/router'; import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import { mutate } from 'swr'; export default function Logout() { - const router = useRouter(); + useTitle('Log out'); + const setUser = useUserStore((state) => state.setUser); + const navigate = useNavigate(); useEffect(() => { (async () => { const userRes = await fetch('/api/user'); + if (userRes.ok) { const res = await fetch('/api/auth/logout'); if (res.ok) { setUser(null); mutate('/api/user', null); - await router.push('/auth/login'); + navigate('/auth/login'); + } else { + navigate('/dashboard'); } } else { - await router.push('/dashboard'); + navigate('/dashboard'); } })(); }, []); - return ( - <> - - - ); + return ; } - -Logout.title = 'Logout'; diff --git a/src/client/pages/auth/register.tsx b/src/client/pages/auth/register.tsx new file mode 100644 index 00000000..3b392527 --- /dev/null +++ b/src/client/pages/auth/register.tsx @@ -0,0 +1,260 @@ +import { Response } from '@/lib/api/response'; +import { fetchApi } from '@/lib/fetchApi'; +import { + Button, + Center, + Checkbox, + Divider, + Image, + LoadingOverlay, + Paper, + PasswordInput, + Stack, + Text, + TextInput, + Title, +} from '@mantine/core'; +import { useForm } from '@mantine/form'; +import { notifications } from '@mantine/notifications'; +import { IconLogin, IconPlus, IconUserPlus, IconX } from '@tabler/icons-react'; +import { useEffect, useState } from 'react'; +import { Link, redirect, useLocation, useNavigate } from 'react-router-dom'; +import useSWR, { mutate } from 'swr'; +import GenericError from '../../error/GenericError'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Register'); + + const location = useLocation(); + const navigate = useNavigate(); + + const [loading, setLoading] = useState(true); + const [invite, setInvite] = useState(null); + + const { + data: config, + error: configError, + isLoading: configLoading, + } = useSWR('/api/server/public', { + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenHidden: false, + revalidateIfStale: false, + }); + + const code = new URLSearchParams(location.search).get('code') ?? undefined; + + const form = useForm({ + initialValues: { + username: '', + password: '', + tos: false, + }, + validate: { + username: (value) => (value.length < 1 ? 'Username is required' : null), + password: (value) => (value.length < 1 ? 'Password is required' : null), + }, + }); + + useEffect(() => { + (async () => { + const res = await fetch('/api/user'); + if (res.ok) { + redirect('/dashboard'); + } else { + setLoading(false); + } + })(); + }, []); + + useEffect(() => { + (async () => { + if (!code) return; + + const res = await fetch(`/api/auth/invite/web?code=${code}`); + if (res.ok) { + const json = await res.json(); + setInvite(json.invite); + } else { + redirect('/auth/login'); + } + })(); + }, [code]); + + useEffect(() => { + if (!config?.features.userRegistration) { + navigate('/auth/login'); + } + }, [code, config]); + + const onSubmit = async (values: typeof form.values) => { + const { username, password, tos } = values; + + if (tos === false && config!.website.tos) { + form.setFieldError('tos', 'You must agree to the Terms of Service to continue'); + return; + } + + const { data, error } = await fetchApi('/api/auth/register', 'POST', { + username, + password, + code, + }); + + if (error) { + if (error.error === 'Username is taken') { + form.setFieldError('username', 'Username is taken'); + } else { + notifications.show({ + title: 'Failed to register', + message: error.error, + color: 'red', + icon: , + }); + } + } else { + notifications.show({ + title: 'Complete!', + message: `Your "${data?.user?.username}" account has been created.`, + color: 'green', + icon: , + }); + + mutate('/api/user'); + redirect('/dashboard'); + } + }; + + if (loading || configLoading) return ; + + if (!config || configError) { + return ( + + ); + } + + return ( +
+ {config.website.loginBackground && ( + Background + )} + + +
+ + <b>{config.website.title ?? 'Zipline'}</b> + +
+ + {invite && ( + + You’ve been invited to join {config?.website?.title ?? 'Zipline'} by{' '} + {invite.inviter?.username} + + )} + +
+ + + + + + {config.website.tos && ( + + I agree to the{' '} + + Terms of Service + + + } + required + {...form.getInputProps('tos', { type: 'checkbox' })} + /> + )} + + + +
+ + + + + +
+
+ ); +} + +Component.displayName = 'Register'; diff --git a/src/pages/setup.tsx b/src/client/pages/auth/setup.tsx old mode 100755 new mode 100644 similarity index 88% rename from src/pages/setup.tsx rename to src/client/pages/auth/setup.tsx index b38de2c5..1d93edfc --- a/src/pages/setup.tsx +++ b/src/client/pages/auth/setup.tsx @@ -1,6 +1,6 @@ -import { Response } from '@/lib/api/response'; -import { getZipline } from '@/lib/db/models/zipline'; +import { type Response } from '@/lib/api/response'; import { fetchApi } from '@/lib/fetchApi'; +import { useTitle } from '@/lib/hooks/useTitle'; import { Anchor, Button, @@ -18,11 +18,8 @@ import { import { useForm } from '@mantine/form'; import { notifications } from '@mantine/notifications'; import { IconArrowBackUp, IconArrowForwardUp, IconCheck, IconX } from '@tabler/icons-react'; -import { GetServerSideProps } from 'next'; -import Head from 'next/head'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; import { useState } from 'react'; +import { redirect, useNavigate } from 'react-router-dom'; import { mutate } from 'swr'; function LinkToDoc({ href, title, children }: { href: string; title: string; children: React.ReactNode }) { @@ -36,8 +33,22 @@ function LinkToDoc({ href, title, children }: { href: string; title: string; chi ); } -export default function Setup() { - const router = useRouter(); +export async function loader() { + const res = await fetch('/api/server/public'); + if (!res.ok) { + throw new Response('Failed to fetch server settings', { status: res.status }); + } + + const data = await res.json(); + if (!data.firstSetup) return redirect('/auth/login'); + + return {}; +} + +export function Component() { + useTitle('Setup'); + + const navigate = useNavigate(); const [active, setActive] = useState(0); const nextStep = () => setActive((current) => (current < 3 ? current + 1 : current)); @@ -99,18 +110,13 @@ export default function Setup() { setActive(2); } else { mutate('/api/user', data as Response['/api/user']); - router.push('/dashboard'); + navigate('/dashboard'); } } }; return ( <> - - Zipline Setup - - - @@ -145,7 +151,11 @@ export default function Setup() { To see all of the available environment variables, please refer to the documentation{' '} - + here. @@ -236,20 +246,4 @@ export default function Setup() { ); } -export const getServerSideProps: GetServerSideProps = async () => { - const { firstSetup } = await getZipline(); - - if (!firstSetup) - return { - redirect: { - destination: '/dashboard', - permanent: false, - }, - }; - - return { - props: {}, - }; -}; - -Setup.title = 'Setup'; +Component.displayName = 'Setup'; diff --git a/src/client/pages/auth/tos.tsx b/src/client/pages/auth/tos.tsx new file mode 100644 index 00000000..66b39b6c --- /dev/null +++ b/src/client/pages/auth/tos.tsx @@ -0,0 +1,41 @@ +import Markdown from '@/components/render/Markdown'; +import { Response } from '@/lib/api/response'; +import { Container, LoadingOverlay } from '@mantine/core'; +import useSWR from 'swr'; +import GenericError from '../../error/GenericError'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Terms of Service'); + + const { + data: config, + error, + isLoading, + } = useSWR('/api/server/public', { + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenHidden: false, + revalidateIfStale: false, + }); + + if (isLoading) return ; + + if (error) { + return ( + + ); + } + + return ( + + + + ); +} + +Component.displayName = 'Tos'; diff --git a/src/client/pages/dashboard/admin/invites.tsx b/src/client/pages/dashboard/admin/invites.tsx new file mode 100644 index 00000000..b775910c --- /dev/null +++ b/src/client/pages/dashboard/admin/invites.tsx @@ -0,0 +1,10 @@ +import DashboardInvites from '@/components/pages/invites'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Invites'); + + return ; +} + +Component.displayName = 'Dashboard/Admin/Invites'; diff --git a/src/client/pages/dashboard/admin/settings.tsx b/src/client/pages/dashboard/admin/settings.tsx new file mode 100644 index 00000000..8541e51f --- /dev/null +++ b/src/client/pages/dashboard/admin/settings.tsx @@ -0,0 +1,10 @@ +import DashboardServerSettings from '@/components/pages/serverSettings'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Server Settings'); + + return ; +} + +Component.displayName = 'Dashboard/Admin/Settings'; diff --git a/src/client/pages/dashboard/admin/users/[id]/files.tsx b/src/client/pages/dashboard/admin/users/[id]/files.tsx new file mode 100644 index 00000000..411d3660 --- /dev/null +++ b/src/client/pages/dashboard/admin/users/[id]/files.tsx @@ -0,0 +1,23 @@ +import ViewUserFiles from '@/components/pages/users/ViewUserFiles'; +import { useTitle } from '@/lib/hooks/useTitle'; +import { Params, redirect, useLoaderData } from 'react-router-dom'; + +export async function loader({ params }: { params: Params }) { + const res = await fetch('/api/users/' + params.id); + if (!res.ok) { + console.log("can't get user", res.status); + return redirect('/dashboard/admin/users'); + } + + const user = await res.json(); + return { user }; +} + +export function Component() { + const { user } = useLoaderData(); + useTitle(`${user ? user.username : 'User'}'s files`); + + return ; +} + +Component.displayName = 'DashboardAdminViewUserFiles'; diff --git a/src/client/pages/dashboard/admin/users/index.tsx b/src/client/pages/dashboard/admin/users/index.tsx new file mode 100644 index 00000000..b0ce83bc --- /dev/null +++ b/src/client/pages/dashboard/admin/users/index.tsx @@ -0,0 +1,10 @@ +import DashboardUsers from '@/components/pages/users'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Users'); + + return ; +} + +Component.displayName = 'Dashboard/Admin/Users'; diff --git a/src/client/pages/dashboard/files.tsx b/src/client/pages/dashboard/files.tsx new file mode 100644 index 00000000..bb3c7a71 --- /dev/null +++ b/src/client/pages/dashboard/files.tsx @@ -0,0 +1,10 @@ +import DashboardFiles from '@/components/pages/files'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Files'); + + return ; +} + +Component.displayName = 'Dashboard/Files'; diff --git a/src/client/pages/dashboard/folders.tsx b/src/client/pages/dashboard/folders.tsx new file mode 100644 index 00000000..011f6827 --- /dev/null +++ b/src/client/pages/dashboard/folders.tsx @@ -0,0 +1,10 @@ +import DashboardFolders from '@/components/pages/folders'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Folders'); + + return ; +} + +Component.displayName = 'Dashboard/Folders'; diff --git a/src/client/pages/dashboard/index.tsx b/src/client/pages/dashboard/index.tsx new file mode 100644 index 00000000..32731d70 --- /dev/null +++ b/src/client/pages/dashboard/index.tsx @@ -0,0 +1,10 @@ +import DashboardHome from '@/components/pages/dashboard'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle(); + + return ; +} + +Component.displayName = 'Dashboard/'; diff --git a/src/client/pages/dashboard/metrics.tsx b/src/client/pages/dashboard/metrics.tsx new file mode 100644 index 00000000..fc284908 --- /dev/null +++ b/src/client/pages/dashboard/metrics.tsx @@ -0,0 +1,10 @@ +import DashboardMetrics from '@/components/pages/metrics'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Metrics'); + + return ; +} + +Component.displayName = 'Dashboard/Metrics'; diff --git a/src/client/pages/dashboard/settings.tsx b/src/client/pages/dashboard/settings.tsx new file mode 100644 index 00000000..ee185187 --- /dev/null +++ b/src/client/pages/dashboard/settings.tsx @@ -0,0 +1,10 @@ +import DashboardSettings from '@/components/pages/settings'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Settings'); + + return ; +} + +Component.displayName = 'Dashboard/Settings'; diff --git a/src/client/pages/dashboard/upload/file.tsx b/src/client/pages/dashboard/upload/file.tsx new file mode 100644 index 00000000..1d19df51 --- /dev/null +++ b/src/client/pages/dashboard/upload/file.tsx @@ -0,0 +1,10 @@ +import UploadFile from '@/components/pages/upload/File'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Upload File'); + + return ; +} + +Component.displayName = 'Dashboard/Upload/File'; diff --git a/src/client/pages/dashboard/upload/text.tsx b/src/client/pages/dashboard/upload/text.tsx new file mode 100644 index 00000000..154c2c18 --- /dev/null +++ b/src/client/pages/dashboard/upload/text.tsx @@ -0,0 +1,10 @@ +import UploadText from '@/components/pages/upload/Text'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('Upload Text'); + + return ; +} + +Component.displayName = 'Dashboard/Upload/Text'; diff --git a/src/client/pages/dashboard/urls.tsx b/src/client/pages/dashboard/urls.tsx new file mode 100644 index 00000000..6ba7157c --- /dev/null +++ b/src/client/pages/dashboard/urls.tsx @@ -0,0 +1,10 @@ +import DashboardURLs from '@/components/pages/urls'; +import { useTitle } from '@/lib/hooks/useTitle'; + +export function Component() { + useTitle('URLs'); + + return ; +} + +Component.displayName = 'Dashboard/URLs'; diff --git a/src/client/pages/folder/[id]/index.tsx b/src/client/pages/folder/[id]/index.tsx new file mode 100644 index 00000000..bb8bea3b --- /dev/null +++ b/src/client/pages/folder/[id]/index.tsx @@ -0,0 +1,57 @@ +import { type Response } from '@/lib/api/response'; +import { ActionIcon, Container, Group, SimpleGrid, Skeleton, Title } from '@mantine/core'; +import { IconUpload } from '@tabler/icons-react'; +import { lazy, Suspense } from 'react'; +import { Link, Params, useLoaderData } from 'react-router-dom'; + +const DashboardFile = lazy(() => import('@/components/file/DashboardFile')); + +export async function loader({ params }: { params: Params }) { + const res = await fetch(`/api/server/folder/${params.id}`); + if (!res.ok) { + throw new Response('Folder not found', { status: 404 }); + } + return { + folder: (await res.json()) as Response['/api/server/folder/[id]'], + }; +} + +export function Component() { + const { folder } = useLoaderData(); + + return ( + <> + + + {folder.name} + + {folder.allowUploads && ( + + + + + + )} + + + + {folder.files?.map((file: any) => ( + } key={file.id}> + + + ))} + + + + ); +} + +Component.displayName = 'ViewFolderId'; diff --git a/src/client/pages/folder/[id]/upload.tsx b/src/client/pages/folder/[id]/upload.tsx new file mode 100644 index 00000000..ed3fecf7 --- /dev/null +++ b/src/client/pages/folder/[id]/upload.tsx @@ -0,0 +1,55 @@ +import ConfigProvider from '@/components/ConfigProvider'; +import UploadFile from '@/components/pages/upload/File'; +import { type Response } from '@/lib/api/response'; +import { SafeConfig } from '@/lib/config/safe'; +import { Anchor, Center, Container, Text } from '@mantine/core'; +import { Link, Params, useLoaderData } from 'react-router-dom'; +import useSWR from 'swr'; + +export async function loader({ params }: { params: Params }) { + const res = await fetch(`/api/server/folder/${params.id}?upload=true`); + if (!res.ok) { + throw new Response('Folder not found', { status: 404 }); + } + return { + folder: (await res.json()) as Response['/api/server/folder/[id]'], + }; +} + +export function Component() { + const { folder } = useLoaderData(); + + const { data: config } = useSWR('/api/server/public', { + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenHidden: false, + revalidateIfStale: false, + }); + + return ( + <> + + + +
+ + {folder.public ? ( + <> + This folder is{' '} + + public + + . Anyone with the link can view its contents and upload files. + + ) : ( + "Only the owner can view this folder's contents. However, anyone can upload files, and they can still access their uploaded files if they have the link to the specific file." + )} + +
+
+
+ + ); +} + +Component.displayName = 'ViewFolderIdUpload'; diff --git a/src/client/pages/view/[id].tsx b/src/client/pages/view/[id].tsx new file mode 100644 index 00000000..e5bafd4d --- /dev/null +++ b/src/client/pages/view/[id].tsx @@ -0,0 +1,245 @@ +import DashboardFileType from '@/components/file/DashboardFileType'; +import TagPill from '@/components/pages/files/tags/TagPill'; +import { File } from '@/lib/db/models/file'; +import { User } from '@/lib/db/models/user'; +import { parseString } from '@/lib/parser'; +import { type parserMetrics } from '@/lib/parser/metrics'; +import { formatRootUrl } from '@/lib/url'; +import { + ActionIcon, + Anchor, + Box, + Button, + Center, + Collapse, + Group, + Modal, + Paper, + PasswordInput, + Text, + Tooltip, + Typography, +} from '@mantine/core'; +import { IconDownload, IconExternalLink, IconInfoCircleFilled } from '@tabler/icons-react'; +import * as sanitize from 'isomorphic-dompurify'; +import { useState } from 'react'; +import { Link } from 'react-router-dom'; +import { useSsrData } from '../../../components/ZiplineSSRProvider'; +import { getFile } from '../../ssr-view/server'; + +type SsrData = { + file: Partial>>>; + password?: boolean; + code: boolean; + user?: Partial; + host: string; + pw?: string | null; + metrics?: Awaited>; + filesRoute?: string; +}; + +export default function ViewFileId() { + const data = useSsrData(); + if (!data) return null; + + const { file, password, code, user, host, metrics, filesRoute, pw } = data; + + const [passwordValue, setPassword] = useState(''); + const [passwordError, setPasswordError] = useState(''); + const [detailsOpen, setDetailsOpen] = useState(false); + + return password && !pw ? ( + {}} opened={true} withCloseButton={false} centered title='Password required'> +
{ + e.preventDefault(); + + const res = await fetch(`/api/user/files/${file.id}/password`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ password: passwordValue.trim() }), + }); + + if (res.ok) { + window.location.reload(); + } else { + setPasswordError('Invalid password'); + } + }} + > + setPassword(event.currentTarget.value)} + error={passwordError} + /> + + + +
+ ) : code ? ( + <> + + + {file.name} + + + setDetailsOpen((o) => !o)}> + + + + + + + + + + + + + {user?.view!.content && ( + + + + )} + + + + {file.name!.endsWith('.md') || file.name!.endsWith('.tex') ? ( + + + + ) : ( + + + + )} + + ) : ( + <> +
+ + + + + {file.name}{' '} + + {user?.view!.showTags && ( + + {file.tags?.map((tag) => ( + + ))} + + )} + {user?.view!.showFolder && + file.Folder && + (file.Folder.public ? ( + + + {file.Folder.name} + + + ) : ( + + {file.Folder.name} + + ))} + {user?.view!.showMimetype && ( + + {file.type} + + )} + + + + + + + + + + + + + + + + + + + {user?.view!.content && ( + + + + )} + +
+ + ); +} diff --git a/src/client/pages/view/url/[id].tsx b/src/client/pages/view/url/[id].tsx new file mode 100644 index 00000000..5ce84244 --- /dev/null +++ b/src/client/pages/view/url/[id].tsx @@ -0,0 +1,65 @@ +import { useSsrData } from '@/components/ZiplineSSRProvider'; +import { Anchor, Button, Modal, PasswordInput } from '@mantine/core'; +import { useEffect, useState } from 'react'; + +export default function ViewUrlId() { + const data = useSsrData<{ + url: { id: string; destination?: string }; + password?: boolean; + }>(); + if (!data) return null; + + const { url, password } = data; + + const [passwordValue, setPassword] = useState(''); + const [passwordError, setPasswordError] = useState(''); + + useEffect(() => { + if (!password && url.destination) window.location.href = url.destination; + }, []); + + return password ? ( + {}} opened={true} withCloseButton={false} centered title='Password required'> +
{ + e.preventDefault(); + + const res = await fetch(`/api/user/urls/${url.id}/password`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ password: passwordValue.trim() }), + }); + + if (res.ok) { + window.location.reload(); + } else { + setPasswordError('Invalid password'); + } + }} + > + setPassword(event.currentTarget.value)} + error={passwordError} + /> + + + +
+ ) : ( +

+ Redirecting to {url.destination!} +

+ ); +} diff --git a/src/client/routes.tsx b/src/client/routes.tsx new file mode 100644 index 00000000..6abc2eeb --- /dev/null +++ b/src/client/routes.tsx @@ -0,0 +1,114 @@ +import Layout from '@/components/Layout'; +import { Response as ApiResponse } from '@/lib/api/response'; +import { isAdministrator } from '@/lib/role'; +import { createBrowserRouter, redirect } from 'react-router-dom'; +import DashboardErrorBoundary from './error/DashboardErrorBoundary'; +import RootErrorBoundary from './error/RootErrorBoundary'; +import FourOhFour from './pages/404'; +import Login from './pages/auth/login'; +import Logout from './pages/auth/logout'; +import Root from './Root'; + +export async function dashboardLoader() { + const res = await fetch('/api/server/settings/web'); + if (!res.ok) { + return redirect('/auth/login'); + } + + const data = await res.json(); + console.log('Loaded settings:', data); + + return data as ApiResponse['/api/server/settings/web']; +} + +export const router = createBrowserRouter([ + { + Component: Root, + path: '/', + children: [ + { + ErrorBoundary: RootErrorBoundary, + children: [ + { path: '*', Component: FourOhFour }, + { + path: '/auth', + children: [ + { path: 'login', Component: Login }, + { path: 'logout', Component: Logout }, + { path: 'register', lazy: () => import('./pages/auth/register') }, + { + path: 'setup', + lazy: () => import('./pages/auth/setup'), + }, + { path: 'tos', lazy: () => import('./pages/auth/tos') }, + ], + }, + { + path: '/dashboard', + Component: Layout, + loader: dashboardLoader, + children: [ + { + ErrorBoundary: DashboardErrorBoundary, + children: [ + { index: true, lazy: () => import('./pages/dashboard/index') }, + { path: 'metrics', lazy: () => import('./pages/dashboard/metrics') }, + { path: 'settings', lazy: () => import('./pages/dashboard/settings') }, + { path: 'files', lazy: () => import('./pages/dashboard/files') }, + { path: 'folders', lazy: () => import('./pages/dashboard/folders') }, + { path: 'urls', lazy: () => import('./pages/dashboard/urls') }, + { + path: 'upload', + children: [ + { path: 'file', lazy: () => import('./pages/dashboard/upload/file') }, + { path: 'text', lazy: () => import('./pages/dashboard/upload/text') }, + ], + }, + { + path: 'admin', + loader: async () => { + const res = await fetch('/api/user'); + if (!res.ok) { + return redirect('/auth/login'); + } + + const { user } = await res.json(); + if (!isAdministrator(user.role)) return redirect('/dashboard'); + }, + children: [ + { path: 'invites', lazy: () => import('./pages/dashboard/admin/invites') }, + { path: 'settings', lazy: () => import('./pages/dashboard/admin/settings') }, + { + path: 'users', + children: [ + { index: true, lazy: () => import('./pages/dashboard/admin/users') }, + { + path: ':id/files', + lazy: () => import('./pages/dashboard/admin/users/[id]/files'), + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + path: 'folder/:id', + children: [ + { + index: true, + lazy: () => import('./pages/folder/[id]'), + }, + { + path: 'upload', + lazy: () => import('./pages/folder/[id]/upload'), + }, + ], + }, + ], + }, + ], + }, +]); diff --git a/src/client/ssr-view-url/client.tsx b/src/client/ssr-view-url/client.tsx new file mode 100644 index 00000000..3bbea03e --- /dev/null +++ b/src/client/ssr-view-url/client.tsx @@ -0,0 +1,25 @@ +import '@mantine/charts/styles.css'; +import '@mantine/core/styles.css'; +import '@mantine/dates/styles.css'; +import '@mantine/dropzone/styles.css'; +import '@mantine/notifications/styles.css'; +import 'mantine-datatable/styles.css'; + +import ZiplineSSRProvider from '@/components/ZiplineSSRProvider'; +import { ZIPLINE_SSR_PROP } from '@/lib/ssr/constants'; +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { createBrowserRouter, RouterProvider } from 'react-router-dom'; +import { createRoutes } from './routes'; + +const router = createBrowserRouter(createRoutes()); + +const initialData = (window as any)[ZIPLINE_SSR_PROP]; + +createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/src/client/ssr-view-url/index.html b/src/client/ssr-view-url/index.html new file mode 100644 index 00000000..841a6900 --- /dev/null +++ b/src/client/ssr-view-url/index.html @@ -0,0 +1,12 @@ + + + + + + + + +
+ + + diff --git a/src/client/ssr-view-url/routes.tsx b/src/client/ssr-view-url/routes.tsx new file mode 100644 index 00000000..031fe5ed --- /dev/null +++ b/src/client/ssr-view-url/routes.tsx @@ -0,0 +1,18 @@ +import { ZiplineTheme } from '@/lib/theme'; +import Root from '../Root'; +import { Config } from '@/lib/config/validate'; +import ViewUrlId from '../pages/view/url/[id]'; + +export const createRoutes = (themes?: ZiplineTheme[], defaultTheme?: Config['website']['theme']) => [ + { + path: '/view/url', + Component: + typeof window === 'undefined' ? undefined : () => , + children: [ + { + path: ':id', + Component: () => , + }, + ], + }, +]; diff --git a/src/client/ssr-view-url/server.tsx b/src/client/ssr-view-url/server.tsx new file mode 100644 index 00000000..ccd11a71 --- /dev/null +++ b/src/client/ssr-view-url/server.tsx @@ -0,0 +1,95 @@ +import * as cookie from 'cookie'; +import { FastifyRequest } from 'fastify'; + +import { config as zConfig } from '@/lib/config'; +import { Config } from '@/lib/config/validate'; +import { verifyPassword } from '@/lib/crypto'; +import { prisma } from '@/lib/db'; +import { renderHtml } from '@/lib/ssr/renderHtml'; +import { ZiplineTheme } from '@/lib/theme'; +import { createRoutes } from './routes'; // This should include the `/url/:id` route + +export async function render( + { + themes, + defaultTheme, + req, + }: { + themes: ZiplineTheme[]; + defaultTheme: Config['website']['theme']; + req: FastifyRequest; + }, + url: string, +) { + const routes = createRoutes(themes, defaultTheme); + + const id = url.split('/').pop(); + if (!id) return { html: 'Not Found', meta: '', status: 404 }; + + const { config: libConfig, reloadSettings } = await import('@/lib/config'); + if (!libConfig) await reloadSettings(); + + const urlEntry = await prisma.url.findFirst({ + where: { + OR: [{ vanity: id }, { code: id }, { id }], + }, + select: { + id: true, + password: true, + destination: true, + maxViews: true, + views: true, + enabled: true, + }, + }); + + if (!urlEntry || !urlEntry.enabled) return { html: 'Not Found', meta: '', status: 404 }; + + if (urlEntry.maxViews && urlEntry.views >= urlEntry.maxViews) { + if (zConfig.features.deleteOnMaxViews) { + await prisma.url.delete({ where: { id: urlEntry.id } }); + } + return { html: 'Gone', meta: '', status: 410 }; + } + + const cookies = cookie.parse(req.headers.cookie || ''); + const pw = cookies[`url_pw_${urlEntry.id}`]; + const hasPassword = !!urlEntry.password; + + const data = { + url: { ...urlEntry }, + password: hasPassword, + }; + + if (hasPassword) { + delete (data.url as any).password; + if (pw) { + const verified = await verifyPassword(pw, urlEntry.password!); + if (!verified) { + delete (data.url as any).destination; + return renderHtml(routes, { url, data, status: 403 }); + } + } else { + delete (data.url as any).destination; + return renderHtml(routes, { url, data, status: 403 }); + } + } + + delete (data.url as any).password; + + await prisma.url.update({ + where: { id: urlEntry.id }, + data: { views: { increment: 1 } }, + }); + + if (data.url.destination) { + return { + html: '', + meta: '', + redirect: data.url.destination, + status: 301, + }; + } + + return renderHtml(routes, { url, data, status: 200 }); +} diff --git a/src/client/ssr-view/client.tsx b/src/client/ssr-view/client.tsx new file mode 100644 index 00000000..3bbea03e --- /dev/null +++ b/src/client/ssr-view/client.tsx @@ -0,0 +1,25 @@ +import '@mantine/charts/styles.css'; +import '@mantine/core/styles.css'; +import '@mantine/dates/styles.css'; +import '@mantine/dropzone/styles.css'; +import '@mantine/notifications/styles.css'; +import 'mantine-datatable/styles.css'; + +import ZiplineSSRProvider from '@/components/ZiplineSSRProvider'; +import { ZIPLINE_SSR_PROP } from '@/lib/ssr/constants'; +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { createBrowserRouter, RouterProvider } from 'react-router-dom'; +import { createRoutes } from './routes'; + +const router = createBrowserRouter(createRoutes()); + +const initialData = (window as any)[ZIPLINE_SSR_PROP]; + +createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/src/client/ssr-view/index.html b/src/client/ssr-view/index.html new file mode 100644 index 00000000..95f795ec --- /dev/null +++ b/src/client/ssr-view/index.html @@ -0,0 +1,12 @@ + + + + + + + + +
+ + + diff --git a/src/client/ssr-view/routes.tsx b/src/client/ssr-view/routes.tsx new file mode 100644 index 00000000..dda2a318 --- /dev/null +++ b/src/client/ssr-view/routes.tsx @@ -0,0 +1,18 @@ +import { ZiplineTheme } from '@/lib/theme'; +import Root from '../Root'; +import ViewFileId from '../pages/view/[id]'; +import { Config } from '@/lib/config/validate'; + +export const createRoutes = (themes?: ZiplineTheme[], defaultTheme?: Config['website']['theme']) => [ + { + path: '/view', + Component: + typeof window === 'undefined' ? undefined : () => , + children: [ + { + path: ':id', + Component: () => , + }, + ], + }, +]; diff --git a/src/client/ssr-view/server.tsx b/src/client/ssr-view/server.tsx new file mode 100644 index 00000000..81bb48c5 --- /dev/null +++ b/src/client/ssr-view/server.tsx @@ -0,0 +1,287 @@ +import '@mantine/charts/styles.css'; +import '@mantine/core/styles.css'; +import '@mantine/dates/styles.css'; +import '@mantine/dropzone/styles.css'; +import '@mantine/notifications/styles.css'; +import 'mantine-datatable/styles.css'; + +import { isCode } from '@/lib/code'; +import { config as zConfig } from '@/lib/config'; +import type { Config } from '@/lib/config/validate'; +import { verifyPassword } from '@/lib/crypto'; +import { prisma } from '@/lib/db'; +import { File, fileSelect } from '@/lib/db/models/file'; +import { User, userSelect } from '@/lib/db/models/user'; +import { parseString } from '@/lib/parser'; +import { parserMetrics } from '@/lib/parser/metrics'; +import { createZiplineSsr } from '@/lib/ssr/createZiplineSsr'; +import type { ZiplineTheme } from '@/lib/theme'; +import { readThemes } from '@/lib/theme/file'; +import * as cookie from 'cookie'; +import { FastifyRequest } from 'fastify'; +import { renderToString } from 'react-dom/server'; +import { createStaticHandler, createStaticRouter, StaticRouterProvider } from 'react-router-dom'; +import { createRoutes } from './routes'; + +export const getFile = async (id: string) => + prisma.file.findFirst({ + where: { name: id as string }, + select: { + ...fileSelect, + password: true, + userId: true, + thumbnail: { select: { path: true } }, + tags: { select: { id: true, name: true, color: true } }, + Folder: { select: { id: true, public: true, name: true } }, + }, + }); + +export async function render( + { + defaultTheme, + req, + }: { + themes: ZiplineTheme[]; + defaultTheme: Config['website']['theme']; + req: FastifyRequest; + }, + url: string, +) { + const id = url.split('/').pop(); + if (!id) return { html: 'Not Found', meta: '', status: 404 }; + + const { config: libConfig, reloadSettings } = await import('@/lib/config'); + if (!libConfig) await reloadSettings(); + + const file = await getFile(id); + if (!file || !file.userId) return { html: 'Not Found', meta: '', status: 404 }; + + if (file.maxViews && file.views >= file.maxViews) return { html: 'Gone', meta: '', status: 410 }; + if (file.deletesAt && file.deletesAt <= new Date()) return { html: 'Expired', meta: '', status: 410 }; + + const user = await prisma.user.findFirst({ + where: { id: file.userId }, + select: { + ...userSelect, + oauthProviders: false, + passkeys: false, + sessions: false, + totpSecret: false, + quota: false, + }, + }); + if (!user) return { html: 'Not Found', meta: '', status: 404 }; + + let host = req.headers.host || 'localhost'; + const proto = req.headers['x-forwarded-proto']; + try { + if ( + JSON.parse(req.headers['cf-visitor'] as string)?.scheme === 'https' || + proto === 'https' || + zConfig.core.returnHttpsUrls + ) { + host = `https://${host}`; + } else { + host = `http://${host}`; + } + } catch { + host = proto === 'https' || zConfig.core.returnHttpsUrls ? `https://${host}` : `http://${host}`; + } + + // Date normalization + (file as any).createdAt = file.createdAt.toISOString(); + (file as any).updatedAt = file.updatedAt.toISOString(); + (file as any).deletesAt = file.deletesAt?.toISOString() || null; + (user as any).createdAt = user.createdAt.toISOString(); + (user as any).updatedAt = user.updatedAt.toISOString(); + + const code = await isCode(file.name); + const themes = await readThemes(); + const metrics = await parserMetrics(user.id); + const config = { website: { theme: zConfig.website.theme } }; + + const cookies = cookie.parse(req.headers.cookie || ''); + const pw = cookies[`file_pw_${file.id}`]; + const hasPassword = !!file.password; + + if (hasPassword) { + if (pw) { + const verified = await verifyPassword(pw, file.password!); + if (!verified) return { html: 'Forbidden', meta: '', status: 403 }; + delete (file as any).password; + } else { + delete (file as any).password; + const data = { + file: { id: file.id, name: file.name, type: file.type }, + password: true, + code, + user, + host, + themes, + metrics, + config, + }; + + const routes = createRoutes(themes, defaultTheme); + const { query } = createStaticHandler(routes); + const context = await query( + new Request('http://client' + url, { + method: 'GET', + headers: new Headers({ accept: 'text/html' }), + }), + ); + + if (context instanceof Response) { + return context; + } + const router = createStaticRouter(routes, context); + const html = renderToString(); + + return { + html, + meta: `Password Protected\n${createZiplineSsr(data)}`, + }; + } + } + + await prisma.file.update({ + where: { id: file.id }, + data: { views: { increment: 1 } }, + }); + + const data = { + file, + password: hasPassword, + pw: pw || null, + code, + user, + host, + themes, + metrics, + filesRoute: zConfig.files.route, + config, + }; + + const routes = createRoutes(themes, defaultTheme); + const { query } = createStaticHandler(routes); + const context = await query( + new Request('http://client' + url, { + method: 'GET', + headers: new Headers({ accept: 'text/html' }), + }), + ); + + if (context instanceof Response) { + return context; + } + + const router = createStaticRouter(routes, context); + const html = renderToString(); + + const meta = ` + ${ + user?.view?.embedTitle && user.view.embed + ? `` + : '' + } + ${ + user?.view?.embedDescription && user.view.embed + ? `` + : '' + } + ${ + user?.view?.embedSiteName && user.view.embed + ? `` + : '' + } + ${ + user?.view?.embedColor && user.view.embed + ? `` + : '' + } + + ${ + file.type?.startsWith('image') + ? ` + + + + + + + ` + : '' + } + + ${ + file.type?.startsWith('video') + ? ` + ${file.thumbnail ? `` : ''} + + + + + ` + : '' + } + + ${ + file.type?.startsWith('audio') + ? ` + + + + + + + + + + + + + + ` + : '' + } + + ${ + !file.type?.startsWith('video') && !file.type?.startsWith('image') + ? ` + + ` + : '' + } + + ${file.name} +`; + + return { + html, + meta: `${meta}\n${createZiplineSsr(data)}`, + }; +} diff --git a/src/styles/global.css b/src/client/styles/global.css similarity index 100% rename from src/styles/global.css rename to src/client/styles/global.css diff --git a/src/components/ConfigProvider.tsx b/src/components/ConfigProvider.tsx index 3ddafa98..2aa5d924 100755 --- a/src/components/ConfigProvider.tsx +++ b/src/components/ConfigProvider.tsx @@ -1,21 +1,30 @@ -import { SafeConfig } from '@/lib/config/safe'; +import { ApiServerSettingsWebResponse } from '@/server/routes/api/server/settings'; import { createContext, useContext } from 'react'; -const ConfigContext = createContext(null); +type ConfigContextType = ApiServerSettingsWebResponse; + +const ConfigContext = createContext(null); export function useConfig() { const ctx = useContext(ConfigContext); if (!ctx) throw new Error('useConfig must be used within a ConfigProvider'); - return ctx; + return ctx.config; +} + +export function useCodeMap() { + const ctx = useContext(ConfigContext); + if (!ctx) throw new Error('useCodeMap must be used within a ConfigProvider'); + + return ctx.codeMap; } export default function ConfigProvider({ - config, + data, children, }: { - config: SafeConfig; + data: ConfigContextType; children: React.ReactNode; }) { - return {children}; + return {children}; } diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index a93bae95..e7a48f9b 100755 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -3,6 +3,7 @@ import type { SafeConfig } from '@/lib/config/safe'; import { fetchApi } from '@/lib/fetchApi'; import useAvatar from '@/lib/hooks/useAvatar'; import useLogin from '@/lib/hooks/useLogin'; +import { Outlet, useLocation } from 'react-router-dom'; import { isAdministrator } from '@/lib/role'; import { useUserStore } from '@/lib/store/user'; import { @@ -44,11 +45,11 @@ import { IconUpload, IconUsersGroup, } from '@tabler/icons-react'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; import { useState } from 'react'; import ConfigProvider from './ConfigProvider'; import VersionBadge from './VersionBadge'; +import { Link, useLoaderData } from 'react-router-dom'; +import { dashboardLoader } from '../client/routes'; type NavLinks = { label: string; @@ -142,14 +143,17 @@ const navLinks: NavLinks[] = [ }, ]; -export default function Layout({ children, config }: { children: React.ReactNode; config: SafeConfig }) { +export default function Layout() { const theme = useMantineTheme(); const { colorScheme } = useMantineColorScheme(); const [opened, setOpened] = useState(false); - const router = useRouter(); const modals = useModals(); const clipboard = useClipboard(); const setUser = useUserStore((s) => s.setUser); + const location = useLocation(); + + const loaderData = useLoaderData(); + const config = loaderData.config; const { user, mutate } = useLogin(); const { avatar } = useAvatar(); @@ -275,7 +279,8 @@ export default function Layout({ children, config }: { children: React.ReactNode } component={Link} - href='/dashboard/settings' + to='/dashboard/settings' + prefetch='intent' > Settings @@ -284,7 +289,8 @@ export default function Layout({ children, config }: { children: React.ReactNode } component={Link} - href='/dashboard/admin/settings' + to='/dashboard/admin/settings' + prefetch='intent' > Server Settings @@ -295,7 +301,7 @@ export default function Layout({ children, config }: { children: React.ReactNode color='red' leftSection={} component={Link} - href='/auth/logout' + to='/auth/logout' > Logout @@ -322,9 +328,10 @@ export default function Layout({ children, config }: { children: React.ReactNode leftSection={link.icon} variant='light' rightSection={} - active={router.pathname === link.href} + active={location.pathname === link.href} component={Link} - href={link.href || ''} + to={link.href || ''} + prefetch='intent' /> ); } else { @@ -335,7 +342,7 @@ export default function Layout({ children, config }: { children: React.ReactNode leftSection={link.icon} variant='light' rightSection={} - defaultOpened={link.active(router.pathname)} + defaultOpened={link.active(location.pathname)} > {link.links .filter( @@ -348,9 +355,10 @@ export default function Layout({ children, config }: { children: React.ReactNode leftSection={sublink.icon} rightSection={} variant='light' - active={router.pathname === sublink.href} + active={location.pathname === sublink.href} component={Link} - href={sublink.href || ''} + to={sublink.href || ''} + prefetch='intent' /> ))} @@ -372,7 +380,7 @@ export default function Layout({ children, config }: { children: React.ReactNode leftSection={} variant='light' component={Link} - href={url} + to={url} target='_blank' /> ))} @@ -382,9 +390,9 @@ export default function Layout({ children, config }: { children: React.ReactNode - + - {children} + diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx index a786ea8a..083c1e74 100755 --- a/src/components/ThemeProvider.tsx +++ b/src/components/ThemeProvider.tsx @@ -1,3 +1,4 @@ +import { Response } from '@/lib/api/response'; import { Config } from '@/lib/config/validate'; import { useSettingsStore } from '@/lib/store/settings'; import { useUserStore } from '@/lib/store/user'; @@ -6,6 +7,7 @@ import dark_blue from '@/lib/theme/builtins/dark_blue'; import { MantineProvider, createTheme } from '@mantine/core'; import { useColorScheme } from '@mantine/hooks'; import { createContext, useContext } from 'react'; +import useSWR from 'swr'; import { useShallow } from 'zustand/shallow'; const ThemeContext = createContext<{ @@ -21,15 +23,25 @@ export function useThemes() { return ctx.themes; } -export default function Theming({ - themes, - defaultTheme, +export default function ThemeProvider({ + ssrThemes, + ssrDefaultTheme, children, }: { - themes: ZiplineTheme[]; + ssrThemes?: ZiplineTheme[]; + ssrDefaultTheme?: Config['website']['theme']; children: React.ReactNode; - defaultTheme?: Config['website']['theme']; }) { + const { data: clientThemes } = useSWR('/api/server/themes', { + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenHidden: false, + revalidateIfStale: false, + }); + + const themes = ssrThemes ?? clientThemes?.themes; + const defaultTheme = ssrDefaultTheme ?? clientThemes?.defaultTheme; + const user = useUserStore((state) => state.user); const [userTheme, preferredDark, preferredLight] = useSettingsStore( useShallow((state) => [state.settings.theme, state.settings.themeDark, state.settings.themeLight]), @@ -53,7 +65,7 @@ export default function Theming({ } return ( - + (null); + +export function useSsrData(): T { + const ctx = useContext(ZiplineSSRContext); + + return ctx as T; +} + +export default function ZiplineSSRProvider({ + children, + ssrData, +}: { + children: React.ReactNode; + ssrData: any; +}) { + return {children}; +} diff --git a/src/components/file/DashboardFileType.tsx b/src/components/file/DashboardFileType.tsx index 38369557..8c216bad 100755 --- a/src/components/file/DashboardFileType.tsx +++ b/src/components/file/DashboardFileType.tsx @@ -15,7 +15,6 @@ import { useEffect, useState, useCallback, useMemo } from 'react'; import { renderMode } from '../pages/upload/renderMode'; import Render from '../render/Render'; import fileIcon from './fileIcon'; -import { parseAsStringLiteral, useQueryState } from 'nuqs'; function PlaceholderContent({ text, Icon }: { text: string; Icon: Icon }) { return ( @@ -78,8 +77,6 @@ export default function DashboardFileType({ code?: boolean; allowZoom?: boolean; }) { - const [overrideType] = useQueryState('otype', parseAsStringLiteral(['video', 'audio', 'image', 'text'])); - const disableMediaPreview = useSettingsStore((state) => state.settings.disableMediaPreview); const dbFile = 'id' in file; @@ -135,7 +132,7 @@ export default function DashboardFileType({ if (code) { setType('text'); getText(); - } else if (overrideType === 'text' || type === 'text') { + } else if (type === 'text') { getText(); } else { return; @@ -167,7 +164,7 @@ export default function DashboardFileType({
); - switch (overrideType || type) { + switch (type) { case 'video': return show ? (