diff --git a/client/.gitignore b/client/.gitignore
deleted file mode 100644
index 54f07af..0000000
--- a/client/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
\ No newline at end of file
diff --git a/client/README.md b/client/README.md
deleted file mode 100644
index e16d995..0000000
--- a/client/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# React + Vite
-
-This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
-
-Currently, two official plugins are available:
-
-- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
-- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
-
-## React Compiler
-
-The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information.
-
-Note: This will impact Vite dev & build performances.
-
-## Expanding the ESLint configuration
-
-If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
diff --git a/client/eslint.config.js b/client/eslint.config.js
deleted file mode 100644
index ea36dd3..0000000
--- a/client/eslint.config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import js from '@eslint/js'
-import globals from 'globals'
-import reactHooks from 'eslint-plugin-react-hooks'
-import reactRefresh from 'eslint-plugin-react-refresh'
-import { defineConfig, globalIgnores } from 'eslint/config'
-
-export default defineConfig([
- globalIgnores(['dist']),
- {
- files: ['**/*.{js,jsx}'],
- extends: [
- js.configs.recommended,
- reactHooks.configs.flat.recommended,
- reactRefresh.configs.vite,
- ],
- languageOptions: {
- globals: globals.browser,
- parserOptions: { ecmaFeatures: { jsx: true } },
- },
- },
-])
diff --git a/client/index.html b/client/index.html
deleted file mode 100644
index 6e56e6e..0000000
--- a/client/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
- client
-
-
-
-
-
-
diff --git a/client/package.json b/client/package.json
deleted file mode 100644
index 90cb1bd..0000000
--- a/client/package.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "name": "client",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "vite build",
- "lint": "eslint .",
- "preview": "vite preview"
- },
- "dependencies": {
- "@tailwindcss/vite": "^4.2.4",
- "react": "^19.2.5",
- "react-dom": "^19.2.5",
- "react-router-dom": "^7.14.2",
- "tailwindcss": "^4.2.4"
- },
- "devDependencies": {
- "@babel/core": "^7.29.0",
- "@eslint/js": "^10.0.1",
- "@rolldown/plugin-babel": "^0.2.3",
- "@types/react": "^19.2.14",
- "@types/react-dom": "^19.2.3",
- "@vitejs/plugin-react": "^6.0.1",
- "babel-plugin-react-compiler": "^1.0.0",
- "eslint": "^10.2.1",
- "eslint-plugin-react-hooks": "^7.1.1",
- "eslint-plugin-react-refresh": "^0.5.2",
- "globals": "^17.5.0",
- "vite": "^8.0.10"
- }
-}
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
deleted file mode 100644
index e794e09..0000000
--- a/client/pnpm-lock.yaml
+++ /dev/null
@@ -1,1800 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- '@tailwindcss/vite':
- specifier: ^4.2.4
- version: 4.2.4(vite@8.0.10(jiti@2.6.1))
- react:
- specifier: ^19.2.5
- version: 19.2.5
- react-dom:
- specifier: ^19.2.5
- version: 19.2.5(react@19.2.5)
- react-router-dom:
- specifier: ^7.14.2
- version: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
- tailwindcss:
- specifier: ^4.2.4
- version: 4.2.4
- devDependencies:
- '@babel/core':
- specifier: ^7.29.0
- version: 7.29.0
- '@eslint/js':
- specifier: ^10.0.1
- version: 10.0.1(eslint@10.2.1(jiti@2.6.1))
- '@rolldown/plugin-babel':
- specifier: ^0.2.3
- version: 0.2.3(@babel/core@7.29.0)(rolldown@1.0.0-rc.17)(vite@8.0.10(jiti@2.6.1))
- '@types/react':
- specifier: ^19.2.14
- version: 19.2.14
- '@types/react-dom':
- specifier: ^19.2.3
- version: 19.2.3(@types/react@19.2.14)
- '@vitejs/plugin-react':
- specifier: ^6.0.1
- version: 6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.0)(rolldown@1.0.0-rc.17)(vite@8.0.10(jiti@2.6.1)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.10(jiti@2.6.1))
- babel-plugin-react-compiler:
- specifier: ^1.0.0
- version: 1.0.0
- eslint:
- specifier: ^10.2.1
- version: 10.2.1(jiti@2.6.1)
- eslint-plugin-react-hooks:
- specifier: ^7.1.1
- version: 7.1.1(eslint@10.2.1(jiti@2.6.1))
- eslint-plugin-react-refresh:
- specifier: ^0.5.2
- version: 0.5.2(eslint@10.2.1(jiti@2.6.1))
- globals:
- specifier: ^17.5.0
- version: 17.5.0
- vite:
- specifier: ^8.0.10
- version: 8.0.10(jiti@2.6.1)
-
-packages:
-
- '@babel/code-frame@7.29.0':
- resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.29.0':
- resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.29.0':
- resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.29.1':
- resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.28.6':
- resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
- 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.28.6':
- resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.28.6':
- resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-string-parser@7.27.1':
- resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-identifier@7.28.5':
- resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helpers@7.29.2':
- resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/parser@7.29.2':
- resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- '@babel/template@7.28.6':
- resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.29.0':
- resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/types@7.29.0':
- resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
- engines: {node: '>=6.9.0'}
-
- '@emnapi/core@1.10.0':
- resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
-
- '@emnapi/runtime@1.10.0':
- resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
-
- '@emnapi/wasi-threads@1.2.1':
- resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
-
- '@eslint-community/eslint-utils@4.9.1':
- resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- peerDependencies:
- eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
-
- '@eslint-community/regexpp@4.12.2':
- resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
- engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
-
- '@eslint/config-array@0.23.5':
- resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- '@eslint/config-helpers@0.5.5':
- resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- '@eslint/core@1.2.1':
- resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- '@eslint/js@10.0.1':
- resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
- peerDependencies:
- eslint: ^10.0.0
- peerDependenciesMeta:
- eslint:
- optional: true
-
- '@eslint/object-schema@3.0.5':
- resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- '@eslint/plugin-kit@0.7.1':
- resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- '@humanfs/core@0.19.2':
- resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==}
- engines: {node: '>=18.18.0'}
-
- '@humanfs/node@0.16.8':
- resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==}
- engines: {node: '>=18.18.0'}
-
- '@humanfs/types@0.15.0':
- resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==}
- engines: {node: '>=18.18.0'}
-
- '@humanwhocodes/module-importer@1.0.1':
- resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
- engines: {node: '>=12.22'}
-
- '@humanwhocodes/retry@0.4.3':
- resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
- engines: {node: '>=18.18'}
-
- '@jridgewell/gen-mapping@0.3.13':
- resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
-
- '@jridgewell/remapping@2.3.5':
- resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
-
- '@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.5.5':
- resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
-
- '@jridgewell/trace-mapping@0.3.31':
- resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
-
- '@napi-rs/wasm-runtime@1.1.4':
- resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
- peerDependencies:
- '@emnapi/core': ^1.7.1
- '@emnapi/runtime': ^1.7.1
-
- '@oxc-project/types@0.127.0':
- resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==}
-
- '@rolldown/binding-android-arm64@1.0.0-rc.17':
- resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [android]
-
- '@rolldown/binding-darwin-arm64@1.0.0-rc.17':
- resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [darwin]
-
- '@rolldown/binding-darwin-x64@1.0.0-rc.17':
- resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [darwin]
-
- '@rolldown/binding-freebsd-x64@1.0.0-rc.17':
- resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [freebsd]
-
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17':
- resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17':
- resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
- resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
- resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ppc64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
- resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [s390x]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
- resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
- resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
- resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [openharmony]
-
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.17':
- resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [wasm32]
-
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17':
- resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [win32]
-
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17':
- resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [win32]
-
- '@rolldown/plugin-babel@0.2.3':
- resolution: {integrity: sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==}
- engines: {node: '>=22.12.0 || ^24.0.0'}
- peerDependencies:
- '@babel/core': ^7.29.0 || ^8.0.0-rc.1
- '@babel/plugin-transform-runtime': ^7.29.0 || ^8.0.0-rc.1
- '@babel/runtime': ^7.27.0 || ^8.0.0-rc.1
- rolldown: ^1.0.0-rc.5
- vite: ^8.0.0
- peerDependenciesMeta:
- '@babel/plugin-transform-runtime':
- optional: true
- '@babel/runtime':
- optional: true
- vite:
- optional: true
-
- '@rolldown/pluginutils@1.0.0-rc.17':
- resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==}
-
- '@rolldown/pluginutils@1.0.0-rc.7':
- resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
-
- '@tailwindcss/node@4.2.4':
- resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==}
-
- '@tailwindcss/oxide-android-arm64@4.2.4':
- resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [android]
-
- '@tailwindcss/oxide-darwin-arm64@4.2.4':
- resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [darwin]
-
- '@tailwindcss/oxide-darwin-x64@4.2.4':
- resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [darwin]
-
- '@tailwindcss/oxide-freebsd-x64@4.2.4':
- resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [freebsd]
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4':
- resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==}
- engines: {node: '>= 20'}
- cpu: [arm]
- os: [linux]
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.2.4':
- resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-arm64-musl@4.2.4':
- resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-linux-x64-gnu@4.2.4':
- resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-x64-musl@4.2.4':
- resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-wasm32-wasi@4.2.4':
- resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==}
- engines: {node: '>=14.0.0'}
- cpu: [wasm32]
- bundledDependencies:
- - '@napi-rs/wasm-runtime'
- - '@emnapi/core'
- - '@emnapi/runtime'
- - '@tybys/wasm-util'
- - '@emnapi/wasi-threads'
- - tslib
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.2.4':
- resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [win32]
-
- '@tailwindcss/oxide-win32-x64-msvc@4.2.4':
- resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [win32]
-
- '@tailwindcss/oxide@4.2.4':
- resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==}
- engines: {node: '>= 20'}
-
- '@tailwindcss/vite@4.2.4':
- resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==}
- peerDependencies:
- vite: ^5.2.0 || ^6 || ^7 || ^8
-
- '@tybys/wasm-util@0.10.1':
- resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
-
- '@types/esrecurse@4.3.1':
- resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==}
-
- '@types/estree@1.0.8':
- resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
-
- '@types/json-schema@7.0.15':
- resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
-
- '@types/react-dom@19.2.3':
- resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
- peerDependencies:
- '@types/react': ^19.2.0
-
- '@types/react@19.2.14':
- resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
-
- '@vitejs/plugin-react@6.0.1':
- resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- peerDependencies:
- '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
- babel-plugin-react-compiler: ^1.0.0
- vite: ^8.0.0
- peerDependenciesMeta:
- '@rolldown/plugin-babel':
- optional: true
- babel-plugin-react-compiler:
- optional: true
-
- acorn-jsx@5.3.2:
- resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
- peerDependencies:
- acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
-
- acorn@8.16.0:
- resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
- engines: {node: '>=0.4.0'}
- hasBin: true
-
- ajv@6.15.0:
- resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==}
-
- babel-plugin-react-compiler@1.0.0:
- resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==}
-
- balanced-match@4.0.4:
- resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
- engines: {node: 18 || 20 || >=22}
-
- baseline-browser-mapping@2.10.23:
- resolution: {integrity: sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- brace-expansion@5.0.5:
- resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==}
- engines: {node: 18 || 20 || >=22}
-
- browserslist@4.28.2:
- resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
- caniuse-lite@1.0.30001791:
- resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==}
-
- convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-
- cookie@1.1.1:
- resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
- engines: {node: '>=18'}
-
- cross-spawn@7.0.6:
- resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
- engines: {node: '>= 8'}
-
- csstype@3.2.3:
- resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
-
- debug@4.4.3:
- resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
-
- deep-is@0.1.4:
- resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
-
- detect-libc@2.1.2:
- resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
- engines: {node: '>=8'}
-
- electron-to-chromium@1.5.344:
- resolution: {integrity: sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==}
-
- enhanced-resolve@5.21.0:
- resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==}
- engines: {node: '>=10.13.0'}
-
- escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
-
- escape-string-regexp@4.0.0:
- resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
- engines: {node: '>=10'}
-
- eslint-plugin-react-hooks@7.1.1:
- resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==}
- engines: {node: '>=18'}
- peerDependencies:
- eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0
-
- eslint-plugin-react-refresh@0.5.2:
- resolution: {integrity: sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==}
- peerDependencies:
- eslint: ^9 || ^10
-
- eslint-scope@9.1.2:
- resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- eslint-visitor-keys@3.4.3:
- resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-
- eslint-visitor-keys@5.0.1:
- resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- eslint@10.2.1:
- resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
- hasBin: true
- peerDependencies:
- jiti: '*'
- peerDependenciesMeta:
- jiti:
- optional: true
-
- espree@11.2.0:
- resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- esquery@1.7.0:
- resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
- engines: {node: '>=0.10'}
-
- esrecurse@4.3.0:
- resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
- engines: {node: '>=4.0'}
-
- estraverse@5.3.0:
- resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
- engines: {node: '>=4.0'}
-
- esutils@2.0.3:
- resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
- engines: {node: '>=0.10.0'}
-
- fast-deep-equal@3.1.3:
- resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-
- fast-json-stable-stringify@2.1.0:
- resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
-
- fast-levenshtein@2.0.6:
- resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
-
- fdir@6.5.0:
- resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- picomatch: ^3 || ^4
- peerDependenciesMeta:
- picomatch:
- optional: true
-
- file-entry-cache@8.0.0:
- resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
- engines: {node: '>=16.0.0'}
-
- find-up@5.0.0:
- resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
- engines: {node: '>=10'}
-
- flat-cache@4.0.1:
- resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
- engines: {node: '>=16'}
-
- flatted@3.4.2:
- resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
-
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
-
- gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
-
- glob-parent@6.0.2:
- resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
- engines: {node: '>=10.13.0'}
-
- globals@17.5.0:
- resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==}
- engines: {node: '>=18'}
-
- graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- hermes-estree@0.25.1:
- resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
-
- hermes-parser@0.25.1:
- resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
-
- ignore@5.3.2:
- resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
- engines: {node: '>= 4'}
-
- imurmurhash@0.1.4:
- resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
- engines: {node: '>=0.8.19'}
-
- is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
-
- is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
-
- isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-
- jiti@2.6.1:
- resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
- hasBin: true
-
- js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
- jsesc@3.1.0:
- resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
- engines: {node: '>=6'}
- hasBin: true
-
- json-buffer@3.0.1:
- resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
-
- json-schema-traverse@0.4.1:
- resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
-
- json-stable-stringify-without-jsonify@1.0.1:
- resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
-
- json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
-
- keyv@4.5.4:
- resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
-
- levn@0.4.1:
- resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
- engines: {node: '>= 0.8.0'}
-
- lightningcss-android-arm64@1.32.0:
- resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [android]
-
- lightningcss-darwin-arm64@1.32.0:
- resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [darwin]
-
- lightningcss-darwin-x64@1.32.0:
- resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [darwin]
-
- lightningcss-freebsd-x64@1.32.0:
- resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [freebsd]
-
- lightningcss-linux-arm-gnueabihf@1.32.0:
- resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm]
- os: [linux]
-
- lightningcss-linux-arm64-gnu@1.32.0:
- resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-arm64-musl@1.32.0:
- resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- lightningcss-linux-x64-gnu@1.32.0:
- resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-x64-musl@1.32.0:
- resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- lightningcss-win32-arm64-msvc@1.32.0:
- resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [win32]
-
- lightningcss-win32-x64-msvc@1.32.0:
- resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [win32]
-
- lightningcss@1.32.0:
- resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
- engines: {node: '>= 12.0.0'}
-
- locate-path@6.0.0:
- resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
- engines: {node: '>=10'}
-
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
-
- magic-string@0.30.21:
- resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
-
- minimatch@10.2.5:
- resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
- engines: {node: 18 || 20 || >=22}
-
- ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-
- nanoid@3.3.11:
- resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
-
- natural-compare@1.4.0:
- resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
-
- node-releases@2.0.38:
- resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==}
-
- optionator@0.9.4:
- resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
- engines: {node: '>= 0.8.0'}
-
- p-limit@3.1.0:
- resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
- engines: {node: '>=10'}
-
- p-locate@5.0.0:
- resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
- engines: {node: '>=10'}
-
- path-exists@4.0.0:
- resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
- engines: {node: '>=8'}
-
- path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
-
- picocolors@1.1.1:
- resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
-
- picomatch@4.0.4:
- resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
- engines: {node: '>=12'}
-
- postcss@8.5.12:
- resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==}
- engines: {node: ^10 || ^12 || >=14}
-
- prelude-ls@1.2.1:
- resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
- engines: {node: '>= 0.8.0'}
-
- punycode@2.3.1:
- resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
- engines: {node: '>=6'}
-
- react-dom@19.2.5:
- resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==}
- peerDependencies:
- react: ^19.2.5
-
- react-router-dom@7.14.2:
- resolution: {integrity: sha512-YZcM5ES8jJSM+KrJ9BdvHHqlnGTg5tH3sC5ChFRj4inosKctdyzBDhOyyHdGk597q2OT6NTrCA1OvB/YDwfekQ==}
- engines: {node: '>=20.0.0'}
- peerDependencies:
- react: '>=18'
- react-dom: '>=18'
-
- react-router@7.14.2:
- resolution: {integrity: sha512-yCqNne6I8IB6rVCH7XUvlBK7/QKyqypBFGv+8dj4QBFJiiRX+FG7/nkdAvGElyvVZ/HQP5N19wzteuTARXi5Gw==}
- engines: {node: '>=20.0.0'}
- peerDependencies:
- react: '>=18'
- react-dom: '>=18'
- peerDependenciesMeta:
- react-dom:
- optional: true
-
- react@19.2.5:
- resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==}
- engines: {node: '>=0.10.0'}
-
- rolldown@1.0.0-rc.17:
- resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
-
- scheduler@0.27.0:
- resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
-
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
- set-cookie-parser@2.7.2:
- resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
-
- shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
-
- shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
-
- source-map-js@1.2.1:
- resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
- engines: {node: '>=0.10.0'}
-
- tailwindcss@4.2.4:
- resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==}
-
- tapable@2.3.3:
- resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
- engines: {node: '>=6'}
-
- tinyglobby@0.2.16:
- resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
- engines: {node: '>=12.0.0'}
-
- tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
- type-check@0.4.0:
- resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
- engines: {node: '>= 0.8.0'}
-
- update-browserslist-db@1.2.3:
- resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
- uri-js@4.4.1:
- resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
-
- vite@8.0.10:
- resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
- peerDependencies:
- '@types/node': ^20.19.0 || >=22.12.0
- '@vitejs/devtools': ^0.1.0
- esbuild: ^0.27.0 || ^0.28.0
- jiti: '>=1.21.0'
- less: ^4.0.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
- '@vitejs/devtools':
- optional: true
- esbuild:
- optional: true
- jiti:
- optional: true
- less:
- optional: true
- sass:
- optional: true
- sass-embedded:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
- tsx:
- optional: true
- yaml:
- optional: true
-
- which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
-
- word-wrap@1.2.5:
- resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
- engines: {node: '>=0.10.0'}
-
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
-
- yocto-queue@0.1.0:
- resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
- engines: {node: '>=10'}
-
- zod-validation-error@4.0.2:
- resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- zod: ^3.25.0 || ^4.0.0
-
- zod@4.3.6:
- resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
-
-snapshots:
-
- '@babel/code-frame@7.29.0':
- dependencies:
- '@babel/helper-validator-identifier': 7.28.5
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
- '@babel/compat-data@7.29.0': {}
-
- '@babel/core@7.29.0':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-compilation-targets': 7.28.6
- '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
- '@babel/helpers': 7.29.2
- '@babel/parser': 7.29.2
- '@babel/template': 7.28.6
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- '@jridgewell/remapping': 2.3.5
- convert-source-map: 2.0.0
- debug: 4.4.3
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/generator@7.29.1':
- dependencies:
- '@babel/parser': 7.29.2
- '@babel/types': 7.29.0
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
- jsesc: 3.1.0
-
- '@babel/helper-compilation-targets@7.28.6':
- dependencies:
- '@babel/compat-data': 7.29.0
- '@babel/helper-validator-option': 7.27.1
- browserslist: 4.28.2
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-globals@7.28.0': {}
-
- '@babel/helper-module-imports@7.28.6':
- dependencies:
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-module-imports': 7.28.6
- '@babel/helper-validator-identifier': 7.28.5
- '@babel/traverse': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-string-parser@7.27.1': {}
-
- '@babel/helper-validator-identifier@7.28.5': {}
-
- '@babel/helper-validator-option@7.27.1': {}
-
- '@babel/helpers@7.29.2':
- dependencies:
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
-
- '@babel/parser@7.29.2':
- dependencies:
- '@babel/types': 7.29.0
-
- '@babel/template@7.28.6':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/parser': 7.29.2
- '@babel/types': 7.29.0
-
- '@babel/traverse@7.29.0':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-globals': 7.28.0
- '@babel/parser': 7.29.2
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
- debug: 4.4.3
- transitivePeerDependencies:
- - supports-color
-
- '@babel/types@7.29.0':
- dependencies:
- '@babel/helper-string-parser': 7.27.1
- '@babel/helper-validator-identifier': 7.28.5
-
- '@emnapi/core@1.10.0':
- dependencies:
- '@emnapi/wasi-threads': 1.2.1
- tslib: 2.8.1
- optional: true
-
- '@emnapi/runtime@1.10.0':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@emnapi/wasi-threads@1.2.1':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))':
- dependencies:
- eslint: 10.2.1(jiti@2.6.1)
- eslint-visitor-keys: 3.4.3
-
- '@eslint-community/regexpp@4.12.2': {}
-
- '@eslint/config-array@0.23.5':
- dependencies:
- '@eslint/object-schema': 3.0.5
- debug: 4.4.3
- minimatch: 10.2.5
- transitivePeerDependencies:
- - supports-color
-
- '@eslint/config-helpers@0.5.5':
- dependencies:
- '@eslint/core': 1.2.1
-
- '@eslint/core@1.2.1':
- dependencies:
- '@types/json-schema': 7.0.15
-
- '@eslint/js@10.0.1(eslint@10.2.1(jiti@2.6.1))':
- optionalDependencies:
- eslint: 10.2.1(jiti@2.6.1)
-
- '@eslint/object-schema@3.0.5': {}
-
- '@eslint/plugin-kit@0.7.1':
- dependencies:
- '@eslint/core': 1.2.1
- levn: 0.4.1
-
- '@humanfs/core@0.19.2':
- dependencies:
- '@humanfs/types': 0.15.0
-
- '@humanfs/node@0.16.8':
- dependencies:
- '@humanfs/core': 0.19.2
- '@humanfs/types': 0.15.0
- '@humanwhocodes/retry': 0.4.3
-
- '@humanfs/types@0.15.0': {}
-
- '@humanwhocodes/module-importer@1.0.1': {}
-
- '@humanwhocodes/retry@0.4.3': {}
-
- '@jridgewell/gen-mapping@0.3.13':
- dependencies:
- '@jridgewell/sourcemap-codec': 1.5.5
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/remapping@2.3.5':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/resolve-uri@3.1.2': {}
-
- '@jridgewell/sourcemap-codec@1.5.5': {}
-
- '@jridgewell/trace-mapping@0.3.31':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.5
-
- '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
- dependencies:
- '@emnapi/core': 1.10.0
- '@emnapi/runtime': 1.10.0
- '@tybys/wasm-util': 0.10.1
- optional: true
-
- '@oxc-project/types@0.127.0': {}
-
- '@rolldown/binding-android-arm64@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-darwin-arm64@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-darwin-x64@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-freebsd-x64@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.17':
- dependencies:
- '@emnapi/core': 1.10.0
- '@emnapi/runtime': 1.10.0
- '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
- optional: true
-
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17':
- optional: true
-
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17':
- optional: true
-
- '@rolldown/plugin-babel@0.2.3(@babel/core@7.29.0)(rolldown@1.0.0-rc.17)(vite@8.0.10(jiti@2.6.1))':
- dependencies:
- '@babel/core': 7.29.0
- picomatch: 4.0.4
- rolldown: 1.0.0-rc.17
- optionalDependencies:
- vite: 8.0.10(jiti@2.6.1)
-
- '@rolldown/pluginutils@1.0.0-rc.17': {}
-
- '@rolldown/pluginutils@1.0.0-rc.7': {}
-
- '@tailwindcss/node@4.2.4':
- dependencies:
- '@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.21.0
- jiti: 2.6.1
- lightningcss: 1.32.0
- magic-string: 0.30.21
- source-map-js: 1.2.1
- tailwindcss: 4.2.4
-
- '@tailwindcss/oxide-android-arm64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-darwin-arm64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-darwin-x64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-freebsd-x64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-musl@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-gnu@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-musl@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-wasm32-wasi@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-win32-x64-msvc@4.2.4':
- optional: true
-
- '@tailwindcss/oxide@4.2.4':
- optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.2.4
- '@tailwindcss/oxide-darwin-arm64': 4.2.4
- '@tailwindcss/oxide-darwin-x64': 4.2.4
- '@tailwindcss/oxide-freebsd-x64': 4.2.4
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4
- '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4
- '@tailwindcss/oxide-linux-arm64-musl': 4.2.4
- '@tailwindcss/oxide-linux-x64-gnu': 4.2.4
- '@tailwindcss/oxide-linux-x64-musl': 4.2.4
- '@tailwindcss/oxide-wasm32-wasi': 4.2.4
- '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4
- '@tailwindcss/oxide-win32-x64-msvc': 4.2.4
-
- '@tailwindcss/vite@4.2.4(vite@8.0.10(jiti@2.6.1))':
- dependencies:
- '@tailwindcss/node': 4.2.4
- '@tailwindcss/oxide': 4.2.4
- tailwindcss: 4.2.4
- vite: 8.0.10(jiti@2.6.1)
-
- '@tybys/wasm-util@0.10.1':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@types/esrecurse@4.3.1': {}
-
- '@types/estree@1.0.8': {}
-
- '@types/json-schema@7.0.15': {}
-
- '@types/react-dom@19.2.3(@types/react@19.2.14)':
- dependencies:
- '@types/react': 19.2.14
-
- '@types/react@19.2.14':
- dependencies:
- csstype: 3.2.3
-
- '@vitejs/plugin-react@6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.0)(rolldown@1.0.0-rc.17)(vite@8.0.10(jiti@2.6.1)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.10(jiti@2.6.1))':
- dependencies:
- '@rolldown/pluginutils': 1.0.0-rc.7
- vite: 8.0.10(jiti@2.6.1)
- optionalDependencies:
- '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.0)(rolldown@1.0.0-rc.17)(vite@8.0.10(jiti@2.6.1))
- babel-plugin-react-compiler: 1.0.0
-
- acorn-jsx@5.3.2(acorn@8.16.0):
- dependencies:
- acorn: 8.16.0
-
- acorn@8.16.0: {}
-
- ajv@6.15.0:
- dependencies:
- fast-deep-equal: 3.1.3
- fast-json-stable-stringify: 2.1.0
- json-schema-traverse: 0.4.1
- uri-js: 4.4.1
-
- babel-plugin-react-compiler@1.0.0:
- dependencies:
- '@babel/types': 7.29.0
-
- balanced-match@4.0.4: {}
-
- baseline-browser-mapping@2.10.23: {}
-
- brace-expansion@5.0.5:
- dependencies:
- balanced-match: 4.0.4
-
- browserslist@4.28.2:
- dependencies:
- baseline-browser-mapping: 2.10.23
- caniuse-lite: 1.0.30001791
- electron-to-chromium: 1.5.344
- node-releases: 2.0.38
- update-browserslist-db: 1.2.3(browserslist@4.28.2)
-
- caniuse-lite@1.0.30001791: {}
-
- convert-source-map@2.0.0: {}
-
- cookie@1.1.1: {}
-
- cross-spawn@7.0.6:
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
- csstype@3.2.3: {}
-
- debug@4.4.3:
- dependencies:
- ms: 2.1.3
-
- deep-is@0.1.4: {}
-
- detect-libc@2.1.2: {}
-
- electron-to-chromium@1.5.344: {}
-
- enhanced-resolve@5.21.0:
- dependencies:
- graceful-fs: 4.2.11
- tapable: 2.3.3
-
- escalade@3.2.0: {}
-
- escape-string-regexp@4.0.0: {}
-
- eslint-plugin-react-hooks@7.1.1(eslint@10.2.1(jiti@2.6.1)):
- dependencies:
- '@babel/core': 7.29.0
- '@babel/parser': 7.29.2
- eslint: 10.2.1(jiti@2.6.1)
- hermes-parser: 0.25.1
- zod: 4.3.6
- zod-validation-error: 4.0.2(zod@4.3.6)
- transitivePeerDependencies:
- - supports-color
-
- eslint-plugin-react-refresh@0.5.2(eslint@10.2.1(jiti@2.6.1)):
- dependencies:
- eslint: 10.2.1(jiti@2.6.1)
-
- eslint-scope@9.1.2:
- dependencies:
- '@types/esrecurse': 4.3.1
- '@types/estree': 1.0.8
- esrecurse: 4.3.0
- estraverse: 5.3.0
-
- eslint-visitor-keys@3.4.3: {}
-
- eslint-visitor-keys@5.0.1: {}
-
- eslint@10.2.1(jiti@2.6.1):
- dependencies:
- '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1))
- '@eslint-community/regexpp': 4.12.2
- '@eslint/config-array': 0.23.5
- '@eslint/config-helpers': 0.5.5
- '@eslint/core': 1.2.1
- '@eslint/plugin-kit': 0.7.1
- '@humanfs/node': 0.16.8
- '@humanwhocodes/module-importer': 1.0.1
- '@humanwhocodes/retry': 0.4.3
- '@types/estree': 1.0.8
- ajv: 6.15.0
- cross-spawn: 7.0.6
- debug: 4.4.3
- escape-string-regexp: 4.0.0
- eslint-scope: 9.1.2
- eslint-visitor-keys: 5.0.1
- espree: 11.2.0
- esquery: 1.7.0
- esutils: 2.0.3
- fast-deep-equal: 3.1.3
- file-entry-cache: 8.0.0
- find-up: 5.0.0
- glob-parent: 6.0.2
- ignore: 5.3.2
- imurmurhash: 0.1.4
- is-glob: 4.0.3
- json-stable-stringify-without-jsonify: 1.0.1
- minimatch: 10.2.5
- natural-compare: 1.4.0
- optionator: 0.9.4
- optionalDependencies:
- jiti: 2.6.1
- transitivePeerDependencies:
- - supports-color
-
- espree@11.2.0:
- dependencies:
- acorn: 8.16.0
- acorn-jsx: 5.3.2(acorn@8.16.0)
- eslint-visitor-keys: 5.0.1
-
- esquery@1.7.0:
- dependencies:
- estraverse: 5.3.0
-
- esrecurse@4.3.0:
- dependencies:
- estraverse: 5.3.0
-
- estraverse@5.3.0: {}
-
- esutils@2.0.3: {}
-
- fast-deep-equal@3.1.3: {}
-
- fast-json-stable-stringify@2.1.0: {}
-
- fast-levenshtein@2.0.6: {}
-
- fdir@6.5.0(picomatch@4.0.4):
- optionalDependencies:
- picomatch: 4.0.4
-
- file-entry-cache@8.0.0:
- dependencies:
- flat-cache: 4.0.1
-
- find-up@5.0.0:
- dependencies:
- locate-path: 6.0.0
- path-exists: 4.0.0
-
- flat-cache@4.0.1:
- dependencies:
- flatted: 3.4.2
- keyv: 4.5.4
-
- flatted@3.4.2: {}
-
- fsevents@2.3.3:
- optional: true
-
- gensync@1.0.0-beta.2: {}
-
- glob-parent@6.0.2:
- dependencies:
- is-glob: 4.0.3
-
- globals@17.5.0: {}
-
- graceful-fs@4.2.11: {}
-
- hermes-estree@0.25.1: {}
-
- hermes-parser@0.25.1:
- dependencies:
- hermes-estree: 0.25.1
-
- ignore@5.3.2: {}
-
- imurmurhash@0.1.4: {}
-
- is-extglob@2.1.1: {}
-
- is-glob@4.0.3:
- dependencies:
- is-extglob: 2.1.1
-
- isexe@2.0.0: {}
-
- jiti@2.6.1: {}
-
- js-tokens@4.0.0: {}
-
- jsesc@3.1.0: {}
-
- json-buffer@3.0.1: {}
-
- json-schema-traverse@0.4.1: {}
-
- json-stable-stringify-without-jsonify@1.0.1: {}
-
- json5@2.2.3: {}
-
- keyv@4.5.4:
- dependencies:
- json-buffer: 3.0.1
-
- levn@0.4.1:
- dependencies:
- prelude-ls: 1.2.1
- type-check: 0.4.0
-
- lightningcss-android-arm64@1.32.0:
- optional: true
-
- lightningcss-darwin-arm64@1.32.0:
- optional: true
-
- lightningcss-darwin-x64@1.32.0:
- optional: true
-
- lightningcss-freebsd-x64@1.32.0:
- optional: true
-
- lightningcss-linux-arm-gnueabihf@1.32.0:
- optional: true
-
- lightningcss-linux-arm64-gnu@1.32.0:
- optional: true
-
- lightningcss-linux-arm64-musl@1.32.0:
- optional: true
-
- lightningcss-linux-x64-gnu@1.32.0:
- optional: true
-
- lightningcss-linux-x64-musl@1.32.0:
- optional: true
-
- lightningcss-win32-arm64-msvc@1.32.0:
- optional: true
-
- lightningcss-win32-x64-msvc@1.32.0:
- optional: true
-
- lightningcss@1.32.0:
- dependencies:
- detect-libc: 2.1.2
- optionalDependencies:
- lightningcss-android-arm64: 1.32.0
- lightningcss-darwin-arm64: 1.32.0
- lightningcss-darwin-x64: 1.32.0
- lightningcss-freebsd-x64: 1.32.0
- lightningcss-linux-arm-gnueabihf: 1.32.0
- lightningcss-linux-arm64-gnu: 1.32.0
- lightningcss-linux-arm64-musl: 1.32.0
- lightningcss-linux-x64-gnu: 1.32.0
- lightningcss-linux-x64-musl: 1.32.0
- lightningcss-win32-arm64-msvc: 1.32.0
- lightningcss-win32-x64-msvc: 1.32.0
-
- locate-path@6.0.0:
- dependencies:
- p-locate: 5.0.0
-
- lru-cache@5.1.1:
- dependencies:
- yallist: 3.1.1
-
- magic-string@0.30.21:
- dependencies:
- '@jridgewell/sourcemap-codec': 1.5.5
-
- minimatch@10.2.5:
- dependencies:
- brace-expansion: 5.0.5
-
- ms@2.1.3: {}
-
- nanoid@3.3.11: {}
-
- natural-compare@1.4.0: {}
-
- node-releases@2.0.38: {}
-
- optionator@0.9.4:
- dependencies:
- deep-is: 0.1.4
- fast-levenshtein: 2.0.6
- levn: 0.4.1
- prelude-ls: 1.2.1
- type-check: 0.4.0
- word-wrap: 1.2.5
-
- p-limit@3.1.0:
- dependencies:
- yocto-queue: 0.1.0
-
- p-locate@5.0.0:
- dependencies:
- p-limit: 3.1.0
-
- path-exists@4.0.0: {}
-
- path-key@3.1.1: {}
-
- picocolors@1.1.1: {}
-
- picomatch@4.0.4: {}
-
- postcss@8.5.12:
- dependencies:
- nanoid: 3.3.11
- picocolors: 1.1.1
- source-map-js: 1.2.1
-
- prelude-ls@1.2.1: {}
-
- punycode@2.3.1: {}
-
- react-dom@19.2.5(react@19.2.5):
- dependencies:
- react: 19.2.5
- scheduler: 0.27.0
-
- react-router-dom@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
- dependencies:
- react: 19.2.5
- react-dom: 19.2.5(react@19.2.5)
- react-router: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
-
- react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
- dependencies:
- cookie: 1.1.1
- react: 19.2.5
- set-cookie-parser: 2.7.2
- optionalDependencies:
- react-dom: 19.2.5(react@19.2.5)
-
- react@19.2.5: {}
-
- rolldown@1.0.0-rc.17:
- dependencies:
- '@oxc-project/types': 0.127.0
- '@rolldown/pluginutils': 1.0.0-rc.17
- optionalDependencies:
- '@rolldown/binding-android-arm64': 1.0.0-rc.17
- '@rolldown/binding-darwin-arm64': 1.0.0-rc.17
- '@rolldown/binding-darwin-x64': 1.0.0-rc.17
- '@rolldown/binding-freebsd-x64': 1.0.0-rc.17
- '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17
- '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17
- '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17
- '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17
- '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17
- '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17
- '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17
- '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17
- '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17
- '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17
- '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17
-
- scheduler@0.27.0: {}
-
- semver@6.3.1: {}
-
- set-cookie-parser@2.7.2: {}
-
- shebang-command@2.0.0:
- dependencies:
- shebang-regex: 3.0.0
-
- shebang-regex@3.0.0: {}
-
- source-map-js@1.2.1: {}
-
- tailwindcss@4.2.4: {}
-
- tapable@2.3.3: {}
-
- tinyglobby@0.2.16:
- dependencies:
- fdir: 6.5.0(picomatch@4.0.4)
- picomatch: 4.0.4
-
- tslib@2.8.1:
- optional: true
-
- type-check@0.4.0:
- dependencies:
- prelude-ls: 1.2.1
-
- update-browserslist-db@1.2.3(browserslist@4.28.2):
- dependencies:
- browserslist: 4.28.2
- escalade: 3.2.0
- picocolors: 1.1.1
-
- uri-js@4.4.1:
- dependencies:
- punycode: 2.3.1
-
- vite@8.0.10(jiti@2.6.1):
- dependencies:
- lightningcss: 1.32.0
- picomatch: 4.0.4
- postcss: 8.5.12
- rolldown: 1.0.0-rc.17
- tinyglobby: 0.2.16
- optionalDependencies:
- fsevents: 2.3.3
- jiti: 2.6.1
-
- which@2.0.2:
- dependencies:
- isexe: 2.0.0
-
- word-wrap@1.2.5: {}
-
- yallist@3.1.1: {}
-
- yocto-queue@0.1.0: {}
-
- zod-validation-error@4.0.2(zod@4.3.6):
- dependencies:
- zod: 4.3.6
-
- zod@4.3.6: {}
diff --git a/client/public/favicon.svg b/client/public/favicon.svg
deleted file mode 100644
index 6893eb1..0000000
--- a/client/public/favicon.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/client/public/icons.svg b/client/public/icons.svg
deleted file mode 100644
index e952219..0000000
--- a/client/public/icons.svg
+++ /dev/null
@@ -1,24 +0,0 @@
-
diff --git a/client/src/App.jsx b/client/src/App.jsx
deleted file mode 100644
index 150a00f..0000000
--- a/client/src/App.jsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"
-import AuthPage from "./components/AuthPage.jsx"
-import MainApp from "./components/MainApp"
-import SettingsPage from "./components/SettingsPage"
-import "./index.css"
-
-function ProtectedRoute({ children }) {
- const token = localStorage.getItem("token")
- if (!token) return
- return children
-}
-
-export default function App() {
- return (
-
-
- } />
-
-
-
- } />
-
-
-
- } />
-
-
- )
-}
diff --git a/client/src/api/http.js b/client/src/api/http.js
deleted file mode 100644
index 6883e46..0000000
--- a/client/src/api/http.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const BASE = 'http://localhost:8080'
-
-export async function apiFetch(method, path, { body, query } = {}) {
- const token = localStorage.getItem('token') || ''
- let url = BASE + path
- if (query) url += '?' + new URLSearchParams(query)
- const opts = { method, headers: token ? { token } : {} }
- if (body) opts.body = body instanceof FormData ? body : new URLSearchParams(body)
- const res = await fetch(url, opts)
- if (!res.ok) { const errText = await res.text(); throw new Error(`${method} ${path} → ${res.status}: ${errText}`) }
- const text = await res.text()
- try { return JSON.parse(text) } catch { return text }
-}
diff --git a/client/src/api/ws.js b/client/src/api/ws.js
deleted file mode 100644
index 6a4a361..0000000
--- a/client/src/api/ws.js
+++ /dev/null
@@ -1,26 +0,0 @@
-let socket = null
-const handlers = {}
-
-export function wsOnEvent(type, fn) {
- handlers[type] = fn
-}
-
-export function wsConnect() {
- if (socket) return
- const token = localStorage.getItem('token') || ''
- socket = new WebSocket('ws://localhost:8080/ws')
- socket.onopen = () => socket.send(JSON.stringify({ token }))
- socket.onmessage = (e) => {
- try {
- const msg = JSON.parse(e.data)
- handlers[msg.type]?.(msg.event)
- } catch (err) { console.error('[ws] message error', err) }
- }
- socket.onclose = () => { socket = null }
- socket.onerror = (err) => console.error('[ws] error', err)
-}
-
-export function wsDisconnect() {
- socket?.close()
- socket = null
-}
diff --git a/client/src/components/AuthPage.jsx b/client/src/components/AuthPage.jsx
deleted file mode 100644
index 001d11f..0000000
--- a/client/src/components/AuthPage.jsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { useState } from 'react'
-import { useNavigate } from 'react-router-dom'
-
-const BASE = 'http://localhost:8080'
-
-export default function AuthPage() {
- const navigate = useNavigate()
- const [username, setUsername] = useState('')
- const [password, setPassword] = useState('')
- const [error, setError] = useState('')
- const [loading, setLoading] = useState(false)
-
- async function doLogin() {
- const res = await fetch(`${BASE}/token`, {
- method: 'POST',
- body: new URLSearchParams({ username, password }),
- })
- if (!res.ok) throw new Error('Invalid credentials')
- const { token, userId } = await res.json()
- localStorage.setItem('token', token)
- localStorage.setItem('userId', userId)
- navigate('/')
- }
-
- async function handleLogin() {
- if (!username.trim() || !password.trim()) { setError('Username and password are required'); return }
- setError('')
- setLoading(true)
- try {
- await doLogin()
- } catch {
- setError('Invalid credentials')
- } finally {
- setLoading(false)
- }
- }
-
- async function handleRegister() {
- if (!username.trim() || !password.trim()) { setError('Username and password are required'); return }
- setError('')
- setLoading(true)
- try {
- const res = await fetch(`${BASE}/user`, {
- method: 'POST',
- body: new URLSearchParams({ username, password }),
- })
- if (!res.ok) { setError('Registration failed'); return }
- await doLogin()
- } catch {
- setError('Could not reach server')
- } finally {
- setLoading(false)
- }
- }
-
- function onKey(e) {
- if (e.key === 'Enter' && !loading) handleLogin()
- }
-
- return (
-
-
-
go-socket
-
setUsername(e.target.value)}
- onKeyDown={onKey}
- autoComplete="username"
- />
-
setPassword(e.target.value)}
- onKeyDown={onKey}
- autoComplete="current-password"
- />
- {error &&
{error}
}
-
-
-
-
-
-
- )
-}
diff --git a/client/src/components/ChatArea.jsx b/client/src/components/ChatArea.jsx
deleted file mode 100644
index 22ff3de..0000000
--- a/client/src/components/ChatArea.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { useState } from 'react'
-import { useApp } from '../context/AppContext'
-import { colorToCss } from '../utils/color'
-import { connectionStatus } from '../utils/connection'
-import MessageList from './MessageList'
-import MessageInput from './MessageInput'
-
-export default function ChatArea() {
- const { state, userId } = useApp()
- const conn = state.connections.find(c => c.id === state.selectedId)
- const [pendingFile, setPendingFile] = useState(null)
- const [dragCount, setDragCount] = useState(0)
- const isDragging = dragCount > 0
-
- function onDragEnter(e) {
- if (Array.from(e.dataTransfer?.types ?? []).includes('Files')) {
- setDragCount(c => c + 1)
- }
- }
- function onDragLeave() {
- setDragCount(c => Math.max(0, c - 1))
- }
- function onDragOver(e) {
- if (Array.from(e.dataTransfer?.types ?? []).includes('Files')) {
- e.preventDefault()
- }
- }
- function onDrop(e) {
- e.preventDefault()
- setDragCount(0)
- const file = e.dataTransfer?.files?.[0]
- if (file && state.selectedId) setPendingFile(file)
- }
-
- let header = null
- if (conn) {
- const otherId = conn.requestorId === userId ? conn.recipientId : conn.requestorId
- const other = state.userMap[otherId]
- const status = connectionStatus(conn, userId)
- header = (
-
-
- {other?.name?.[0]?.toUpperCase() ?? '?'}
-
-
-
{other?.name ?? '…'}
- {other?.pronouns && (
-
{other.pronouns}
- )}
-
- {status && (
-
● {status.label}
- )}
-
- )
- }
-
- return (
-
- {header}
- {state.selectedId ? (
- <>
-
-
- >
- ) : (
-
- Select a conversation
-
- )}
- {isDragging && state.selectedId && (
-
- )}
-
- )
-}
diff --git a/client/src/components/ConnectionItem.jsx b/client/src/components/ConnectionItem.jsx
deleted file mode 100644
index 48887ca..0000000
--- a/client/src/components/ConnectionItem.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { useApp } from '../context/AppContext'
-import { colorToCss } from '../utils/color'
-import { connectionStatus } from '../utils/connection'
-
-export default function ConnectionItem({ conn, onContextMenu }) {
- const { state, selectConnection, userId } = useApp()
- const otherId = conn.requestorId === userId ? conn.recipientId : conn.requestorId
- const other = state.userMap[otherId]
- const unread = state.unread[conn.id] || 0
- const isSelected = state.selectedId === conn.id
- const status = connectionStatus(conn, userId)
-
- return (
-
- )
-}
diff --git a/client/src/components/ConnectionList.jsx b/client/src/components/ConnectionList.jsx
deleted file mode 100644
index 9f69e57..0000000
--- a/client/src/components/ConnectionList.jsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { useEffect, useState } from 'react'
-import { useApp } from '../context/AppContext'
-import ConnectionItem from './ConnectionItem'
-import ConnectionMenu from './ConnectionMenu'
-
-export default function ConnectionList() {
- const { state, userId } = useApp()
- const [search, setSearch] = useState('')
- const [menu, setMenu] = useState(null)
- const [notice, setNotice] = useState('')
-
- useEffect(() => {
- if (!notice) return
- const t = setTimeout(() => setNotice(''), 2500)
- return () => clearTimeout(t)
- }, [notice])
-
- const filtered = state.connections.filter(conn => {
- if (!search) return true
- const otherId = conn.requestorId === userId ? conn.recipientId : conn.requestorId
- const other = state.userMap[otherId]
- const haystack = (other?.name ?? otherId.slice(0, 8)).toLowerCase()
- return haystack.includes(search.toLowerCase())
- })
-
- return (
-
-
- setSearch(e.target.value)}
- />
-
-
-
- {filtered.length === 0 && (
-
No contacts
- )}
- {filtered.map(conn => (
-
{
- e.preventDefault()
- setMenu({ x: e.clientX, y: e.clientY, conn })
- }}
- />
- ))}
-
-
- {notice && (
-
- {notice}
-
- )}
-
- {menu && (
-
setMenu(null)}
- onNotice={setNotice}
- />
- )}
-
- )
-}
diff --git a/client/src/components/ConnectionMenu.jsx b/client/src/components/ConnectionMenu.jsx
deleted file mode 100644
index 0c55c3c..0000000
--- a/client/src/components/ConnectionMenu.jsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { useEffect, useRef } from 'react'
-import { useApp } from '../context/AppContext'
-import { pendingActor } from '../utils/connection'
-
-export default function ConnectionMenu({ x, y, conn, onClose, onNotice }) {
- const { userId, elevateConnection, deelevateConnection, deleteConnection } = useApp()
- const ref = useRef(null)
-
- useEffect(() => {
- function handleDown(e) {
- if (!ref.current?.contains(e.target)) onClose()
- }
- function handleEsc(e) {
- if (e.key === 'Escape') onClose()
- }
- document.addEventListener('mousedown', handleDown)
- document.addEventListener('keydown', handleEsc)
- return () => {
- document.removeEventListener('mousedown', handleDown)
- document.removeEventListener('keydown', handleEsc)
- }
- }, [onClose])
-
- function run(label, fn) {
- onClose()
- fn().then(
- result => {
- if (label === 'elevate' && result === 'waiting') {
- onNotice('Friend request sent — waiting for the other user')
- } else if (label === 'elevate' && result === 'elevated') {
- onNotice('Now friends')
- } else if (label === 'deelevate') {
- onNotice('Unfriended')
- } else if (label === 'delete') {
- onNotice('Connection removed')
- }
- },
- err => onNotice(err.message ?? String(err)),
- )
- }
-
- const isFriend = conn.state === 1
- const pending = pendingActor(conn)
- const iAmPending = pending === userId
- const otherIsPending = pending && !iAmPending
-
- return (
-
- {isFriend && (
-
- )}
- {!isFriend && otherIsPending && (
-
- )}
- {!isFriend && !pending && (
-
- )}
- {!isFriend && iAmPending && (
-
Friend request pending…
- )}
-
-
-
- )
-}
diff --git a/client/src/components/HubRow.jsx b/client/src/components/HubRow.jsx
deleted file mode 100644
index 80c5427..0000000
--- a/client/src/components/HubRow.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-export default function HubRow() {
- return (
-
-
-
- )
-}
diff --git a/client/src/components/MainApp.jsx b/client/src/components/MainApp.jsx
deleted file mode 100644
index 2a469c9..0000000
--- a/client/src/components/MainApp.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { AppProvider } from '../context/AppContext'
-import Sidebar from './Sidebar'
-import ChatArea from './ChatArea'
-
-export default function MainApp() {
- return (
-
-
-
-
-
-
- )
-}
diff --git a/client/src/components/MessageInput.jsx b/client/src/components/MessageInput.jsx
deleted file mode 100644
index 0eb2703..0000000
--- a/client/src/components/MessageInput.jsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import { useState, useRef } from 'react'
-import { useApp } from '../context/AppContext'
-
-function fmtSize(bytes) {
- if (bytes < 1024) return `${bytes} B`
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
- return `${(bytes / 1024 / 1024).toFixed(1)} MB`
-}
-
-export default function MessageInput({ pendingFile, setPendingFile }) {
- const { state, sendMessage } = useApp()
- const [text, setText] = useState('')
- const [busy, setBusy] = useState(false)
- const [error, setError] = useState('')
- const textareaRef = useRef(null)
- const fileInputRef = useRef(null)
-
- async function handleSend() {
- const trimmed = text.trim()
- if ((!trimmed && !pendingFile) || !state.selectedId || busy) return
- const file = pendingFile
- setError('')
- setText('')
- setPendingFile(null)
- setBusy(true)
- try {
- await sendMessage(state.selectedId, trimmed, file)
- } catch (err) {
- setText(trimmed)
- setPendingFile(file)
- setError(err.message ?? String(err))
- } finally {
- setBusy(false)
- textareaRef.current?.focus()
- }
- }
-
- function onKeyDown(e) {
- if (e.key === 'Enter' && !e.shiftKey) {
- e.preventDefault()
- handleSend()
- }
- }
-
- if (!state.selectedId) return null
-
- const canSend = !busy && (text.trim() || pendingFile)
-
- return (
-
- {pendingFile && (
-
- 📎
- {pendingFile.name}
- {fmtSize(pendingFile.size)}
-
-
- )}
-
-
- {
- const f = e.target.files?.[0]
- if (f) setPendingFile(f)
- e.target.value = ''
- }}
- />
-
-
-
- {error && (
-
{error}
- )}
-
- )
-}
diff --git a/client/src/components/MessageItem.jsx b/client/src/components/MessageItem.jsx
deleted file mode 100644
index c1c1a1f..0000000
--- a/client/src/components/MessageItem.jsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import { useEffect, useState } from 'react'
-import { useApp } from '../context/AppContext'
-import { apiFetch } from '../api/http'
-import { colorToCss } from '../utils/color'
-
-const IMAGE_EXT = /\.(png|jpe?g|gif|webp|bmp)$/i
-
-function formatTime(iso) {
- const d = new Date(iso)
- return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
-}
-
-function fileNameFromKey(key) {
- return key.split('/').pop() || key
-}
-
-export default function MessageItem({ msg, showHeader }) {
- const { state, userId } = useApp()
- const isMe = msg.sender === userId
- const sender = isMe ? state.currentUser : state.userMap[msg.sender]
- const [downloading, setDownloading] = useState(false)
- const isImage = !!msg.attachedFile && IMAGE_EXT.test(msg.attachedFile)
- const [imgUrl, setImgUrl] = useState(null)
-
- useEffect(() => {
- if (!isImage) return
- let cancelled = false
- apiFetch('GET', '/file', { query: { key: msg.attachedFile, connectionid: msg.receiver } })
- .then(meta => { if (!cancelled && meta?.url) setImgUrl(meta.url) })
- .catch(err => console.error('[MessageItem] preview failed', err))
- return () => { cancelled = true }
- }, [isImage, msg.attachedFile, msg.receiver])
-
- async function openAttachment() {
- if (downloading) return
- setDownloading(true)
- try {
- const meta = await apiFetch('GET', '/file', {
- query: { key: msg.attachedFile, connectionid: msg.receiver },
- })
- if (meta?.url) window.open(meta.url, '_blank', 'noopener')
- } catch (err) {
- console.error('[MessageItem] download failed', err)
- } finally {
- setDownloading(false)
- }
- }
-
- return (
-
- {showHeader ? (
-
- {sender?.name?.[0]?.toUpperCase() ?? '?'}
-
- ) : (
-
- )}
-
-
- {showHeader && (
-
-
- {sender?.name ?? msg.sender.slice(0, 8)}
-
- {formatTime(msg.createdAt)}
-
- )}
- {msg.content && (
-
{msg.content}
- )}
- {msg.attachedFile && isImage && (
- imgUrl ? (
-
-
-
- ) : (
-
- Loading image…
-
- )
- )}
- {msg.attachedFile && !isImage && (
-
- )}
-
-
-
- {formatTime(msg.createdAt)}
-
-
- )
-}
diff --git a/client/src/components/MessageList.jsx b/client/src/components/MessageList.jsx
deleted file mode 100644
index 638f15e..0000000
--- a/client/src/components/MessageList.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { useEffect, useRef } from 'react'
-import { useApp } from '../context/AppContext'
-import MessageItem from './MessageItem'
-
-export default function MessageList() {
- const { state } = useApp()
- const bottomRef = useRef(null)
-
- useEffect(() => {
- bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
- }, [state.messages])
-
- return (
-
- {state.messages.map((msg, i) => {
- const prev = state.messages[i - 1]
- const showHeader = !prev || prev.sender !== msg.sender
- return
- })}
-
-
- )
-}
diff --git a/client/src/components/SettingsPage.jsx b/client/src/components/SettingsPage.jsx
deleted file mode 100644
index f35db07..0000000
--- a/client/src/components/SettingsPage.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { useState } from 'react'
-import { Link, useNavigate } from 'react-router-dom'
-import { apiFetch } from '../api/http'
-
-export default function SettingsPage() {
- const userId = localStorage.getItem('userId') ?? ''
- const [recipient, setRecipient] = useState('')
- const [status, setStatus] = useState(null)
- const [busy, setBusy] = useState(false)
- const [copied, setCopied] = useState(false)
- const navigate = useNavigate()
-
- async function copyId() {
- if (!userId) return
- try {
- await navigator.clipboard.writeText(userId)
- setCopied(true)
- setTimeout(() => setCopied(false), 1500)
- } catch {
- setStatus({ kind: 'err', text: 'Clipboard unavailable' })
- }
- }
-
- async function addConnection() {
- const id = recipient.trim()
- if (!id) return
- setBusy(true)
- setStatus(null)
- try {
- await apiFetch('GET', '/connection', { query: { recipient: id } })
- setStatus({ kind: 'ok', text: 'Connection created' })
- setRecipient('')
- } catch (err) {
- setStatus({ kind: 'err', text: err.message ?? String(err) })
- } finally {
- setBusy(false)
- }
- }
-
- function logout() {
- localStorage.removeItem('token')
- localStorage.removeItem('userId')
- navigate('/auth')
- }
-
- return (
-
-
-
- ← Back
-
-
-
-
- Your user ID
-
-
- {userId || '(missing)'}
-
-
-
- Share this with someone so they can add you.
-
-
-
-
-
- )
-}
diff --git a/client/src/components/Sidebar.jsx b/client/src/components/Sidebar.jsx
deleted file mode 100644
index 5362484..0000000
--- a/client/src/components/Sidebar.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import HubRow from './HubRow'
-import ConnectionList from './ConnectionList'
-import UserBar from './UserBar'
-
-export default function Sidebar() {
- return (
-
-
-
-
-
- )
-}
diff --git a/client/src/components/UserBar.jsx b/client/src/components/UserBar.jsx
deleted file mode 100644
index b50a0a4..0000000
--- a/client/src/components/UserBar.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Link } from 'react-router-dom'
-import { useApp } from '../context/AppContext'
-import { colorToCss } from '../utils/color'
-
-export default function UserBar() {
- const { state } = useApp()
- const user = state.currentUser
-
- return (
-
-
- {user?.name?.[0]?.toUpperCase() ?? '?'}
-
-
- {user?.name ?? '…'}
-
-
- ⚙
-
-
- )
-}
diff --git a/client/src/context/AppContext.jsx b/client/src/context/AppContext.jsx
deleted file mode 100644
index 0e6cd2f..0000000
--- a/client/src/context/AppContext.jsx
+++ /dev/null
@@ -1,243 +0,0 @@
-import { createContext, useContext, useReducer, useEffect, useRef, useCallback } from 'react'
-import { apiFetch } from '../api/http'
-import { wsConnect, wsDisconnect, wsOnEvent } from '../api/ws'
-
-const Ctx = createContext(null)
-
-const WS_AUTH = 0
-const WS_DM = 1
-const WS_CONN_CREATED = 2
-const WS_CONN_DELETED = 3
-const WS_CONN_ELEVATED = 4
-const WS_CONN_DEELEVATED = 5
-const WS_USER_PROFILE = 6
-const WS_CONN_ELEVATE_PENDING = 10
-
-const initial = {
- connections: [],
- userMap: {},
- unread: {},
- selectedId: null,
- messages: [],
- currentUser: null,
-}
-
-function reducer(state, action) {
- switch (action.type) {
- case 'SET_CONNECTIONS':
- return { ...state, connections: action.payload }
- case 'SET_USER_MAP':
- return { ...state, userMap: { ...state.userMap, ...action.payload } }
- case 'SET_UNREAD':
- return { ...state, unread: action.payload }
- case 'SET_CURRENT_USER':
- return { ...state, currentUser: action.payload }
- case 'SELECT_CONNECTION':
- return {
- ...state,
- selectedId: action.id,
- unread: { ...state.unread, [action.id]: 0 },
- }
- case 'SET_MESSAGES':
- return { ...state, messages: action.payload }
- case 'APPEND_MESSAGE':
- return { ...state, messages: [...state.messages, action.payload] }
- case 'REMOVE_MESSAGE':
- return { ...state, messages: state.messages.filter(m => m.id !== action.id) }
- case 'BUMP_UNREAD':
- return {
- ...state,
- unread: { ...state.unread, [action.id]: (state.unread[action.id] || 0) + 1 },
- }
- case 'ADD_CONNECTION':
- return { ...state, connections: [action.payload, ...state.connections] }
- case 'REMOVE_CONNECTION':
- return {
- ...state,
- connections: state.connections.filter(c => c.id !== action.id),
- selectedId: state.selectedId === action.id ? null : state.selectedId,
- messages: state.selectedId === action.id ? [] : state.messages,
- }
- case 'UPDATE_CONN_STATE':
- return {
- ...state,
- connections: state.connections.map(c =>
- c.id === action.id ? { ...c, state: action.newState } : c
- ),
- }
- case 'PATCH_CONNECTION':
- return {
- ...state,
- connections: state.connections.map(c =>
- c.id === action.id ? { ...c, ...action.changes } : c
- ),
- }
- case 'PATCH_USER':
- return {
- ...state,
- userMap: {
- ...state.userMap,
- [action.userId]: { ...state.userMap[action.userId], ...action.changes },
- },
- }
- default:
- return state
- }
-}
-
-export function AppProvider({ children }) {
- const [state, dispatch] = useReducer(reducer, initial)
- const selectedIdRef = useRef(null)
- const userId = localStorage.getItem('userId')
-
- useEffect(() => {
- selectedIdRef.current = state.selectedId
- }, [state.selectedId])
-
- useEffect(() => {
- async function init() {
- const me = await apiFetch('GET', '/user', { query: { targetid: userId } })
- dispatch({ type: 'SET_CURRENT_USER', payload: { ...me, id: userId } })
-
- const conns = (await apiFetch('GET', '/connections')) ?? []
- dispatch({ type: 'SET_CONNECTIONS', payload: conns })
-
- const otherIds = [...new Set(
- conns.map(c => c.requestorId === userId ? c.recipientId : c.requestorId)
- )]
- const entries = await Promise.all(
- otherIds.map(async id => {
- const u = await apiFetch('GET', '/user', { query: { targetid: id } })
- return [id, u]
- })
- )
- dispatch({ type: 'SET_USER_MAP', payload: Object.fromEntries(entries) })
-
- if (conns.length > 0) {
- const ids = conns.map(c => c.id).join(',')
- const counts = (await apiFetch('GET', '/connections/unreadmessages', { query: { connections: ids } })) ?? []
- const unreadMap = {}
- conns.forEach((c, i) => { unreadMap[c.id] = counts[i] || 0 })
- dispatch({ type: 'SET_UNREAD', payload: unreadMap })
- }
-
- wsOnEvent(WS_DM, (event) => {
- if (event.receiver === selectedIdRef.current) {
- dispatch({ type: 'APPEND_MESSAGE', payload: event })
- } else {
- dispatch({ type: 'BUMP_UNREAD', id: event.receiver })
- }
- })
-
- wsOnEvent(WS_CONN_CREATED, async (event) => {
- dispatch({ type: 'ADD_CONNECTION', payload: event })
- const otherId = event.requestorId === userId ? event.recipientId : event.requestorId
- const u = await apiFetch('GET', '/user', { query: { targetid: otherId } })
- dispatch({ type: 'SET_USER_MAP', payload: { [otherId]: u } })
- })
-
- wsOnEvent(WS_CONN_DELETED, (id) => {
- dispatch({ type: 'REMOVE_CONNECTION', id })
- })
-
- wsOnEvent(WS_CONN_ELEVATED, ({ id, newState }) => {
- dispatch({ type: 'UPDATE_CONN_STATE', id, newState })
- })
-
- wsOnEvent(WS_CONN_DEELEVATED, ({ id, newState }) => {
- dispatch({ type: 'UPDATE_CONN_STATE', id, newState })
- })
-
- wsOnEvent(WS_CONN_ELEVATE_PENDING, ({ id, userWantingToElevate }) => {
- dispatch({ type: 'PATCH_CONNECTION', id, changes: { userWantingToElevate } })
- })
-
- // event = { userId, profileChangeList: { pronouns?, description?, color? } }
- wsOnEvent(WS_USER_PROFILE, ({ userId: uid, profileChangeList }) => {
- dispatch({ type: 'PATCH_USER', userId: uid, changes: profileChangeList })
- })
- // types 7 (avatar) and 8 (profilebg) don't affect our color-circle display — ignore
-
- wsConnect()
- }
-
- init().catch(err => console.error('[AppContext] init failed', err))
- return () => wsDisconnect()
- }, [])
-
- const selectConnection = useCallback(async (id) => {
- dispatch({ type: 'SELECT_CONNECTION', id })
- dispatch({ type: 'SET_MESSAGES', payload: [] })
- try {
- const msgs = (await apiFetch('GET', '/connection/messages', { query: { connectionid: id } })) ?? []
- if (selectedIdRef.current === id) {
- dispatch({ type: 'SET_MESSAGES', payload: msgs })
- }
- } catch (err) {
- console.error('[AppContext] failed to load messages for', id, err)
- }
- }, [])
-
- const elevateConnection = useCallback(async (connectionId) => {
- const text = await apiFetch('POST', '/connection/elevate', { body: { connectionid: connectionId } })
- if (text === 'elevated') {
- dispatch({ type: 'UPDATE_CONN_STATE', id: connectionId, newState: 1 })
- return 'elevated'
- }
- dispatch({ type: 'PATCH_CONNECTION', id: connectionId, changes: { userWantingToElevate: userId } })
- return 'waiting'
- }, [userId])
-
- const deelevateConnection = useCallback(async (connectionId) => {
- await apiFetch('POST', '/connection/deelevate', { body: { connectionid: connectionId } })
- dispatch({ type: 'UPDATE_CONN_STATE', id: connectionId, newState: 0 })
- }, [])
-
- const deleteConnection = useCallback(async (connectionId) => {
- await apiFetch('DELETE', '/connection', { query: { connectionid: connectionId } })
- dispatch({ type: 'REMOVE_CONNECTION', id: connectionId })
- }, [])
-
- const sendMessage = useCallback(async (connectionId, content, file) => {
- let attachedFile = ''
- if (file) {
- const fd = new FormData()
- fd.append('connectionid', connectionId)
- fd.append('file', file)
- attachedFile = await apiFetch('POST', '/file', { body: fd })
- }
-
- const uid = localStorage.getItem('userId')
- const optimistic = {
- id: crypto.randomUUID(),
- content,
- attachedFile,
- createdAt: new Date().toISOString(),
- sender: uid,
- receiver: connectionId,
- }
- dispatch({ type: 'APPEND_MESSAGE', payload: optimistic })
- try {
- await apiFetch('POST', '/connection/message', {
- body: { connectionid: connectionId, msgContent: content, attachedFile },
- })
- } catch (err) {
- dispatch({ type: 'REMOVE_MESSAGE', id: optimistic.id })
- throw err
- }
- }, [])
-
- return (
-
- {children}
-
- )
-}
-
-export function useApp() {
- return useContext(Ctx)
-}
diff --git a/client/src/index.css b/client/src/index.css
deleted file mode 100644
index fbdeab4..0000000
--- a/client/src/index.css
+++ /dev/null
@@ -1,5 +0,0 @@
-@import "tailwindcss";
-
-body {
- @apply bg-gray-900 text-white;
-}
diff --git a/client/src/main.jsx b/client/src/main.jsx
deleted file mode 100644
index 3f7fc68..0000000
--- a/client/src/main.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { StrictMode } from "react"
-import { createRoot } from "react-dom/client"
-import App from "./App"
-
-createRoot(document.getElementById("root")).render(
-
-
-
-)
diff --git a/client/src/utils/color.js b/client/src/utils/color.js
deleted file mode 100644
index c8d970a..0000000
--- a/client/src/utils/color.js
+++ /dev/null
@@ -1,6 +0,0 @@
-const FALLBACK_COLOR = '#4b5563'
-
-export function colorToCss(color) {
- if (!color) return FALLBACK_COLOR
- return `rgba(${color[0]},${color[1]},${color[2]},${(color[3] ?? 255) / 255})`
-}
diff --git a/client/src/utils/connection.js b/client/src/utils/connection.js
deleted file mode 100644
index b4ef3bd..0000000
--- a/client/src/utils/connection.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const ZERO_UUID = '00000000-0000-0000-0000-000000000000'
-
-export function pendingActor(conn) {
- const u = conn?.userWantingToElevate
- return u && u !== ZERO_UUID ? u : null
-}
-
-export function connectionStatus(conn, currentUserId) {
- if (!conn) return null
- if (conn.state === 1) return { label: 'friend', cls: 'text-green-400' }
- const pending = pendingActor(conn)
- if (pending === currentUserId) return { label: 'request sent', cls: 'text-yellow-400' }
- if (pending) return { label: 'request pending', cls: 'text-blue-400' }
- return null
-}
diff --git a/client/vite.config.js b/client/vite.config.js
deleted file mode 100644
index 95c288b..0000000
--- a/client/vite.config.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { defineConfig } from 'vite'
-import react, { reactCompilerPreset } from '@vitejs/plugin-react'
-import babel from '@rolldown/plugin-babel'
-import tailwindcss from '@tailwindcss/vite'
-
-export default defineConfig({
- plugins: [
- tailwindcss(),
- react(),
- babel({ presets: [reactCompilerPreset()] })
- ],
-})
diff --git a/go-socket b/go-socket
index 76d0cd4..4d45e7c 100755
Binary files a/go-socket and b/go-socket differ
diff --git a/main.go b/main.go
index 7b07005..b39cc4d 100644
--- a/main.go
+++ b/main.go
@@ -64,7 +64,7 @@ func main() {
http.HandleFunc("GET /hub/channel/messages", withCORS(httpRequest.HandleHubChannelGetMessages))
http.HandleFunc("GET /hub/channel", withCORS(httpRequest.GetChannelData))
http.HandleFunc("GET /hubs", withCORS(httpRequest.HandleGetHubs))
- http.HandleFunc("GET /hubs/channels", withCORS(httpRequest.HandleGetChannels))
+ http.HandleFunc("GET /hub/channels", withCORS(httpRequest.HandleGetChannels))
http.HandleFunc("GET /hubs/users", withCORS(httpRequest.HandleGetHubUsers))
http.HandleFunc("GET /hubs/roles", withCORS(httpRequest.GetRoles))
http.HandleFunc("PUT /hub/join", withCORS(httpRequest.HandleHubJoin))
diff --git a/packages/httpRequest/get.go b/packages/httpRequest/get.go
index a38dd1a..f12f159 100644
--- a/packages/httpRequest/get.go
+++ b/packages/httpRequest/get.go
@@ -102,6 +102,10 @@ func getHubByIdStr(ctx context.Context, hubId string) (*types.Hub, error) {
if err != nil {
return nil, err
}
+ for _, u := range hub.Users {
+ updateChannelCacheForSpecUser(u, hub)
+ }
+ cache.SaveHub(hub)
}
return hub, nil
diff --git a/test-client/index.html b/test-client/index.html
index b4cbf59..4bcee91 100644
--- a/test-client/index.html
+++ b/test-client/index.html
@@ -48,7 +48,7 @@
-
+
@@ -609,7 +609,7 @@
'get-hubs': { method:'GET', path:'/hubs', title:'GET /hubs — get own hubs', fields:[{id:'gh-token',dest:'header',name:'token'}] },
'get-hub-data': { method:'GET', path:'/hub', title:'GET /hub — get hub data', fields:[{id:'ghd-token',dest:'header',name:'token'},{id:'ghd-hubid',dest:'header',name:'hub_id'}] },
'get-hub-channel-data': { method:'GET', path:'/hub/channel', title:'GET /hub/channel — get channel data', fields:[{id:'ghcd-token',dest:'header',name:'token'},{id:'ghcd-hubid',dest:'header',name:'hub_id'},{id:'ghcd-channelid',dest:'query',name:'channel_id'}] },
- 'get-hub-channels': { method:'GET', path:'/hubs/channels', title:'GET /hubs/channels — get hub channels', fields:[{id:'ghc-token',dest:'header',name:'token'},{id:'ghc-hubid',dest:'header',name:'hub_id'}] },
+ 'get-hub-channels': { method:'GET', path:'/hub/channels', title:'GET /hub/channels — get hub channels', fields:[{id:'ghc-token',dest:'header',name:'token'},{id:'ghc-hubid',dest:'header',name:'hub_id'}] },
'get-hub-users': { method:'GET', path:'/hubs/users', title:'GET /hubs/users — get hub users (excludes self)', fields:[{id:'ghu-token',dest:'header',name:'token'},{id:'ghu-hubid',dest:'header',name:'hub_id'}] },
'get-hub-roles': { method:'GET', path:'/hubs/roles', title:'GET /hubs/roles — get hub roles', fields:[{id:'ghr-token',dest:'header',name:'token'},{id:'ghr-hubid',dest:'header',name:'hub_id'}] },
'get-users': { method:'GET', path:'/users', title:'GET /users — get multiple users by IDs', fields:[{id:'gus-token',dest:'header',name:'token'},{id:'gus-targetids',dest:'query',name:'target_ids'}] },