diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example new file mode 100644 index 0000000..ff04daf --- /dev/null +++ b/apps/frontend/.env.example @@ -0,0 +1,4 @@ +# Backend API base URL (no trailing slash, no /api suffix) +# Dev local: http://localhost:3000 +# Prod VPS: https://api.ti-pote.example.com +VITE_API_URL=http://localhost:3000 diff --git a/apps/frontend/.gitignore b/apps/frontend/.gitignore new file mode 100644 index 0000000..fdaeba9 --- /dev/null +++ b/apps/frontend/.gitignore @@ -0,0 +1,39 @@ +# Dependencies +node_modules/ +.pnp +.pnp.js + +# Build output +dist/ +dist-ssr/ +build/ +*.local + +# Vite +.vite/ + +# Env +.env +.env.local +.env.*.local + +# IDE +.vscode/* +!.vscode/extensions.json +.idea/ +*.swp +*.swo +.DS_Store + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Tauri (Rust build artifacts) +src-tauri/target/ +src-tauri/Cargo.lock +src-tauri/gen/schemas/ +src-tauri/WixTools/ diff --git a/apps/frontend/README.md b/apps/frontend/README.md new file mode 100644 index 0000000..f81119c --- /dev/null +++ b/apps/frontend/README.md @@ -0,0 +1,68 @@ +# @ti-pote/frontend + +Desktop companion app for Ti-Pote. **Vite + React + TypeScript + Tailwind**, +wrappable as a native desktop app with **Tauri v2**. + +## Features + +- Auth: register / login / auto refresh-token rotation +- Session persistence (Tauri Store plugin on desktop, localStorage in browser) +- Dashboard: list of associated robots (`GET /api/devices`) +- Robot pairing: 6-digit code screen wired to `POST /api/pairing/confirm` + +## Quick start (web dev) + +```bash +cd apps/frontend +cp .env.example .env # point VITE_API_URL to your backend +pnpm install +pnpm dev # http://localhost:1420 +``` + +## Desktop build (Tauri v2) + +Prerequisites: Rust toolchain (`rustup`) and the +[Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for your OS. + +```bash +# First time only: generate the bundle icons from any source PNG +pnpm tauri icon path/to/logo.png + +# Dev (hot reload + native window) +pnpm tauri dev + +# Production bundle (.dmg / .app on macOS, .msi on Windows, .deb/.AppImage on Linux) +pnpm tauri build +``` + +## Project layout + +``` +apps/frontend/ +├── src/ +│ ├── components/ Button / Input / Card / ProtectedRoute +│ ├── context/ AuthContext (React) +│ ├── lib/ +│ │ ├── api.ts fetch wrapper + typed endpoints + auto-refresh +│ │ └── storage.ts Tauri Store ↔ localStorage fallback +│ ├── pages/ Login / Register / Dashboard / PairRobot +│ ├── styles/ Tailwind entry +│ ├── App.tsx Router +│ └── main.tsx Entry point +└── src-tauri/ Tauri v2 Rust wrapper + ├── Cargo.toml + ├── tauri.conf.json + ├── capabilities/ + └── src/{main.rs,lib.rs} +``` + +## Backend API used + +| Flow | Endpoint | Notes | +| -------- | ---------------------------- | ---------------------------------- | +| Register | `POST /api/auth/register` | Creates user + home | +| Login | `POST /api/auth/login` | | +| Refresh | `POST /api/auth/refresh` | Called transparently on 401 | +| Me | `GET /api/auth/me` | | +| Devices | `GET /api/devices` | Dashboard | +| Pair | `POST /api/pairing/confirm` | `{ code }` — 6-digit from robot UI | diff --git a/apps/frontend/index.html b/apps/frontend/index.html new file mode 100644 index 0000000..e306f6d --- /dev/null +++ b/apps/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + Ti-Pote + + +
+ + + diff --git a/apps/frontend/package.json b/apps/frontend/package.json new file mode 100644 index 0000000..3249f76 --- /dev/null +++ b/apps/frontend/package.json @@ -0,0 +1,32 @@ +{ + "name": "@ti-pote/frontend", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview", + "lint": "eslint src --ext ts,tsx --max-warnings 0", + "tauri": "tauri" + }, + "dependencies": { + "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-store": "^2.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.0", + "zustand": "^4.5.5" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.0.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10", + "typescript": "^5.5.4", + "vite": "^5.4.2" + } +} diff --git a/apps/frontend/postcss.config.js b/apps/frontend/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/apps/frontend/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/apps/frontend/src-tauri/.gitignore b/apps/frontend/src-tauri/.gitignore new file mode 100644 index 0000000..1b03424 --- /dev/null +++ b/apps/frontend/src-tauri/.gitignore @@ -0,0 +1,6 @@ +# Generated by Cargo +target/ +Cargo.lock + +# Generated by Tauri +gen/schemas/ diff --git a/apps/frontend/src-tauri/Cargo.toml b/apps/frontend/src-tauri/Cargo.toml new file mode 100644 index 0000000..9650bbf --- /dev/null +++ b/apps/frontend/src-tauri/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "ti-pote-desktop" +version = "0.0.1" +description = "Ti-Pote desktop companion app" +authors = ["Arthur"] +edition = "2021" +rust-version = "1.77" + +[lib] +name = "ti_pote_desktop_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-store = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[features] +# This feature is used for production builds or when a dev server is not specified, +# DO NOT REMOVE!! +custom-protocol = ["tauri/custom-protocol"] diff --git a/apps/frontend/src-tauri/build.rs b/apps/frontend/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/apps/frontend/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/apps/frontend/src-tauri/capabilities/default.json b/apps/frontend/src-tauri/capabilities/default.json new file mode 100644 index 0000000..b9fc682 --- /dev/null +++ b/apps/frontend/src-tauri/capabilities/default.json @@ -0,0 +1,10 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Default permissions for the main window", + "windows": ["main"], + "permissions": [ + "core:default", + "store:default" + ] +} diff --git a/apps/frontend/src-tauri/icons/128x128.png b/apps/frontend/src-tauri/icons/128x128.png new file mode 100644 index 0000000..53606db Binary files /dev/null and b/apps/frontend/src-tauri/icons/128x128.png differ diff --git a/apps/frontend/src-tauri/icons/128x128@2x.png b/apps/frontend/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..3a8827f Binary files /dev/null and b/apps/frontend/src-tauri/icons/128x128@2x.png differ diff --git a/apps/frontend/src-tauri/icons/32x32.png b/apps/frontend/src-tauri/icons/32x32.png new file mode 100644 index 0000000..ab7f0d8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/32x32.png differ diff --git a/apps/frontend/src-tauri/icons/64x64.png b/apps/frontend/src-tauri/icons/64x64.png new file mode 100644 index 0000000..8858528 Binary files /dev/null and b/apps/frontend/src-tauri/icons/64x64.png differ diff --git a/apps/frontend/src-tauri/icons/Square107x107Logo.png b/apps/frontend/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..ba34e79 Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square107x107Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square142x142Logo.png b/apps/frontend/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..c0636c8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square142x142Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square150x150Logo.png b/apps/frontend/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..75394d1 Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square150x150Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square284x284Logo.png b/apps/frontend/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..a0dcb03 Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square284x284Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square30x30Logo.png b/apps/frontend/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..7646530 Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square30x30Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square310x310Logo.png b/apps/frontend/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..af294f6 Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square310x310Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square44x44Logo.png b/apps/frontend/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..ae45b6f Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square44x44Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square71x71Logo.png b/apps/frontend/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..c90805d Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square71x71Logo.png differ diff --git a/apps/frontend/src-tauri/icons/Square89x89Logo.png b/apps/frontend/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..8b3d51b Binary files /dev/null and b/apps/frontend/src-tauri/icons/Square89x89Logo.png differ diff --git a/apps/frontend/src-tauri/icons/StoreLogo.png b/apps/frontend/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..55d6d54 Binary files /dev/null and b/apps/frontend/src-tauri/icons/StoreLogo.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml b/apps/frontend/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..2ffbf24 --- /dev/null +++ b/apps/frontend/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..3e7b56b Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..40df639 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..8dd9584 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..bf35071 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..918e3a7 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..2191b62 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..5096c30 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..7ee84f7 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b9c87bb Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..962b36e Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..e9a0fce Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..ec00bd9 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..5cd79a7 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..238cfa2 Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..4ba62fc Binary files /dev/null and b/apps/frontend/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/apps/frontend/src-tauri/icons/android/values/ic_launcher_background.xml b/apps/frontend/src-tauri/icons/android/values/ic_launcher_background.xml new file mode 100644 index 0000000..ea9c223 --- /dev/null +++ b/apps/frontend/src-tauri/icons/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/apps/frontend/src-tauri/icons/icon.icns b/apps/frontend/src-tauri/icons/icon.icns new file mode 100644 index 0000000..c369568 Binary files /dev/null and b/apps/frontend/src-tauri/icons/icon.icns differ diff --git a/apps/frontend/src-tauri/icons/icon.ico b/apps/frontend/src-tauri/icons/icon.ico new file mode 100644 index 0000000..e30cc8e Binary files /dev/null and b/apps/frontend/src-tauri/icons/icon.ico differ diff --git a/apps/frontend/src-tauri/icons/icon.png b/apps/frontend/src-tauri/icons/icon.png new file mode 100644 index 0000000..38ac00d Binary files /dev/null and b/apps/frontend/src-tauri/icons/icon.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@1x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000..aa597d2 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@1x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000..7471fe8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@2x-1.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000..7471fe8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@2x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@3x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000..77822c2 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-20x20@3x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@1x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000..ae51c15 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@1x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000..8c3d4c8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@2x-1.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@2x.png new file mode 100644 index 0000000..8c3d4c8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@2x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@3x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@3x.png new file mode 100644 index 0000000..19c3dd7 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-29x29@3x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@1x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000..7471fe8 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@1x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000..019101a Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@2x-1.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@2x.png new file mode 100644 index 0000000..019101a Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@2x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@3x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@3x.png new file mode 100644 index 0000000..3e74ee7 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-40x40@3x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-512@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-512@2x.png new file mode 100644 index 0000000..f43db73 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-512@2x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-60x60@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000..3e74ee7 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-60x60@2x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-60x60@3x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000..2b3351e Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-60x60@3x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-76x76@1x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000..6926f2e Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-76x76@1x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-76x76@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000..88956f3 Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-76x76@2x.png differ diff --git a/apps/frontend/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/apps/frontend/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000..eb9166a Binary files /dev/null and b/apps/frontend/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/apps/frontend/src-tauri/src/lib.rs b/apps/frontend/src-tauri/src/lib.rs new file mode 100644 index 0000000..de33c66 --- /dev/null +++ b/apps/frontend/src-tauri/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_store::Builder::new().build()) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/apps/frontend/src-tauri/src/main.rs b/apps/frontend/src-tauri/src/main.rs new file mode 100644 index 0000000..b6a1e01 --- /dev/null +++ b/apps/frontend/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + ti_pote_desktop_lib::run() +} diff --git a/apps/frontend/src-tauri/tauri.conf.json b/apps/frontend/src-tauri/tauri.conf.json new file mode 100644 index 0000000..db4d753 --- /dev/null +++ b/apps/frontend/src-tauri/tauri.conf.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "Ti-Pote", + "version": "0.0.1", + "identifier": "com.tipote.desktop", + "build": { + "beforeDevCommand": "pnpm dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "pnpm build", + "frontendDist": "../dist" + }, + "app": { + "windows": [ + { + "title": "Ti-Pote", + "width": 1100, + "height": 760, + "minWidth": 900, + "minHeight": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + }, + "plugins": {} +} diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx new file mode 100644 index 0000000..7737f29 --- /dev/null +++ b/apps/frontend/src/App.tsx @@ -0,0 +1,52 @@ +import { Navigate, Route, Routes } from 'react-router-dom'; +import { ProtectedRoute } from './components/ProtectedRoute'; +import { useAuth } from './context/AuthContext'; +import { DashboardPage } from './pages/DashboardPage'; +import { LoginPage } from './pages/LoginPage'; +import { PairRobotPage } from './pages/PairRobotPage'; +import { RegisterPage } from './pages/RegisterPage'; + +/** + * Router. + * + * - Public routes (login/register) auto-redirect to "/" when the user + * is already authenticated — avoids the annoying loop where a logged-in + * user clicks back and lands on a login form. + * - Protected routes are gated by . + */ +export function App() { + const { status } = useAuth(); + const authed = status === 'authenticated'; + + return ( + + : } + /> + : } + /> + + + + + } + /> + + + + } + /> + + } /> + + ); +} diff --git a/apps/frontend/src/components/ProtectedRoute.tsx b/apps/frontend/src/components/ProtectedRoute.tsx new file mode 100644 index 0000000..90bf2d0 --- /dev/null +++ b/apps/frontend/src/components/ProtectedRoute.tsx @@ -0,0 +1,31 @@ +import type { ReactNode } from 'react'; +import { Navigate, useLocation } from 'react-router-dom'; +import { useAuth } from '../context/AuthContext'; + +/** + * Gate a subtree behind an authenticated user. + * + * - While the auth state is still bootstrapping (refreshing the session + * from storage), render a neutral splash. + * - If the user is unauthenticated, redirect to /login while keeping + * the original destination in location state so we can bounce back + * after login. + */ +export function ProtectedRoute({ children }: { children: ReactNode }) { + const { status } = useAuth(); + const location = useLocation(); + + if (status === 'loading') { + return ( +
+
+
+ ); + } + + if (status === 'unauthenticated') { + return ; + } + + return <>{children}; +} diff --git a/apps/frontend/src/components/ui.tsx b/apps/frontend/src/components/ui.tsx new file mode 100644 index 0000000..2ec1868 --- /dev/null +++ b/apps/frontend/src/components/ui.tsx @@ -0,0 +1,148 @@ +import type { ButtonHTMLAttributes, InputHTMLAttributes, ReactNode } from 'react'; + +// ─── Button ───────────────────────────────────────────────────────── + +type Variant = 'primary' | 'secondary' | 'ghost' | 'danger'; + +interface ButtonProps extends ButtonHTMLAttributes { + variant?: Variant; + loading?: boolean; +} + +const VARIANT_CLASSES: Record = { + primary: + 'bg-brand-500 hover:bg-brand-400 active:bg-brand-600 text-white shadow-lg shadow-brand-500/30', + secondary: 'bg-slate-800 hover:bg-slate-700 text-slate-100 border border-slate-700', + ghost: 'bg-transparent hover:bg-slate-800/60 text-slate-300', + danger: 'bg-red-600 hover:bg-red-500 text-white', +}; + +export function Button({ + variant = 'primary', + loading = false, + disabled, + className = '', + children, + ...rest +}: ButtonProps) { + return ( + + ); +} + +// ─── Input ────────────────────────────────────────────────────────── + +interface InputProps extends InputHTMLAttributes { + label?: string; + error?: string | null; +} + +export function Input({ label, error, className = '', id, ...rest }: InputProps) { + const inputId = id || rest.name; + return ( +
+ {label && ( + + )} + + {error &&

{error}

} +
+ ); +} + +// ─── Card ─────────────────────────────────────────────────────────── + +export function Card({ + children, + className = '', +}: { + children: ReactNode; + className?: string; +}) { + return ( +
+ {children} +
+ ); +} + +// ─── StatusBadge ─────────────────────────────────────────────────── + +export function StatusBadge({ status }: { status: 'online' | 'offline' | 'updating' }) { + const styles = { + online: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/30', + offline: 'bg-slate-500/10 text-slate-400 border-slate-500/30', + updating: 'bg-amber-500/10 text-amber-400 border-amber-500/30', + }[status]; + + const dot = { + online: 'bg-emerald-400 shadow-emerald-400/60', + offline: 'bg-slate-500', + updating: 'bg-amber-400 shadow-amber-400/60 animate-pulse', + }[status]; + + return ( + + + {status} + + ); +} diff --git a/apps/frontend/src/context/AuthContext.tsx b/apps/frontend/src/context/AuthContext.tsx new file mode 100644 index 0000000..6874673 --- /dev/null +++ b/apps/frontend/src/context/AuthContext.tsx @@ -0,0 +1,98 @@ +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useState, + type ReactNode, +} from 'react'; +import { + api, + hasStoredSession, + type LoginInput, + type Me, + type RegisterInput, +} from '../lib/api'; + +type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated'; + +interface AuthContextValue { + status: AuthStatus; + user: Me | null; + login: (input: LoginInput) => Promise; + register: (input: RegisterInput) => Promise; + logout: () => Promise; + refreshMe: () => Promise; +} + +const AuthContext = createContext(null); + +export function AuthProvider({ children }: { children: ReactNode }) { + const [status, setStatus] = useState('loading'); + const [user, setUser] = useState(null); + + // Bootstrap: if we have a refresh token on disk, try /auth/me + useEffect(() => { + let cancelled = false; + + (async () => { + if (!(await hasStoredSession())) { + if (!cancelled) setStatus('unauthenticated'); + return; + } + try { + const me = await api.me(); + if (cancelled) return; + setUser(me); + setStatus('authenticated'); + } catch { + if (cancelled) return; + setUser(null); + setStatus('unauthenticated'); + } + })(); + + return () => { + cancelled = true; + }; + }, []); + + const login = useCallback(async (input: LoginInput) => { + await api.login(input); + const me = await api.me(); + setUser(me); + setStatus('authenticated'); + }, []); + + const register = useCallback(async (input: RegisterInput) => { + await api.register(input); + const me = await api.me(); + setUser(me); + setStatus('authenticated'); + }, []); + + const logout = useCallback(async () => { + await api.logout(); + setUser(null); + setStatus('unauthenticated'); + }, []); + + const refreshMe = useCallback(async () => { + const me = await api.me(); + setUser(me); + }, []); + + const value = useMemo( + () => ({ status, user, login, register, logout, refreshMe }), + [status, user, login, register, logout, refreshMe], + ); + + return {children}; +} + +export function useAuth(): AuthContextValue { + const ctx = useContext(AuthContext); + if (!ctx) throw new Error('useAuth must be used inside '); + return ctx; +} diff --git a/apps/frontend/src/lib/api.ts b/apps/frontend/src/lib/api.ts new file mode 100644 index 0000000..d6d893d --- /dev/null +++ b/apps/frontend/src/lib/api.ts @@ -0,0 +1,233 @@ +/** + * Thin typed wrapper around fetch with: + * - base URL from VITE_API_URL (default http://localhost:3000) + * - automatic `Authorization: Bearer ` injection + * - transparent refresh-token rotation on 401 + * - typed error class + * + * Token persistence is delegated to `lib/storage.ts` (Tauri store in + * desktop builds, localStorage in pure browser dev). + */ + +import { storage } from './storage'; + +const BASE_URL = + (import.meta.env.VITE_API_URL as string | undefined)?.replace(/\/$/, '') || + 'http://localhost:3000'; + +const API_PREFIX = '/api'; + +const ACCESS_KEY = 'auth.accessToken'; +const REFRESH_KEY = 'auth.refreshToken'; + +// ─── Types ────────────────────────────────────────────────────────── + +export interface Tokens { + accessToken: string; + refreshToken: string; +} + +export interface Me { + id: string; + email: string; + homeId: string; + type: 'user'; +} + +export interface RegisterInput { + email: string; + password: string; + displayName: string; + homeName: string; +} + +export interface LoginInput { + email: string; + password: string; +} + +export interface DeviceSummary { + id: string; + homeId: string; + name: string; + status: 'online' | 'offline' | 'updating'; + firmwareVersion: string | null; + lastSeenAt: string | null; + createdAt: string; + updatedAt: string; +} + +export interface PairingConfirmResult { + deviceId: string; + deviceName: string; +} + +// ─── Error ────────────────────────────────────────────────────────── + +export class ApiError extends Error { + constructor( + public readonly status: number, + message: string, + public readonly body?: unknown, + ) { + super(message); + this.name = 'ApiError'; + } +} + +// ─── Token helpers ────────────────────────────────────────────────── + +async function getAccessToken(): Promise { + return storage.get(ACCESS_KEY); +} + +async function getRefreshToken(): Promise { + return storage.get(REFRESH_KEY); +} + +export async function saveTokens(tokens: Tokens): Promise { + await storage.set(ACCESS_KEY, tokens.accessToken); + await storage.set(REFRESH_KEY, tokens.refreshToken); +} + +export async function clearTokens(): Promise { + await storage.delete(ACCESS_KEY); + await storage.delete(REFRESH_KEY); +} + +export async function hasStoredSession(): Promise { + const [a, r] = await Promise.all([getAccessToken(), getRefreshToken()]); + return Boolean(a && r); +} + +// ─── Core fetch with refresh-on-401 ───────────────────────────────── + +interface RequestOptions { + method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; + body?: unknown; + auth?: boolean; // default true + // Internal: prevents infinite refresh loops + _retried?: boolean; +} + +async function request(path: string, opts: RequestOptions = {}): Promise { + const { method = 'GET', body, auth = true, _retried = false } = opts; + + const headers: Record = { + 'Content-Type': 'application/json', + Accept: 'application/json', + }; + + if (auth) { + const token = await getAccessToken(); + if (token) headers.Authorization = `Bearer ${token}`; + } + + const res = await fetch(`${BASE_URL}${API_PREFIX}${path}`, { + method, + headers, + body: body !== undefined ? JSON.stringify(body) : undefined, + }); + + // Attempt transparent refresh on 401 (once) + if (res.status === 401 && auth && !_retried) { + const refreshed = await tryRefresh(); + if (refreshed) { + return request(path, { ...opts, _retried: true }); + } + await clearTokens(); + } + + const isJson = res.headers.get('content-type')?.includes('application/json'); + const payload: unknown = isJson ? await res.json().catch(() => null) : null; + + if (!res.ok) { + const message = + (payload && + typeof payload === 'object' && + 'message' in payload && + String((payload as { message: unknown }).message)) || + res.statusText || + `HTTP ${res.status}`; + throw new ApiError(res.status, message, payload); + } + + return payload as T; +} + +let refreshInFlight: Promise | null = null; + +async function tryRefresh(): Promise { + if (refreshInFlight) return refreshInFlight; + + refreshInFlight = (async () => { + const refreshToken = await getRefreshToken(); + if (!refreshToken) return false; + try { + const res = await fetch(`${BASE_URL}${API_PREFIX}/auth/refresh`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ refreshToken }), + }); + if (!res.ok) return false; + const tokens = (await res.json()) as Tokens; + await saveTokens(tokens); + return true; + } catch { + return false; + } finally { + // Release slot after microtask so concurrent callers can await + setTimeout(() => { + refreshInFlight = null; + }, 0); + } + })(); + + return refreshInFlight; +} + +// ─── Typed endpoint wrappers ──────────────────────────────────────── + +export const api = { + // Auth + async register(input: RegisterInput): Promise { + const tokens = await request('/auth/register', { + method: 'POST', + body: input, + auth: false, + }); + await saveTokens(tokens); + return tokens; + }, + + async login(input: LoginInput): Promise { + const tokens = await request('/auth/login', { + method: 'POST', + body: input, + auth: false, + }); + await saveTokens(tokens); + return tokens; + }, + + async me(): Promise { + return request('/auth/me'); + }, + + async logout(): Promise { + await clearTokens(); + }, + + // Devices + async listDevices(): Promise { + return request('/devices'); + }, + + // Pairing + async confirmPairing(code: string): Promise { + return request('/pairing/confirm', { + method: 'POST', + body: { code }, + }); + }, +}; diff --git a/apps/frontend/src/lib/storage.ts b/apps/frontend/src/lib/storage.ts new file mode 100644 index 0000000..d6ab005 --- /dev/null +++ b/apps/frontend/src/lib/storage.ts @@ -0,0 +1,100 @@ +/** + * Persistent key-value storage. + * + * In a Tauri desktop build we prefer the `@tauri-apps/plugin-store` plugin + * (encrypted, per-app location). In a plain browser dev build we fall back + * to `localStorage`. The same async API is exposed in both cases so callers + * never care which backend they are talking to. + */ + +type StorageBackend = { + get(key: string): Promise; + set(key: string, value: unknown): Promise; + delete(key: string): Promise; + clear(): Promise; +}; + +let backendPromise: Promise | null = null; + +function isTauri(): boolean { + return ( + typeof window !== 'undefined' && + // Tauri v2 sets these globals on window at runtime + ('__TAURI_INTERNALS__' in window || '__TAURI__' in window) + ); +} + +async function createBackend(): Promise { + if (isTauri()) { + try { + const { Store } = await import('@tauri-apps/plugin-store'); + const store = await Store.load('ti-pote.json'); + return { + async get(key: string) { + const value = await store.get(key); + return value ?? null; + }, + async set(key, value) { + await store.set(key, value); + await store.save(); + }, + async delete(key) { + await store.delete(key); + await store.save(); + }, + async clear() { + await store.clear(); + await store.save(); + }, + }; + } catch (err) { + console.warn('[storage] Tauri store unavailable, falling back to localStorage', err); + } + } + + // Browser fallback + return { + async get(key: string) { + const raw = localStorage.getItem(key); + if (raw == null) return null; + try { + return JSON.parse(raw) as T; + } catch { + return null; + } + }, + async set(key, value) { + localStorage.setItem(key, JSON.stringify(value)); + }, + async delete(key) { + localStorage.removeItem(key); + }, + async clear() { + localStorage.clear(); + }, + }; +} + +function getBackend(): Promise { + if (!backendPromise) backendPromise = createBackend(); + return backendPromise; +} + +export const storage = { + async get(key: string): Promise { + const b = await getBackend(); + return b.get(key); + }, + async set(key: string, value: unknown): Promise { + const b = await getBackend(); + return b.set(key, value); + }, + async delete(key: string): Promise { + const b = await getBackend(); + return b.delete(key); + }, + async clear(): Promise { + const b = await getBackend(); + return b.clear(); + }, +}; diff --git a/apps/frontend/src/main.tsx b/apps/frontend/src/main.tsx new file mode 100644 index 0000000..3359db9 --- /dev/null +++ b/apps/frontend/src/main.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { BrowserRouter } from 'react-router-dom'; +import { App } from './App'; +import { AuthProvider } from './context/AuthContext'; +import './styles/index.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + + + , +); diff --git a/apps/frontend/src/pages/DashboardPage.tsx b/apps/frontend/src/pages/DashboardPage.tsx new file mode 100644 index 0000000..67acaf8 --- /dev/null +++ b/apps/frontend/src/pages/DashboardPage.tsx @@ -0,0 +1,118 @@ +import { useEffect, useState } from 'react'; +import { Link } from 'react-router-dom'; +import { Button, Card, StatusBadge } from '../components/ui'; +import { useAuth } from '../context/AuthContext'; +import { api, ApiError, type DeviceSummary } from '../lib/api'; + +export function DashboardPage() { + const { user, logout } = useAuth(); + const [devices, setDevices] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + async function fetchDevices() { + setLoading(true); + setError(null); + try { + const list = await api.listDevices(); + setDevices(list); + } catch (err) { + setError(err instanceof ApiError ? err.message : 'Erreur réseau'); + setDevices([]); + } finally { + setLoading(false); + } + } + + useEffect(() => { + void fetchDevices(); + }, []); + + return ( +
+ {/* ─ Header ─ */} +
+
+

Tableau de bord

+

+ Bonjour{user ? `, ${user.email.split('@')[0]}` : ''} 👋 +

+
+ +
+ + {/* ─ Actions ─ */} +
+

Tes robots

+
+ + + + +
+
+ + {/* ─ Device list ─ */} + {loading && ( + Chargement… + )} + + {!loading && error && ( + + {error} + + )} + + {!loading && !error && devices && devices.length === 0 && ( + +
+ 🤖 +
+
+

Aucun robot associé

+

+ Allume ton Ti-Pote puis associe-le avec le code qui s'affichera. +

+
+ + + +
+ )} + + {!loading && !error && devices && devices.length > 0 && ( +
+ {devices.map((d) => ( + +
+
+

{d.name}

+

+ {d.id} +

+
+ +
+
+
+
Firmware :
+
{d.firmwareVersion || '—'}
+
+
+
Vu pour la dernière fois :
+
+ {d.lastSeenAt ? new Date(d.lastSeenAt).toLocaleString() : 'jamais'} +
+
+
+
+ ))} +
+ )} +
+ ); +} diff --git a/apps/frontend/src/pages/LoginPage.tsx b/apps/frontend/src/pages/LoginPage.tsx new file mode 100644 index 0000000..850439f --- /dev/null +++ b/apps/frontend/src/pages/LoginPage.tsx @@ -0,0 +1,97 @@ +import { useState, type FormEvent } from 'react'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; +import { Button, Card, Input } from '../components/ui'; +import { useAuth } from '../context/AuthContext'; +import { ApiError } from '../lib/api'; + +interface LocationState { + from?: { pathname: string }; +} + +export function LoginPage() { + const { login } = useAuth(); + const navigate = useNavigate(); + const location = useLocation(); + const from = (location.state as LocationState | null)?.from?.pathname || '/'; + + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [submitting, setSubmitting] = useState(false); + const [error, setError] = useState(null); + + async function onSubmit(e: FormEvent) { + e.preventDefault(); + setError(null); + setSubmitting(true); + try { + await login({ email, password }); + navigate(from, { replace: true }); + } catch (err) { + if (err instanceof ApiError) { + setError( + err.status === 401 + ? 'Email ou mot de passe incorrect.' + : err.message || 'Erreur de connexion.', + ); + } else { + setError('Impossible de joindre le serveur.'); + } + } finally { + setSubmitting(false); + } + } + + return ( +
+ +
+
+ 🤖 +
+

Bon retour !

+

Connecte-toi à ton Ti-Pote

+
+ +
+ setEmail(e.target.value)} + /> + setPassword(e.target.value)} + /> + + {error && ( +
+ {error} +
+ )} + + +
+ +

+ Pas encore de compte ?{' '} + + Créer un compte + +

+
+
+ ); +} diff --git a/apps/frontend/src/pages/PairRobotPage.tsx b/apps/frontend/src/pages/PairRobotPage.tsx new file mode 100644 index 0000000..a801cd3 --- /dev/null +++ b/apps/frontend/src/pages/PairRobotPage.tsx @@ -0,0 +1,193 @@ +import { useMemo, useRef, useState, type ClipboardEvent, type KeyboardEvent } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { Button, Card } from '../components/ui'; +import { api, ApiError } from '../lib/api'; + +const CODE_LENGTH = 6; + +/** + * Pairing flow (user side). + * + * The robot-client calls POST /pairing/request on first boot, displays a + * 6-digit code, and polls GET /pairing/status/:requestId until it sees a + * `confirmed` response. + * + * Here we just collect the 6 digits from the user and POST them to + * /pairing/confirm — the backend then flips the pairing request to + * confirmed and the robot picks up its device credentials on its next poll. + */ +export function PairRobotPage() { + const navigate = useNavigate(); + const [digits, setDigits] = useState(() => + Array.from({ length: CODE_LENGTH }, () => ''), + ); + const [submitting, setSubmitting] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState<{ deviceId: string; deviceName: string } | null>( + null, + ); + const inputsRef = useRef<(HTMLInputElement | null)[]>([]); + + const code = useMemo(() => digits.join(''), [digits]); + const isComplete = code.length === CODE_LENGTH && digits.every((d) => /\d/.test(d)); + + function setDigitAt(index: number, value: string) { + const cleaned = value.replace(/\D/g, '').slice(0, 1); + setDigits((prev) => { + const next = [...prev]; + next[index] = cleaned; + return next; + }); + if (cleaned && index < CODE_LENGTH - 1) { + inputsRef.current[index + 1]?.focus(); + } + } + + function onKeyDown(index: number, e: KeyboardEvent) { + if (e.key === 'Backspace' && !digits[index] && index > 0) { + inputsRef.current[index - 1]?.focus(); + } else if (e.key === 'ArrowLeft' && index > 0) { + inputsRef.current[index - 1]?.focus(); + } else if (e.key === 'ArrowRight' && index < CODE_LENGTH - 1) { + inputsRef.current[index + 1]?.focus(); + } else if (e.key === 'Enter' && isComplete) { + void submit(); + } + } + + function onPaste(e: ClipboardEvent) { + const pasted = e.clipboardData.getData('text').replace(/\D/g, '').slice(0, CODE_LENGTH); + if (!pasted) return; + e.preventDefault(); + const next = Array.from({ length: CODE_LENGTH }, (_, i) => pasted[i] ?? ''); + setDigits(next); + const lastFilled = Math.min(pasted.length, CODE_LENGTH) - 1; + inputsRef.current[lastFilled < 0 ? 0 : lastFilled]?.focus(); + } + + async function submit() { + setError(null); + setSubmitting(true); + try { + const result = await api.confirmPairing(code); + setSuccess(result); + } catch (err) { + if (err instanceof ApiError) { + if (err.status === 400) { + setError('Code invalide ou expiré. Vérifie le code affiché sur le robot.'); + } else { + setError(err.message || "Erreur lors de l'association."); + } + } else { + setError('Impossible de joindre le serveur.'); + } + } finally { + setSubmitting(false); + } + } + + // ─── Success screen ───────────────────────────────────────────── + if (success) { + return ( +
+ +
+ ✅ +
+

Robot associé !

+

+ {success.deviceName} fait + maintenant partie de ton foyer. +

+

{success.deviceId}

+ +
+ + +
+
+
+ ); + } + + // ─── Input screen ─────────────────────────────────────────────── + return ( +
+ +
+
+ 🔗 +
+

Associer un robot

+

+ Saisis le code à 6 chiffres affiché sur ton Ti-Pote +

+
+ +
{ + e.preventDefault(); + void submit(); + }} + className="flex flex-col gap-5" + > +
+ {digits.map((d, i) => ( + { + inputsRef.current[i] = el; + }} + inputMode="numeric" + pattern="\d*" + maxLength={1} + value={d} + onChange={(e) => setDigitAt(i, e.target.value)} + onKeyDown={(e) => onKeyDown(i, e)} + onFocus={(e) => e.target.select()} + className="h-14 w-12 rounded-xl border border-slate-700 bg-slate-900/60 text-center text-2xl font-semibold tabular-nums text-slate-100 shadow-inner focus:border-brand-400/60 focus:outline-none focus:ring-2 focus:ring-brand-400/40" + aria-label={`Chiffre ${i + 1}`} + /> + ))} +
+ + {error && ( +
+ {error} +
+ )} + + +
+ +
+ + ← Retour au tableau de bord + +
+ +
+

💡 Comment obtenir le code ?

+

+ Allume ton Ti-Pote. Lors du premier démarrage, il annonce vocalement un code à + 6 chiffres et l'affiche (écran / LED / logs). Ce code n'est valable que 10 minutes. +

+
+
+
+ ); +} diff --git a/apps/frontend/src/pages/RegisterPage.tsx b/apps/frontend/src/pages/RegisterPage.tsx new file mode 100644 index 0000000..b8d0d73 --- /dev/null +++ b/apps/frontend/src/pages/RegisterPage.tsx @@ -0,0 +1,119 @@ +import { useState, type FormEvent } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { Button, Card, Input } from '../components/ui'; +import { useAuth } from '../context/AuthContext'; +import { ApiError } from '../lib/api'; + +export function RegisterPage() { + const { register } = useAuth(); + const navigate = useNavigate(); + + const [displayName, setDisplayName] = useState(''); + const [homeName, setHomeName] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [submitting, setSubmitting] = useState(false); + const [error, setError] = useState(null); + + async function onSubmit(e: FormEvent) { + e.preventDefault(); + setError(null); + + if (password.length < 8) { + setError('Le mot de passe doit faire au moins 8 caractères.'); + return; + } + + setSubmitting(true); + try { + await register({ email, password, displayName, homeName }); + navigate('/', { replace: true }); + } catch (err) { + if (err instanceof ApiError) { + setError( + err.status === 409 + ? 'Cette adresse email est déjà utilisée.' + : err.message || "Erreur lors de l'inscription.", + ); + } else { + setError('Impossible de joindre le serveur.'); + } + } finally { + setSubmitting(false); + } + } + + return ( +
+ +
+
+ ✨ +
+

Crée ton compte

+

+ Associe un Ti-Pote à ta maison en quelques secondes +

+
+ +
+ setDisplayName(e.target.value)} + /> + setHomeName(e.target.value)} + /> + setEmail(e.target.value)} + /> + setPassword(e.target.value)} + /> + + {error && ( +
+ {error} +
+ )} + + +
+ +

+ Déjà un compte ?{' '} + + Se connecter + +

+
+
+ ); +} diff --git a/apps/frontend/src/styles/index.css b/apps/frontend/src/styles/index.css new file mode 100644 index 0000000..b91dc9c --- /dev/null +++ b/apps/frontend/src/styles/index.css @@ -0,0 +1,15 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + html, + body, + #root { + height: 100%; + } + + body { + @apply bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-slate-100; + } +} diff --git a/apps/frontend/tailwind.config.js b/apps/frontend/tailwind.config.js new file mode 100644 index 0000000..a90d558 --- /dev/null +++ b/apps/frontend/tailwind.config.js @@ -0,0 +1,33 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{ts,tsx}'], + theme: { + extend: { + colors: { + brand: { + 50: '#f0f9ff', + 100: '#e0f2fe', + 200: '#bae6fd', + 300: '#7dd3fc', + 400: '#38bdf8', + 500: '#0ea5e9', + 600: '#0284c7', + 700: '#0369a1', + 800: '#075985', + 900: '#0c4a6e', + }, + }, + fontFamily: { + sans: [ + 'Inter', + '-apple-system', + 'system-ui', + 'Segoe UI', + 'Roboto', + 'sans-serif', + ], + }, + }, + }, + plugins: [], +}; diff --git a/apps/frontend/tsconfig.json b/apps/frontend/tsconfig.json new file mode 100644 index 0000000..3b7d21c --- /dev/null +++ b/apps/frontend/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/apps/frontend/tsconfig.node.json b/apps/frontend/tsconfig.node.json new file mode 100644 index 0000000..97ede7e --- /dev/null +++ b/apps/frontend/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/apps/frontend/vite.config.ts b/apps/frontend/vite.config.ts new file mode 100644 index 0000000..14549a5 --- /dev/null +++ b/apps/frontend/vite.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import path from 'node:path'; + +// @ts-expect-error process is provided by Node at config time +const host = process.env.TAURI_DEV_HOST; + +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, + // Tauri expects a fixed port and silences console noise + clearScreen: false, + server: { + port: 1420, + strictPort: true, + host: host || false, + hmr: host + ? { + protocol: 'ws', + host, + port: 1421, + } + : undefined, + watch: { + ignored: ['**/src-tauri/**'], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 957e317..20fa950 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,19 +115,19 @@ importers: version: 4.0.1 '@typescript-eslint/eslint-plugin': specifier: ^8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0)(typescript@5.8.3))(eslint@10.1.0)(typescript@5.8.3) + version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3) '@typescript-eslint/parser': specifier: ^8.57.2 - version: 8.57.2(eslint@10.1.0)(typescript@5.8.3) + version: 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3) eslint: specifier: ^10.1.0 - version: 10.1.0 + version: 10.1.0(jiti@1.21.7) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.1.0) + version: 10.1.8(eslint@10.1.0(jiti@1.21.7)) eslint-plugin-prettier: specifier: ^5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0))(eslint@10.1.0)(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@1.21.7)))(eslint@10.1.0(jiti@1.21.7))(prettier@3.8.1) jest: specifier: ^30.3.0 version: 30.3.0(@types/node@25.5.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.8.3)) @@ -150,18 +150,54 @@ importers: specifier: ^5.8.3 version: 5.8.3 - apps/desktop: + apps/frontend: dependencies: '@tauri-apps/api': - specifier: ^2 + specifier: ^2.0.0 version: 2.10.1 + '@tauri-apps/plugin-store': + specifier: ^2.0.0 + version: 2.4.2 + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + react-router-dom: + specifier: ^6.26.0 + version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + zustand: + specifier: ^4.5.5 + version: 4.5.7(@types/react@18.3.28)(react@18.3.1) devDependencies: '@tauri-apps/cli': - specifier: ^2 + specifier: ^2.0.0 version: 2.10.1 - serve: - specifier: ^14 - version: 14.2.6 + '@types/react': + specifier: ^18.3.3 + version: 18.3.28 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.7(@types/react@18.3.28) + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.7.0(vite@5.4.21(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.27(postcss@8.5.8) + postcss: + specifier: ^8.4.41 + version: 8.5.8 + tailwindcss: + specifier: ^3.4.10 + version: 3.4.19(tsx@4.21.0) + typescript: + specifier: ^5.5.4 + version: 5.9.3 + vite: + specifier: ^5.4.2 + version: 5.4.21(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) apps/robot-client: dependencies: @@ -186,13 +222,13 @@ importers: version: 22.19.15 eslint: specifier: ^10.1.0 - version: 10.1.0 + version: 10.1.0(jiti@1.21.7) prettier: specifier: ^3.8.1 version: 3.8.1 tsup: specifier: ^8.5.0 - version: 8.5.1(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3) + version: 8.5.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -201,7 +237,7 @@ importers: version: 5.9.3 vitest: specifier: ^3.2.1 - version: 3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + version: 3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1) apps/simulator: dependencies: @@ -223,13 +259,13 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(terser@5.46.1)(tsx@4.21.0)) + version: 6.0.1(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(jiti@1.21.7)(terser@5.46.1)(tsx@4.21.0)) typescript: specifier: ~5.9.3 version: 5.9.3 vite: specifier: ^8.0.1 - version: 8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(terser@5.46.1)(tsx@4.21.0) + version: 8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(jiti@1.21.7)(terser@5.46.1)(tsx@4.21.0) packages: @@ -277,6 +313,10 @@ packages: peerDependencies: zod: ^3.23.8 + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@angular-devkit/core@19.2.17': resolution: {integrity: sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -467,6 +507,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@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.29.2': resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} @@ -510,102 +562,204 @@ packages: '@emnapi/wasi-threads@1.2.0': resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.27.4': resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.27.4': resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.27.4': resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.27.4': resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.27.4': resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.27.4': resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.27.4': resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.4': resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.27.4': resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.27.4': resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.27.4': resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.27.4': resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.27.4': resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.27.4': resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.27.4': resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.27.4': resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.27.4': resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} engines: {node: '>=18'} @@ -618,6 +772,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.4': resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} engines: {node: '>=18'} @@ -630,6 +790,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.4': resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} engines: {node: '>=18'} @@ -642,24 +808,48 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.27.4': resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.27.4': resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.27.4': resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.27.4': resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} engines: {node: '>=18'} @@ -1133,6 +1323,18 @@ packages: '@nestjs/platform-socket.io': optional: true + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@nuxt/opencollective@0.4.1': resolution: {integrity: sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==} engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} @@ -1152,6 +1354,10 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@remix-run/router@1.23.2': + resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} + engines: {node: '>=14.0.0'} + '@rolldown/binding-android-arm64@1.0.0-rc.12': resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1247,6 +1453,9 @@ packages: cpu: [x64] os: [win32] + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rolldown/pluginutils@1.0.0-rc.12': resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} @@ -1628,6 +1837,9 @@ packages: engines: {node: '>= 10'} hasBin: true + '@tauri-apps/plugin-store@2.4.2': + resolution: {integrity: sha512-0ClHS50Oq9HEvLPhNzTNFxbWVOqoAp3dRvtewQBeqfIQ0z5m3JRnOISIn2ZVPCrQC0MyGyhTS9DWhHjpigQE7A==} + '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -1746,17 +1958,28 @@ packages: '@types/passport@1.0.17': resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==} + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@types/qs@6.15.0': resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: '@types/react': ^19.2.0 + '@types/react@18.3.28': + resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} + '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} @@ -1952,6 +2175,12 @@ packages: cpu: [x64] os: [win32] + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@vitejs/plugin-react@6.0.1': resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2045,9 +2274,6 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - '@zeit/schemas@2.36.0': - resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} - abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -2115,9 +2341,6 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -2164,9 +2387,6 @@ packages: append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - arch@2.2.0: - resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} - arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -2196,6 +2416,13 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -2248,6 +2475,10 @@ packages: resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==} engines: {node: '>= 18'} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2259,10 +2490,6 @@ packages: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} - boxen@7.0.0: - resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} - engines: {node: '>=14.16'} - brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -2273,6 +2500,10 @@ packages: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -2307,10 +2538,6 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - bytes@3.0.0: - resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} - engines: {node: '>= 0.8'} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -2335,6 +2562,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -2343,10 +2574,6 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - caniuse-lite@1.0.30001781: resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} @@ -2354,18 +2581,10 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} - chalk-template@0.4.0: - resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} - engines: {node: '>=12'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.0.1: - resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -2377,6 +2596,10 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -2398,10 +2621,6 @@ packages: class-validator@0.15.1: resolution: {integrity: sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==} - cli-boxes@3.0.0: - resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} - engines: {node: '>=10'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -2418,10 +2637,6 @@ packages: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} - clipboardy@3.0.0: - resolution: {integrity: sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2469,14 +2684,6 @@ packages: resolution: {integrity: sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==} engines: {node: '>= 6'} - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.1: - resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} - engines: {node: '>= 0.8.0'} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2491,10 +2698,6 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - content-disposition@0.5.2: - resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} - engines: {node: '>= 0.6'} - content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -2544,6 +2747,11 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2591,10 +2799,6 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -2633,10 +2837,16 @@ packages: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff@4.0.4: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dotenv-expand@12.0.3: resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==} engines: {node: '>=12'} @@ -2730,6 +2940,11 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.27.4: resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} engines: {node: '>=18'} @@ -2899,6 +3114,10 @@ packages: fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -2911,6 +3130,9 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -2935,6 +3157,10 @@ packages: resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} engines: {node: '>=20'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + finalhandler@1.3.2: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} @@ -2992,6 +3218,9 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -3049,6 +3278,10 @@ packages: get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -3180,9 +3413,6 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ioredis@5.10.1: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} @@ -3198,14 +3428,17 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} @@ -3235,14 +3468,14 @@ packages: resolution: {integrity: sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==} engines: {node: '>=16'} + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-port-reachable@4.0.0: - resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3266,10 +3499,6 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -3435,6 +3664,10 @@ packages: node-notifier: optional: true + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + jose@6.2.2: resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} @@ -3670,6 +3903,10 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -3722,13 +3959,17 @@ packages: merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - mime-db@1.33.0: - resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} - engines: {node: '>= 0.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} @@ -3738,10 +3979,6 @@ packages: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} - mime-types@2.1.18: - resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} - engines: {node: '>= 0.6'} - mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -3817,10 +4054,6 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -3896,10 +4129,6 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3996,9 +4225,6 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - path-is-inside@1.0.2: - resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4007,6 +4233,9 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -4018,9 +4247,6 @@ packages: path-to-regexp@0.1.13: resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} - path-to-regexp@3.3.0: - resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} - path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -4087,6 +4313,10 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} @@ -4127,6 +4357,18 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -4145,6 +4387,19 @@ packages: yaml: optional: true + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.8: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} @@ -4218,6 +4473,9 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -4225,10 +4483,6 @@ packages: resolution: {integrity: sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==} engines: {node: '>=14.18.0'} - range-parser@1.2.0: - resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} - engines: {node: '>= 0.6'} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -4241,9 +4495,10 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} @@ -4253,10 +4508,34 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-router-dom@6.30.3: + resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + react-router@6.30.3: + resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -4265,6 +4544,10 @@ packages: resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -4284,13 +4567,6 @@ packages: reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} - registry-auth-token@3.3.2: - resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} - - registry-url@3.1.0: - resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} - engines: {node: '>=0.10.0'} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4314,10 +4590,19 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rolldown@1.0.0-rc.12: resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4332,6 +4617,9 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -4348,6 +4636,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -4390,9 +4681,6 @@ packages: resolution: {integrity: sha512-AmH3D9hHPFmnF/oq/rvigfiAouAKyK/TjnrkwZRYSFZxNggJxwvbAbfYrLeuvq7ktUdhuHdVdSjj852Z55R+uA==} engines: {node: '>=16.0.0'} - serve-handler@6.1.7: - resolution: {integrity: sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==} - serve-static@1.16.3: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} @@ -4401,11 +4689,6 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} - serve@14.2.6: - resolution: {integrity: sha512-QEjUSA+sD4Rotm1znR8s50YqA3kYpRGPmtd5GlFxbaL9n/FdUNbqMhxClqdditSk0LlZyA/dhud6XNRTOC9x2Q==} - engines: {node: '>= 14'} - hasBin: true - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -4571,10 +4854,6 @@ packages: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4603,6 +4882,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -4611,6 +4894,11 @@ packages: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + tapable@2.3.2: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} @@ -4679,6 +4967,10 @@ packages: resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} engines: {node: '>= 0.4'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -4794,10 +5086,6 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -4925,15 +5213,17 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - update-check@1.5.4: - resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -4965,27 +5255,22 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' 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 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 peerDependenciesMeta: '@types/node': optional: true - jiti: - optional: true less: optional: true lightningcss: @@ -5000,10 +5285,6 @@ packages: optional: true terser: optional: true - tsx: - optional: true - yaml: - optional: true vite@8.0.3: resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==} @@ -5124,10 +5405,6 @@ packages: engines: {node: '>=8'} hasBin: true - widest-line@4.0.1: - resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} - engines: {node: '>=12'} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -5237,6 +5514,21 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zustand@4.5.7: + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + snapshots: '@a2a-js/sdk@0.2.5': @@ -5294,6 +5586,8 @@ snapshots: zod: 4.3.6 zod-to-json-schema: 3.25.2(zod@4.3.6) + '@alloc/quick-lru@5.2.0': {} + '@angular-devkit/core@19.2.17(chokidar@4.0.3)': dependencies: ajv: 8.17.1 @@ -5518,6 +5812,16 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/runtime@7.29.2': {} '@babel/template@7.28.6': @@ -5577,87 +5881,156 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.21.5': + optional: true + '@esbuild/aix-ppc64@0.27.4': optional: true + '@esbuild/android-arm64@0.21.5': + optional: true + '@esbuild/android-arm64@0.27.4': optional: true + '@esbuild/android-arm@0.21.5': + optional: true + '@esbuild/android-arm@0.27.4': optional: true + '@esbuild/android-x64@0.21.5': + optional: true + '@esbuild/android-x64@0.27.4': optional: true + '@esbuild/darwin-arm64@0.21.5': + optional: true + '@esbuild/darwin-arm64@0.27.4': optional: true + '@esbuild/darwin-x64@0.21.5': + optional: true + '@esbuild/darwin-x64@0.27.4': optional: true + '@esbuild/freebsd-arm64@0.21.5': + optional: true + '@esbuild/freebsd-arm64@0.27.4': optional: true + '@esbuild/freebsd-x64@0.21.5': + optional: true + '@esbuild/freebsd-x64@0.27.4': optional: true + '@esbuild/linux-arm64@0.21.5': + optional: true + '@esbuild/linux-arm64@0.27.4': optional: true + '@esbuild/linux-arm@0.21.5': + optional: true + '@esbuild/linux-arm@0.27.4': optional: true + '@esbuild/linux-ia32@0.21.5': + optional: true + '@esbuild/linux-ia32@0.27.4': optional: true + '@esbuild/linux-loong64@0.21.5': + optional: true + '@esbuild/linux-loong64@0.27.4': optional: true + '@esbuild/linux-mips64el@0.21.5': + optional: true + '@esbuild/linux-mips64el@0.27.4': optional: true + '@esbuild/linux-ppc64@0.21.5': + optional: true + '@esbuild/linux-ppc64@0.27.4': optional: true + '@esbuild/linux-riscv64@0.21.5': + optional: true + '@esbuild/linux-riscv64@0.27.4': optional: true + '@esbuild/linux-s390x@0.21.5': + optional: true + '@esbuild/linux-s390x@0.27.4': optional: true + '@esbuild/linux-x64@0.21.5': + optional: true + '@esbuild/linux-x64@0.27.4': optional: true '@esbuild/netbsd-arm64@0.27.4': optional: true + '@esbuild/netbsd-x64@0.21.5': + optional: true + '@esbuild/netbsd-x64@0.27.4': optional: true '@esbuild/openbsd-arm64@0.27.4': optional: true + '@esbuild/openbsd-x64@0.21.5': + optional: true + '@esbuild/openbsd-x64@0.27.4': optional: true '@esbuild/openharmony-arm64@0.27.4': optional: true + '@esbuild/sunos-x64@0.21.5': + optional: true + '@esbuild/sunos-x64@0.27.4': optional: true + '@esbuild/win32-arm64@0.21.5': + optional: true + '@esbuild/win32-arm64@0.27.4': optional: true + '@esbuild/win32-ia32@0.21.5': + optional: true + '@esbuild/win32-ia32@0.27.4': optional: true + '@esbuild/win32-x64@0.21.5': + optional: true + '@esbuild/win32-x64@0.27.4': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.1.0)': + '@eslint-community/eslint-utils@4.9.1(eslint@10.1.0(jiti@1.21.7))': dependencies: - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -6310,6 +6683,18 @@ snapshots: optionalDependencies: '@nestjs/platform-socket.io': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.17)(rxjs@7.8.2) + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + '@nuxt/opencollective@0.4.1': dependencies: consola: 3.4.2 @@ -6323,6 +6708,8 @@ snapshots: '@pkgr/core@0.2.9': {} + '@remix-run/router@1.23.2': {} + '@rolldown/binding-android-arm64@1.0.0-rc.12': optional: true @@ -6370,6 +6757,8 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': optional: true + '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rolldown/pluginutils@1.0.0-rc.12': {} '@rolldown/pluginutils@1.0.0-rc.7': {} @@ -6598,6 +6987,10 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.10.1 '@tauri-apps/cli-win32-x64-msvc': 2.10.1 + '@tauri-apps/plugin-store@2.4.2': + dependencies: + '@tauri-apps/api': 2.10.1 + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -6756,14 +7149,25 @@ snapshots: dependencies: '@types/express': 5.0.6 + '@types/prop-types@15.7.15': {} + '@types/qs@6.15.0': {} '@types/range-parser@1.2.7': {} + '@types/react-dom@18.3.7(@types/react@18.3.28)': + dependencies: + '@types/react': 18.3.28 + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: '@types/react': 19.2.14 + '@types/react@18.3.28': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -6802,15 +7206,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0)(typescript@5.8.3))(eslint@10.1.0)(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3))(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.2(eslint@10.1.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0)(typescript@5.8.3) - '@typescript-eslint/utils': 8.57.2(eslint@10.1.0)(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.57.2 - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.8.3) @@ -6818,14 +7222,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.2(eslint@10.1.0)(typescript@5.8.3)': + '@typescript-eslint/parser@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.57.2 '@typescript-eslint/types': 8.57.2 '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.57.2 debug: 4.4.3 - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -6848,13 +7252,13 @@ snapshots: dependencies: typescript: 5.8.3 - '@typescript-eslint/type-utils@8.57.2(eslint@10.1.0)(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 8.57.2 '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.8.3) - '@typescript-eslint/utils': 8.57.2(eslint@10.1.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3) debug: 4.4.3 - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) ts-api-utils: 2.5.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -6877,13 +7281,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.2(eslint@10.1.0)(typescript@5.8.3)': + '@typescript-eslint/utils@8.57.2(eslint@10.1.0(jiti@1.21.7))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@1.21.7)) '@typescript-eslint/scope-manager': 8.57.2 '@typescript-eslint/types': 8.57.2 '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.8.3) - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -6954,10 +7358,22 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@6.0.1(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(terser@5.46.1)(tsx@4.21.0))': + '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 5.4.21(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-react@6.0.1(vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(jiti@1.21.7)(terser@5.46.1)(tsx@4.21.0))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(terser@5.46.1)(tsx@4.21.0) + vite: 8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(jiti@1.21.7)(terser@5.46.1)(tsx@4.21.0) '@vitest/expect@3.2.4': dependencies: @@ -6967,13 +7383,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0))': + '@vitest/mocker@3.2.4(vite@5.4.21(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 7.3.1(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 5.4.21(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -7081,8 +7497,6 @@ snapshots: '@xtuc/long@4.2.2': {} - '@zeit/schemas@2.36.0': {} - abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -7153,10 +7567,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-align@3.0.1: - dependencies: - string-width: 4.2.3 - ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -7188,8 +7598,6 @@ snapshots: append-field@1.0.0: {} - arch@2.2.0: {} - arg@4.1.3: {} arg@5.0.2: {} @@ -7210,6 +7618,15 @@ snapshots: atomic-sleep@1.0.0: {} + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001781 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -7281,6 +7698,8 @@ snapshots: node-addon-api: 8.7.0 node-gyp-build: 4.8.4 + binary-extensions@2.3.0: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -7318,17 +7737,6 @@ snapshots: transitivePeerDependencies: - supports-color - boxen@7.0.0: - dependencies: - ansi-align: 3.0.1 - camelcase: 7.0.1 - chalk: 5.0.1 - cli-boxes: 3.0.0 - string-width: 5.1.2 - type-fest: 2.19.0 - widest-line: 4.0.1 - wrap-ansi: 8.1.0 - brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -7342,6 +7750,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.11 @@ -7381,8 +7793,6 @@ snapshots: dependencies: streamsearch: 1.1.0 - bytes@3.0.0: {} - bytes@3.1.2: {} cac@6.7.14: {} @@ -7406,12 +7816,12 @@ snapshots: callsites@3.1.0: {} + camelcase-css@2.0.1: {} + camelcase@5.3.1: {} camelcase@6.3.0: {} - camelcase@7.0.1: {} - caniuse-lite@1.0.30001781: {} chai@5.3.3: @@ -7422,23 +7832,29 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 - chalk-template@0.4.0: - dependencies: - chalk: 4.1.2 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.0.1: {} - char-regex@1.0.2: {} chardet@2.1.1: {} check-error@2.1.3: {} + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -7457,8 +7873,6 @@ snapshots: libphonenumber-js: 1.12.40 validator: 13.15.26 - cli-boxes@3.0.0: {} - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -7473,12 +7887,6 @@ snapshots: cli-width@4.1.0: {} - clipboardy@3.0.0: - dependencies: - arch: 2.2.0 - execa: 5.1.1 - is-wsl: 2.2.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -7517,22 +7925,6 @@ snapshots: core-util-is: 1.0.3 esprima: 4.0.1 - compressible@2.0.18: - dependencies: - mime-db: 1.54.0 - - compression@1.8.1: - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9 - negotiator: 0.6.4 - on-headers: 1.1.0 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - concat-map@0.0.1: {} concat-stream@2.0.0: @@ -7546,8 +7938,6 @@ snapshots: consola@3.4.2: {} - content-disposition@0.5.2: {} - content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -7588,6 +7978,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cssesc@3.0.0: {} + csstype@3.2.3: {} dateformat@4.6.3: {} @@ -7610,8 +8002,6 @@ snapshots: deep-eql@5.0.2: {} - deep-extend@0.6.0: {} - deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -7638,8 +8028,12 @@ snapshots: detect-newline@3.1.0: {} + didyoumean@1.2.2: {} + diff@4.0.4: {} + dlv@1.1.3: {} + dotenv-expand@12.0.3: dependencies: dotenv: 16.6.1 @@ -7751,6 +8145,32 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + esbuild@0.27.4: optionalDependencies: '@esbuild/aix-ppc64': 0.27.4 @@ -7790,19 +8210,19 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.1.0): + eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@1.21.7)): dependencies: - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0))(eslint@10.1.0)(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@1.21.7)))(eslint@10.1.0(jiti@1.21.7))(prettier@3.8.1): dependencies: - eslint: 10.1.0 + eslint: 10.1.0(jiti@1.21.7) prettier: 3.8.1 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@10.1.0) + eslint-config-prettier: 10.1.8(eslint@10.1.0(jiti@1.21.7)) eslint-scope@5.1.1: dependencies: @@ -7820,9 +8240,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.1.0: + eslint@10.1.0(jiti@1.21.7): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@1.21.7)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.3 '@eslint/config-helpers': 0.5.3 @@ -7852,6 +8272,8 @@ snapshots: minimatch: 10.2.4 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 transitivePeerDependencies: - supports-color @@ -8017,6 +8439,14 @@ snapshots: fast-diff@1.3.0: {} + fast-glob@3.3.3: + 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-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -8025,6 +8455,10 @@ snapshots: fast-uri@3.1.0: {} + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -8050,6 +8484,10 @@ snapshots: transitivePeerDependencies: - supports-color + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + finalhandler@1.3.2: dependencies: debug: 2.6.9 @@ -8136,6 +8574,8 @@ snapshots: forwarded@0.2.0: {} + fraction.js@5.3.4: {} + fresh@0.5.2: {} fresh@2.0.0: {} @@ -8190,6 +8630,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -8316,8 +8760,6 @@ snapshots: inherits@2.0.4: {} - ini@1.3.8: {} - ioredis@5.10.1: dependencies: '@ioredis/commands': 1.5.1 @@ -8338,9 +8780,15 @@ snapshots: is-arrayish@0.2.1: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-callable@1.2.7: {} - is-docker@2.2.1: {} + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 is-extendable@0.1.1: {} @@ -8358,9 +8806,9 @@ snapshots: is-network-error@1.3.1: {} - is-plain-obj@4.1.0: {} + is-number@7.0.0: {} - is-port-reachable@4.0.0: {} + is-plain-obj@4.1.0: {} is-promise@4.0.0: {} @@ -8376,10 +8824,6 @@ snapshots: is-unicode-supported@2.1.0: {} - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - isarray@2.0.5: {} isexe@2.0.0: {} @@ -8740,6 +9184,8 @@ snapshots: - supports-color - ts-node + jiti@1.21.7: {} + jose@6.2.2: {} joycon@3.1.1: {} @@ -8927,6 +9373,10 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + loupe@3.2.1: {} lru-cache@10.4.3: {} @@ -8967,18 +9417,19 @@ snapshots: merge-stream@2.0.0: {} + merge2@1.4.1: {} + methods@1.1.2: {} - mime-db@1.33.0: {} + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 mime-db@1.52.0: {} mime-db@1.54.0: {} - mime-types@2.1.18: - dependencies: - mime-db: 1.33.0 - mime-types@2.1.35: dependencies: mime-db: 1.52.0 @@ -9043,8 +9494,6 @@ snapshots: negotiator@0.6.3: {} - negotiator@0.6.4: {} - negotiator@1.0.0: {} neo-async@2.6.2: {} @@ -9094,8 +9543,6 @@ snapshots: dependencies: ee-first: 1.1.1 - on-headers@1.1.0: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -9190,12 +9637,12 @@ snapshots: path-is-absolute@1.0.1: {} - path-is-inside@1.0.2: {} - path-key@3.1.1: {} path-key@4.0.0: {} + path-parse@1.0.7: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -9208,8 +9655,6 @@ snapshots: path-to-regexp@0.1.13: {} - path-to-regexp@3.3.0: {} - path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -9263,6 +9708,8 @@ snapshots: picomatch@4.0.4: {} + pify@2.3.0: {} + pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 @@ -9321,13 +9768,38 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(postcss@8.5.8)(tsx@4.21.0): + postcss-import@15.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.8): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.8 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0): dependencies: lilconfig: 3.1.3 optionalDependencies: + jiti: 1.21.7 postcss: 8.5.8 tsx: 4.21.0 + postcss-nested@6.2.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.5.8: dependencies: nanoid: 3.3.11 @@ -9390,12 +9862,12 @@ snapshots: quansync@0.2.11: {} + queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} radash@12.1.1: {} - range-parser@1.2.0: {} - range-parser@1.2.1: {} raw-body@2.5.3: @@ -9412,12 +9884,11 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - rc@1.2.8: + react-dom@18.3.1(react@18.3.1): dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 react-dom@19.2.4(react@19.2.4): dependencies: @@ -9426,8 +9897,30 @@ snapshots: react-is@18.3.1: {} + react-refresh@0.17.0: {} + + react-router-dom@6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.2 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.30.3(react@18.3.1) + + react-router@6.30.3(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.2 + react: 18.3.1 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + react@19.2.4: {} + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -9442,6 +9935,10 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + readdirp@4.1.2: {} real-require@0.2.0: {} @@ -9454,15 +9951,6 @@ snapshots: reflect-metadata@0.2.2: {} - registry-auth-token@3.3.2: - dependencies: - rc: 1.2.8 - safe-buffer: 5.2.1 - - registry-url@3.1.0: - dependencies: - rc: 1.2.8 - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -9477,11 +9965,19 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 + reusify@1.1.0: {} + rolldown@1.0.0-rc.12: dependencies: '@oxc-project/types': 0.122.0 @@ -9544,6 +10040,10 @@ snapshots: transitivePeerDependencies: - supports-color + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + rxjs@7.8.1: dependencies: tslib: 2.8.1 @@ -9558,6 +10058,10 @@ snapshots: safer-buffer@2.1.2: {} + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + scheduler@0.27.0: {} schema-utils@3.3.0: @@ -9639,16 +10143,6 @@ snapshots: transitivePeerDependencies: - supports-color - serve-handler@6.1.7: - dependencies: - bytes: 3.0.0 - content-disposition: 0.5.2 - mime-types: 2.1.18 - minimatch: 3.1.5 - path-is-inside: 1.0.2 - path-to-regexp: 3.3.0 - range-parser: 1.2.0 - serve-static@1.16.3: dependencies: encodeurl: 2.0.0 @@ -9667,22 +10161,6 @@ snapshots: transitivePeerDependencies: - supports-color - serve@14.2.6: - dependencies: - '@zeit/schemas': 2.36.0 - ajv: 8.18.0 - arg: 5.0.2 - boxen: 7.0.0 - chalk: 5.0.1 - chalk-template: 0.4.0 - clipboardy: 3.0.0 - compression: 1.8.1 - is-port-reachable: 4.0.0 - serve-handler: 6.1.7 - update-check: 1.5.4 - transitivePeerDependencies: - - supports-color - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -9864,8 +10342,6 @@ snapshots: strip-final-newline@4.0.0: {} - strip-json-comments@2.0.1: {} - strip-json-comments@3.1.1: {} strip-json-comments@5.0.3: {} @@ -9896,12 +10372,42 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + symbol-observable@4.0.0: {} synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 + tailwindcss@3.4.19(tsx@4.21.0): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-import: 15.1.0(postcss@8.5.8) + postcss-js: 4.1.0(postcss@8.5.8) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0) + postcss-nested: 6.2.0(postcss@8.5.8) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + tapable@2.3.2: {} terser-webpack-plugin@5.4.0(webpack@5.104.1): @@ -9960,6 +10466,10 @@ snapshots: safe-buffer: 5.2.1 typed-array-buffer: 1.0.3 + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + toidentifier@1.0.1: {} token-types@6.1.2: @@ -10033,7 +10543,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3): + tsup@8.5.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.4) cac: 6.7.14 @@ -10044,7 +10554,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(postcss@8.5.8)(tsx@4.21.0) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0) resolve-from: 5.0.0 rollup: 4.60.1 source-map: 0.7.6 @@ -10076,8 +10586,6 @@ snapshots: type-fest@0.21.3: {} - type-fest@2.19.0: {} - type-fest@4.41.0: {} type-is@1.6.18: @@ -10179,17 +10687,16 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - update-check@1.5.4: - dependencies: - registry-auth-token: 3.3.2 - registry-url: 3.1.0 - uri-js@4.4.1: dependencies: punycode: 2.3.1 url-join@4.0.1: {} + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + util-deprecate@1.0.2: {} utils-merge@1.0.1: {} @@ -10208,16 +10715,15 @@ snapshots: vary@1.1.2: {} - vite-node@3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vite-node@3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 5.4.21(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1) transitivePeerDependencies: - '@types/node' - - jiti - less - lightningcss - sass @@ -10226,25 +10732,30 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml - vite@7.3.1(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vite@5.4.21(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1): dependencies: - esbuild: 0.27.4 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + esbuild: 0.21.5 postcss: 8.5.8 rollup: 4.60.1 - tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.19.15 fsevents: 2.3.3 lightningcss: 1.32.0 terser: 5.46.1 - tsx: 4.21.0 - vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(terser@5.46.1)(tsx@4.21.0): + vite@5.4.21(@types/node@25.5.0)(lightningcss@1.32.0)(terser@5.46.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.8 + rollup: 4.60.1 + optionalDependencies: + '@types/node': 25.5.0 + fsevents: 2.3.3 + lightningcss: 1.32.0 + terser: 5.46.1 + + vite@8.0.3(@types/node@25.5.0)(esbuild@0.27.4)(jiti@1.21.7)(terser@5.46.1)(tsx@4.21.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -10255,14 +10766,15 @@ snapshots: '@types/node': 25.5.0 esbuild: 0.27.4 fsevents: 2.3.3 + jiti: 1.21.7 terser: 5.46.1 tsx: 4.21.0 - vitest@3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0): + vitest@3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)) + '@vitest/mocker': 3.2.4(vite@5.4.21(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -10280,13 +10792,12 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) - vite-node: 3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0) + vite: 5.4.21(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1) + vite-node: 3.2.4(@types/node@22.19.15)(lightningcss@1.32.0)(terser@5.46.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.15 transitivePeerDependencies: - - jiti - less - lightningcss - msw @@ -10296,8 +10807,6 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml walker@1.0.8: dependencies: @@ -10374,10 +10883,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - widest-line@4.0.1: - dependencies: - string-width: 5.1.2 - word-wrap@1.2.5: {} wordwrap@1.0.0: {} @@ -10456,3 +10961,10 @@ snapshots: zod@3.25.76: {} zod@4.3.6: {} + + zustand@4.5.7(@types/react@18.3.28)(react@18.3.1): + dependencies: + use-sync-external-store: 1.6.0(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.28 + react: 18.3.1