diff --git a/.github/workflows/frontend-deploy.yml b/.github/workflows/frontend-deploy.yml index d0c64e8..88d0678 100644 --- a/.github/workflows/frontend-deploy.yml +++ b/.github/workflows/frontend-deploy.yml @@ -8,6 +8,10 @@ on: permissions: contents: read +concurrency: + group: frontend-production + cancel-in-progress: false + jobs: build-and-deploy: runs-on: ubuntu-latest @@ -54,21 +58,23 @@ jobs: set -euo pipefail PACKAGE_VERSION="$(node -p "require('./package.json').version")" - echo "Release version: $RELEASE_VERSION" - echo "package.json version: $PACKAGE_VERSION" - if [ "$RELEASE_VERSION" != "$PACKAGE_VERSION" ]; then echo "::error::Version mismatch: frontend release '$RELEASE_VERSION' does not match package.json version '$PACKAGE_VERSION'." exit 1 fi - - name: Set up environment file - run: | - echo "VITE_API_URL=${{ secrets.VITE_API_URL }}" > .env.production + - name: Set up production environment + run: cp .env.production.example .env.production - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Check formatting + run: pnpm run format:check + + - name: Lint app + run: pnpm run lint + - name: Build app run: pnpm run build @@ -92,6 +98,19 @@ jobs: fs.writeFileSync("dist/version.json", `${JSON.stringify(version, null, 2)}\n`); NODE + - name: Package immutable release + env: + RELEASE_VERSION: ${{ steps.version.outputs.version }} + run: tar -czf "$PWD/bitfinance-frontend-$RELEASE_VERSION.tar.gz" -C dist . + + - name: Retain rollback artifact + uses: actions/upload-artifact@v7 + with: + name: bitfinance-frontend-${{ steps.version.outputs.version }} + path: apps/frontend/bitfinance-frontend-${{ steps.version.outputs.version }}.tar.gz + retention-days: 90 + if-no-files-found: error + - name: Connect to Tailscale uses: tailscale/github-action@v4 with: @@ -99,8 +118,9 @@ jobs: oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} tags: tag:ci - - name: Deploy files + - name: Deploy immutable release env: + RELEASE_VERSION: ${{ steps.version.outputs.version }} SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }} SSH_HOST_IP: ${{ secrets.SSH_HOST }} TAILSCALE_HOST: ${{ secrets.TAILSCALE_HOST }} @@ -110,6 +130,8 @@ jobs: set -euo pipefail TARGET_HOST="${TAILSCALE_HOST:-$SSH_HOST_IP}" + ARCHIVE_NAME="bitfinance-frontend-$RELEASE_VERSION.tar.gz" + REMOTE_ARCHIVE="/tmp/$ARCHIVE_NAME-$GITHUB_RUN_ID" mkdir -p ~/.ssh chmod 700 ~/.ssh @@ -121,16 +143,48 @@ jobs: printf '%s' "$SSH_PRIVATE_KEY" > "$KEY_FILE" chmod 600 "$KEY_FILE" - ssh -i "$KEY_FILE" \ - -p "$SSH_PORT" \ + scp -i "$KEY_FILE" \ + -P "$SSH_PORT" \ -o BatchMode=yes \ -o IdentitiesOnly=yes \ -o StrictHostKeyChecking=yes \ - "$SSH_USERNAME@$TARGET_HOST" 'echo "SSH auth OK"' + "$ARCHIVE_NAME" "$SSH_USERNAME@$TARGET_HOST:$REMOTE_ARCHIVE" - scp -i "$KEY_FILE" \ - -P "$SSH_PORT" \ + ssh -i "$KEY_FILE" \ + -p "$SSH_PORT" \ -o BatchMode=yes \ -o IdentitiesOnly=yes \ -o StrictHostKeyChecking=yes \ - -r dist/* "$SSH_USERNAME@$TARGET_HOST:/var/www/bitfinance/" + "$SSH_USERNAME@$TARGET_HOST" \ + "RELEASE_VERSION='$RELEASE_VERSION' REMOTE_ARCHIVE='$REMOTE_ARCHIVE' bash -s" <<'REMOTE' + set -euo pipefail + + DEPLOY_ROOT=/var/www/bitfinance + RELEASE_PATH="$DEPLOY_ROOT/releases/$RELEASE_VERSION" + STAGING_PATH="$DEPLOY_ROOT/releases/.$RELEASE_VERSION-$RANDOM" + + cleanup() { + rm -f "$REMOTE_ARCHIVE" + rm -rf "$STAGING_PATH" + } + trap cleanup EXIT + + mkdir -p "$DEPLOY_ROOT/releases" + if [ -e "$RELEASE_PATH" ]; then + echo "Release already exists and is immutable: $RELEASE_PATH" >&2 + exit 1 + fi + + mkdir "$STAGING_PATH" + tar -xzf "$REMOTE_ARCHIVE" -C "$STAGING_PATH" + test -f "$STAGING_PATH/index.html" + grep -F "\"version\": \"$RELEASE_VERSION\"" "$STAGING_PATH/version.json" + mv "$STAGING_PATH" "$RELEASE_PATH" + + rm -f "$DEPLOY_ROOT/current.next" + ln -s "releases/$RELEASE_VERSION" "$DEPLOY_ROOT/current.next" + mv -Tf "$DEPLOY_ROOT/current.next" "$DEPLOY_ROOT/current" + + test "$(readlink "$DEPLOY_ROOT/current")" = "releases/$RELEASE_VERSION" + test -f "$DEPLOY_ROOT/current/sw.js" + REMOTE diff --git a/.github/workflows/frontend-v2-deploy.yml b/.github/workflows/frontend-v2-deploy.yml deleted file mode 100644 index 5aa2f8c..0000000 --- a/.github/workflows/frontend-v2-deploy.yml +++ /dev/null @@ -1,155 +0,0 @@ -name: Frontend v2 Release - -on: - push: - tags: - - "frontend-v2/v*" - -permissions: - contents: read - -concurrency: - group: frontend-v2-production - cancel-in-progress: false - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - environment: production - defaults: - run: - working-directory: apps/frontend-v2 - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Set release version - id: version - env: - REF_NAME: ${{ github.ref_name }} - run: | - set -euo pipefail - VERSION="${REF_NAME#frontend-v2/v}" - - if ! printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then - echo "::error::Version must be semver without the v prefix. Received '$VERSION'." - exit 1 - fi - - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - - name: Install pnpm - uses: pnpm/action-setup@v6 - with: - version: 11.0.9 - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: apps/frontend-v2/pnpm-lock.yaml - - - name: Validate package.json version - env: - RELEASE_VERSION: ${{ steps.version.outputs.version }} - run: | - set -euo pipefail - PACKAGE_VERSION="$(node -p "require('./package.json').version")" - - echo "Release version: $RELEASE_VERSION" - echo "package.json version: $PACKAGE_VERSION" - - if [ "$RELEASE_VERSION" != "$PACKAGE_VERSION" ]; then - echo "::error::Version mismatch: frontend v2 release '$RELEASE_VERSION' does not match package.json version '$PACKAGE_VERSION'." - exit 1 - fi - - - name: Set up production environment - run: | - cp .env.production.example .env.production - cat .env.production >> "$GITHUB_ENV" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Lint app - run: pnpm run lint - - - name: Build app - run: pnpm run build - - - name: Write version file - env: - RELEASE_VERSION: ${{ steps.version.outputs.version }} - RELEASE_REF: ${{ github.ref_name }} - RELEASE_SHA: ${{ github.sha }} - run: | - set -euo pipefail - node - <<'NODE' - const fs = require("fs"); - - const version = { - version: process.env.RELEASE_VERSION, - commit: process.env.RELEASE_SHA, - ref: process.env.RELEASE_REF, - builtAt: new Date().toISOString() - }; - - fs.writeFileSync("dist/version.json", `${JSON.stringify(version, null, 2)}\n`); - NODE - - - name: Connect to Tailscale - uses: tailscale/github-action@v4 - with: - oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }} - oauth-secret: ${{ secrets.TS_OAUTH_SECRET }} - tags: tag:ci - - - name: Deploy files - env: - RELEASE_VERSION: ${{ steps.version.outputs.version }} - SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }} - SSH_HOST_IP: ${{ secrets.SSH_HOST }} - TAILSCALE_HOST: ${{ secrets.TAILSCALE_HOST }} - SSH_USERNAME: ${{ secrets.SSH_USERNAME }} - SSH_PORT: ${{ secrets.SSH_PORT || '22' }} - DEPLOY_PATH: /var/www/bitfinance-v2 - run: | - set -euo pipefail - - TARGET_HOST="${TAILSCALE_HOST:-$SSH_HOST_IP}" - - mkdir -p ~/.ssh - chmod 700 ~/.ssh - ssh-keyscan -p "$SSH_PORT" -H "$TARGET_HOST" > ~/.ssh/known_hosts - chmod 600 ~/.ssh/known_hosts - - KEY_FILE="$(mktemp)" - trap 'rm -f "$KEY_FILE"' EXIT - printf '%s' "$SSH_PRIVATE_KEY" > "$KEY_FILE" - chmod 600 "$KEY_FILE" - - ssh -i "$KEY_FILE" \ - -p "$SSH_PORT" \ - -o BatchMode=yes \ - -o IdentitiesOnly=yes \ - -o StrictHostKeyChecking=yes \ - "$SSH_USERNAME@$TARGET_HOST" \ - "mkdir -p '$DEPLOY_PATH'" - - scp -i "$KEY_FILE" \ - -P "$SSH_PORT" \ - -o BatchMode=yes \ - -o IdentitiesOnly=yes \ - -o StrictHostKeyChecking=yes \ - -r dist/* "$SSH_USERNAME@$TARGET_HOST:$DEPLOY_PATH/" - - ssh -i "$KEY_FILE" \ - -p "$SSH_PORT" \ - -o BatchMode=yes \ - -o IdentitiesOnly=yes \ - -o StrictHostKeyChecking=yes \ - "$SSH_USERNAME@$TARGET_HOST" \ - "test -f '$DEPLOY_PATH/index.html' && grep -F '\"version\": \"$RELEASE_VERSION\"' '$DEPLOY_PATH/version.json'" diff --git a/.github/workflows/main-validation.yml b/.github/workflows/main-validation.yml index c934c48..b667306 100644 --- a/.github/workflows/main-validation.yml +++ b/.github/workflows/main-validation.yml @@ -17,7 +17,6 @@ jobs: runs-on: ubuntu-latest outputs: frontend: ${{ steps.filter.outputs.frontend }} - frontend_v2: ${{ steps.filter.outputs.frontend_v2 }} backend: ${{ steps.filter.outputs.backend }} mcp: ${{ steps.filter.outputs.mcp }} steps: @@ -33,10 +32,6 @@ jobs: - 'apps/frontend/**' - '.github/workflows/frontend-deploy.yml' - '.github/workflows/main-validation.yml' - frontend_v2: - - 'apps/frontend-v2/**' - - '.github/workflows/frontend-v2-deploy.yml' - - '.github/workflows/main-validation.yml' backend: - 'apps/backend/**' - '.github/workflows/backend-docker-publish.yml' @@ -72,39 +67,13 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - - name: Build frontend - run: pnpm run build - - frontend-v2: - runs-on: ubuntu-latest - needs: changes - if: needs.changes.outputs.frontend_v2 == 'true' - defaults: - run: - working-directory: apps/frontend-v2 - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Install pnpm - uses: pnpm/action-setup@v6 - with: - version: 11.0.9 - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: "22" - cache: pnpm - cache-dependency-path: apps/frontend-v2/pnpm-lock.yaml - - - name: Install dependencies - run: pnpm install --frozen-lockfile + - name: Check frontend formatting + run: pnpm run format:check - - name: Lint frontend-v2 + - name: Lint frontend run: pnpm run lint - - name: Build frontend-v2 + - name: Build frontend run: pnpm run build backend: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 71ccd28..6512c6c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,7 @@ Frontend: ```bash cd apps/frontend pnpm install +pnpm format:check pnpm lint pnpm build ``` diff --git a/PLAN.md b/PLAN.md deleted file mode 100644 index 87110f8..0000000 --- a/PLAN.md +++ /dev/null @@ -1,85 +0,0 @@ -# Theme Switching And Members/Roles Integration Plan - -## Summary - -Implement local theme switching and full-stack organization member/role management in phases. Theme switching is frontend-only with `light`, `dark`, and `system` modes. Member management moves to `/organization/members` and requires backend support for returning roles, updating roles, and removing members. - -## Phase 1: Theme Foundation - -- [x] Mount `next-themes` `ThemeProvider` at the app root with class-based dark mode, `defaultTheme="system"`, `enableSystem`, and `storageKey="bitfinance-theme"`. -- [x] Replace the direct `sonner` import in `App` with the existing themed `components/ui/sonner` wrapper. -- [x] Add shared theme option constants/types for `light`, `dark`, and `system`. -- [x] Add theme labels to English and Portuguese locale files. -- [x] Verify dark mode applies through existing Tailwind `.dark` variables and fix touched chrome surfaces that are missing dark styles. - -## Phase 2: Theme Controls - -- [x] Add a theme selector to Account Preferences next to the existing language selector. -- [x] Add a quick theme submenu/radio group to the user dropdown. -- [x] Use `useTheme()` from `next-themes`; no backend persistence or user-settings API changes. -- [x] Ensure both controls reflect the same current selection and update immediately. -- [x] Verify persistence across page refreshes and system-theme changes. - -## Phase 3: Backend Member Role Contract - -- [x] Add an `OrganizationMemberResponse` model with `id`, `username`, `email`, `role`, and `joinedAt`. -- [x] Update `GET /api/v1/organizations/{organizationId}` to return member role data instead of plain `UserResponseModel`. -- [x] Add `PATCH /api/v1/organizations/{organizationId}/members/{userId}/role` with `{ role }`. -- [x] Add `DELETE /api/v1/organizations/{organizationId}/members/{userId}`. -- [x] Enforce policy: - - Owners can manage admins and members. - - Admins can invite and remove members only. - - No one can invite an owner. - - The last owner cannot be demoted or removed. -- [x] No migration is needed for roles because `organization_members.role` already exists. - -## Phase 4: Frontend API And State - -- [x] Update organization types so members require `role` and include `joinedAt`. -- [x] Remove `Owner` from invite role options; expose `Admin`/`Member` for owners and `Member` only for admins. -- [x] Add organization service methods for role update and member removal. -- [x] Add TanStack mutations for role update/removal. -- [x] Invalidate organization detail, organization list, and `auth.me` after membership changes. -- [x] Handle losing access to the currently selected organization after member removal by relying on refreshed `auth.me` and existing selected-organization reconciliation. - -## Phase 5: Dedicated Members And Roles Page - -- [x] Add protected route `/organization/members` under the dashboard layout. -- [x] Add a desktop sidebar item labeled `Members & roles` through `layouts/app-navigation.ts`. -- [x] Add matching breadcrumb and locale strings. -- [x] Move member management out of `/account/organization`; keep organization settings focused on name, budget, and overview. -- [x] Build the new page with: - - [x] selected-organization empty state, - - [x] loading/unavailable states, - - [x] current members table/list, - - [x] invite member action, - - [x] role-change dialog or inline select, - - [x] remove-member confirmation. -- [x] Disable or hide actions based on current user role and backend policy. - -## Phase 6: Cleanup And Verification - -- [x] Remove the old role-management placeholder alert from the organization settings page. -- [x] Update More page and organization switcher links only if they still describe organization member management incorrectly. -- [x] Keep invite creation and join flow behavior intact. -- [x] Ensure mobile layouts remain usable, especially member rows, dialogs, and bottom navigation. - -## Test Plan - -- Backend: - - Add tests for member role response mapping. - - Add tests for owner role updates, admin limitations, member removal, and last-owner protection. - - Run `dotnet build apps/backend/BitFinance.sln`. - - Run `dotnet test apps/backend/BitFinance.sln` after adding tests. -- Frontend: - - Run `pnpm lint` from `apps/frontend`. - - Run `pnpm build` from `apps/frontend`. - - Manually verify theme switching from Account Preferences and user menu. - - Manually verify `/organization/members` navigation, active sidebar state, member list rendering, invite roles, role updates, and member removal states. - -## Assumptions - -- Theme preference is local-only. -- The dedicated member-management route is `/organization/members`. -- Pending invitation listing and revocation are out of scope. -- Multiple owners are allowed, but at least one owner must always remain. diff --git a/README.md b/README.md index bbe9d4f..f74c287 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ BitFinance is a finance platform for tracking bills, expenses, organizations, an ## Components -- **Frontend**: React, TypeScript, Vite, Tailwind CSS, Radix UI, TanStack Query, and Zustand web application. +- **Frontend**: React 19, TypeScript, Vite, Tailwind CSS, TanStack Query, Zustand, and installable PWA support. - **Backend**: .NET API with PostgreSQL persistence, Redis caching support, object storage integration, authentication, and organization-based finance workflows. - **MCP server**: .NET Streamable HTTP MCP server that exposes BitFinance API capabilities to MCP-compatible agents and clients. diff --git a/apps/frontend-v2/.env.development.example b/apps/frontend-v2/.env.development.example deleted file mode 100644 index 12d2b02..0000000 --- a/apps/frontend-v2/.env.development.example +++ /dev/null @@ -1,2 +0,0 @@ -VITE_API_URL=http://localhost:8080/api/v1 -VITE_HEALTH_URL=http://localhost:8080/health diff --git a/apps/frontend-v2/.env.example b/apps/frontend-v2/.env.example deleted file mode 100644 index b10b4ff..0000000 --- a/apps/frontend-v2/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -VITE_API_URL=/api/v1 -VITE_HEALTH_URL=/health diff --git a/apps/frontend-v2/.env.production.example b/apps/frontend-v2/.env.production.example deleted file mode 100644 index b10b4ff..0000000 --- a/apps/frontend-v2/.env.production.example +++ /dev/null @@ -1,2 +0,0 @@ -VITE_API_URL=/api/v1 -VITE_HEALTH_URL=/health diff --git a/apps/frontend-v2/README.md b/apps/frontend-v2/README.md deleted file mode 100644 index 81082b0..0000000 --- a/apps/frontend-v2/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# BitFinance frontend v2 - -The redesigned BitFinance client. It uses typed services under `src/api`, keeps -server data in TanStack Query, and persists only the selected organization in -Zustand. The existing `apps/frontend` remains the production frontend. - -## Run locally - -```bash -cd apps/frontend-v2 -pnpm install --frozen-lockfile -cp .env.development.example .env.local -pnpm dev -``` - -The Vite server uses port `5174`. The backend must allow that origin with -credentials. Health is requested from `/health`, not `/api/v1/health`. - -## Checks - -```bash -pnpm lint -pnpm build -``` - -## Design notes - -The redesign is a “modern finance desk”: Ledger Ink, Paper, Cobalt, Mint, Amber, and Coral create a calm but legible finance workspace. Space Grotesk gives headings a deliberate voice, Figtree keeps interface copy warm, and IBM Plex Mono makes dates and amounts scan like instruments. The cash-flow timeline is the signature interaction: upcoming bills and recent expenses share one horizontal horizon. - -The app includes English and Brazilian Portuguese copy, responsive desktop/mobile -navigation, light/dark tokens, accessible focus states, reduced-motion handling, -server-backed CRUD, uploads/downloads, and explicit loading/empty/error states. - -The compiler is pinned to TypeScript 5.9.3 because the current TypeScript ESLint parser does not yet load the registry’s TypeScript 7 release; the rest of the verified tooling uses its current stable line. - -## Deployment - -Frontend v2 is released independently at -`https://bitfinance-v2.gustavomiranda.dev` while the existing frontend remains -live. See [`docs/deployment.md`](docs/deployment.md) for the release workflow, -VPS, Nginx, TLS, and verification steps. - -## Backend mapping - -See [`docs/backend-endpoints.md`](docs/backend-endpoints.md) for the 39-route -client mapping ledger and contract boundaries. diff --git a/apps/frontend-v2/docs/deployment.md b/apps/frontend-v2/docs/deployment.md deleted file mode 100644 index 01a0e64..0000000 --- a/apps/frontend-v2/docs/deployment.md +++ /dev/null @@ -1,142 +0,0 @@ -# Frontend v2 deployment - -Frontend v2 is deployed independently from the existing frontend so both can -remain live during the rollout: - -- Existing frontend: unchanged, deployed to `/var/www/bitfinance/`. -- Frontend v2: `https://bitfinance-v2.gustavomiranda.dev`, deployed to - `/var/www/bitfinance-v2/`. - -The release workflow is `.github/workflows/frontend-v2-deploy.yml`. It runs when -a `frontend-v2/v` tag is pushed and requires the tag version to match -`apps/frontend-v2/package.json`. - -## 1. Configure DNS - -Create an `A` record for `bitfinance-v2.gustavomiranda.dev` pointing to the VPS -public IPv4 address. Add an `AAAA` record only if the VPS is also configured to -serve the site over IPv6. - -Wait for the record to resolve before requesting a TLS certificate: - -```bash -dig +short bitfinance-v2.gustavomiranda.dev -``` - -## 2. Prepare the deployment directory - -On the VPS, create the v2 directory and make the GitHub Actions SSH user its -owner. Replace `` and `` with the values used by the -existing frontend deployment. - -```bash -sudo mkdir -p /var/www/bitfinance-v2 -sudo chown -R : /var/www/bitfinance-v2 -sudo chmod 0755 /var/www/bitfinance-v2 -``` - -The deployment user must be able to create files in this directory without -`sudo`. Do not change `/var/www/bitfinance/` or the existing frontend virtual -host. - -## 3. Add the Nginx virtual host - -Create a separate Nginx server block. Replace `127.0.0.1:8080` with the backend -upstream already used by the existing BitFinance virtual host. - -```nginx -server { - listen 80; - listen [::]:80; - server_name bitfinance-v2.gustavomiranda.dev; - - root /var/www/bitfinance-v2; - index index.html; - - location /api/v1/ { - proxy_pass http://127.0.0.1:8080; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location = /health { - proxy_pass http://127.0.0.1:8080/health; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location / { - try_files $uri $uri/ /index.html; - } -} -``` - -Enable the site using the same layout as the VPS's existing Nginx installation, -then validate and reload it: - -```bash -sudo nginx -t -sudo systemctl reload nginx -``` - -## 4. Enable TLS - -After DNS resolves and the HTTP virtual host is reachable, request a certificate -using the VPS's existing ACME client. With Certbot's Nginx integration: - -```bash -sudo certbot --nginx -d bitfinance-v2.gustavomiranda.dev -sudo nginx -t -sudo systemctl reload nginx -``` - -Confirm that certificate renewal is already scheduled on the VPS. - -## 5. GitHub production environment - -The v2 workflow reuses the existing `production` environment and its secrets: - -- `TS_OAUTH_CLIENT_ID` -- `TS_OAUTH_SECRET` -- `SSH_KEY` -- `SSH_HOST` -- `TAILSCALE_HOST` -- `SSH_USERNAME` -- `SSH_PORT` (optional; defaults to `22`) - -No separate API URL secret is required. The production build uses `/api/v1` and -`/health`, and Nginx proxies both paths to the shared backend on the same origin. - -## 6. Publish and verify a release - -Create the release tag from the merged `main` commit. For the initial v2 -version currently declared in `package.json`: - -```bash -git switch main -git pull --ff-only origin main -git tag frontend-v2/v0.1.0 -git push origin frontend-v2/v0.1.0 -``` - -Wait for the **Frontend v2 Release** workflow to finish, then verify the release: - -```bash -curl --fail https://bitfinance-v2.gustavomiranda.dev/version.json -curl --fail https://bitfinance-v2.gustavomiranda.dev/health -test "$(curl --silent --output /dev/null --write-out '%{http_code}' \ - https://bitfinance-v2.gustavomiranda.dev/api/v1/organizations)" = "401" -``` - -The expected `401` from the protected organizations endpoint confirms that the -request reached the backend through the v2 proxy without requiring credentials. - -Also verify in a browser that a nested v2 route survives a direct page refresh, -then test login, one authenticated API request, token refresh, and logout. Finally, -confirm the existing frontend is still available at its original URL. diff --git a/apps/frontend-v2/eslint.config.js b/apps/frontend-v2/eslint.config.js deleted file mode 100644 index a269c37..0000000 --- a/apps/frontend-v2/eslint.config.js +++ /dev/null @@ -1,19 +0,0 @@ -import js from "@eslint/js"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import tseslint from "typescript-eslint"; - -export default tseslint.config( - { ignores: ["dist", "coverage"] }, - js.configs.recommended, - ...tseslint.configs.recommended, - { - files: ["**/*.{ts,tsx}"], - plugins: { "react-hooks": reactHooks, "react-refresh": reactRefresh }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], - }, - }, -); diff --git a/apps/frontend-v2/index.html b/apps/frontend-v2/index.html deleted file mode 100644 index 4957ad8..0000000 --- a/apps/frontend-v2/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - BitFinance — finance desk - - -
- - - diff --git a/apps/frontend-v2/package.json b/apps/frontend-v2/package.json deleted file mode 100644 index cfa89c7..0000000 --- a/apps/frontend-v2/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "bitfinance-frontend-v2", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@base-ui/react": "1.6.0", - "@tanstack/react-query": "^5.101.2", - "axios": "^1.18.1", - "date-fns": "4.4.0", - "i18next": "26.3.6", - "lucide-react": "1.24.0", - "react": "19.2.7", - "react-dom": "19.2.7", - "react-i18next": "17.0.9", - "react-router-dom": "7.18.1", - "sonner": "2.0.7", - "zod": "4.4.3", - "zustand": "5.0.14" - }, - "devDependencies": { - "@eslint/js": "10.0.1", - "@tailwindcss/vite": "4.3.2", - "@types/node": "26.1.1", - "@types/react": "19.2.17", - "@types/react-dom": "19.2.3", - "@vitejs/plugin-react": "6.0.3", - "eslint": "10.6.0", - "eslint-plugin-react-hooks": "7.1.1", - "eslint-plugin-react-refresh": "0.5.3", - "tailwindcss": "4.3.2", - "typescript": "5.9.3", - "typescript-eslint": "8.63.0", - "vite": "8.1.4" - }, - "packageManager": "pnpm@11.0.9" -} diff --git a/apps/frontend-v2/pnpm-lock.yaml b/apps/frontend-v2/pnpm-lock.yaml deleted file mode 100644 index 58542a3..0000000 --- a/apps/frontend-v2/pnpm-lock.yaml +++ /dev/null @@ -1,2423 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@base-ui/react': - specifier: 1.6.0 - version: 1.6.0(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@tanstack/react-query': - specifier: ^5.101.2 - version: 5.101.2(react@19.2.7) - axios: - specifier: ^1.18.1 - version: 1.18.1 - date-fns: - specifier: 4.4.0 - version: 4.4.0 - i18next: - specifier: 26.3.6 - version: 26.3.6(typescript@5.9.3) - lucide-react: - specifier: 1.24.0 - version: 1.24.0(react@19.2.7) - react: - specifier: 19.2.7 - version: 19.2.7 - react-dom: - specifier: 19.2.7 - version: 19.2.7(react@19.2.7) - react-i18next: - specifier: 17.0.9 - version: 17.0.9(i18next@26.3.6(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) - react-router-dom: - specifier: 7.18.1 - version: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - sonner: - specifier: 2.0.7 - version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - zod: - specifier: 4.4.3 - version: 4.4.3 - zustand: - specifier: 5.0.14 - version: 5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)) - devDependencies: - '@eslint/js': - specifier: 10.0.1 - version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) - '@tailwindcss/vite': - specifier: 4.3.2 - version: 4.3.2(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)) - '@types/node': - specifier: 26.1.1 - version: 26.1.1 - '@types/react': - specifier: 19.2.17 - version: 19.2.17 - '@types/react-dom': - specifier: 19.2.3 - version: 19.2.3(@types/react@19.2.17) - '@vitejs/plugin-react': - specifier: 6.0.3 - version: 6.0.3(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)) - eslint: - specifier: 10.6.0 - version: 10.6.0(jiti@2.7.0) - eslint-plugin-react-hooks: - specifier: 7.1.1 - version: 7.1.1(eslint@10.6.0(jiti@2.7.0)) - eslint-plugin-react-refresh: - specifier: 0.5.3 - version: 0.5.3(eslint@10.6.0(jiti@2.7.0)) - tailwindcss: - specifier: 4.3.2 - version: 4.3.2 - typescript: - specifier: 5.9.3 - version: 5.9.3 - typescript-eslint: - specifier: 8.63.0 - version: 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - vite: - specifier: 8.1.4 - version: 8.1.4(@types/node@26.1.1)(jiti@2.7.0) - -packages: - - '@babel/code-frame@7.29.7': - resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.7': - resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.7': - resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.29.7': - resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.29.7': - resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.29.7': - resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.29.7': - resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-string-parser@7.29.7': - resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.29.7': - resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.29.7': - resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.7': - resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/runtime@7.29.7': - resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.29.7': - resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.7': - resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} - engines: {node: '>=6.9.0'} - - '@base-ui/react@1.6.0': - resolution: {integrity: sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@date-fns/tz': ^1.2.0 - '@types/react': ^17 || ^18 || ^19 - date-fns: ^4.0.0 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@date-fns/tz': - optional: true - '@types/react': - optional: true - date-fns: - optional: true - - '@base-ui/utils@0.3.1': - resolution: {integrity: sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg==} - peerDependencies: - '@types/react': ^17 || ^18 || ^19 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@types/react': - optional: true - - '@emnapi/core@1.11.1': - resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} - - '@emnapi/runtime@1.11.1': - resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - - '@emnapi/wasi-threads@1.2.2': - resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.23.5': - resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/config-helpers@0.6.0': - resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/core@1.2.1': - resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/js@10.0.1': - resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^10.0.0 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/object-schema@3.0.5': - resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/plugin-kit@0.7.2': - resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - - '@floating-ui/react-dom@2.1.8': - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} - engines: {node: '>=18.18.0'} - - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@napi-rs/wasm-runtime@1.1.6': - resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - - '@oxc-project/types@0.139.0': - resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} - - '@rolldown/binding-android-arm64@1.1.5': - resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.1.5': - resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.1.5': - resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.1.5': - resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.1.5': - resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.1.5': - resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.1.5': - resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.1.5': - resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.1.5': - resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.1.5': - resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.1.5': - resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.1.5': - resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.1.5': - resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.1.5': - resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.1.5': - resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - - '@tailwindcss/node@4.3.2': - resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} - - '@tailwindcss/oxide-android-arm64@4.3.2': - resolution: {integrity: sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.3.2': - resolution: {integrity: sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.3.2': - resolution: {integrity: sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.3.2': - resolution: {integrity: sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': - resolution: {integrity: sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': - resolution: {integrity: sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-arm64-musl@4.3.2': - resolution: {integrity: sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-linux-x64-gnu@4.3.2': - resolution: {integrity: sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-x64-musl@4.3.2': - resolution: {integrity: sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-wasm32-wasi@4.3.2': - resolution: {integrity: sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': - resolution: {integrity: sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.3.2': - resolution: {integrity: sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.3.2': - resolution: {integrity: sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==} - engines: {node: '>= 20'} - - '@tailwindcss/vite@4.3.2': - resolution: {integrity: sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 || ^8 - - '@tanstack/query-core@5.101.2': - resolution: {integrity: sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw==} - - '@tanstack/react-query@5.101.2': - resolution: {integrity: sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg==} - peerDependencies: - react: ^18 || ^19 - - '@tybys/wasm-util@0.10.3': - resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - - '@types/esrecurse@4.3.1': - resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/node@26.1.1': - resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.17': - resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} - - '@typescript-eslint/eslint-plugin@8.63.0': - resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.63.0 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/parser@8.63.0': - resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/project-service@8.63.0': - resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/scope-manager@8.63.0': - resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.63.0': - resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/type-utils@8.63.0': - resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/types@8.63.0': - resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.63.0': - resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/utils@8.63.0': - resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/visitor-keys@8.63.0': - resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@vitejs/plugin-react@6.0.3': - resolution: {integrity: sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 - babel-plugin-react-compiler: ^1.0.0 - vite: ^8.0.0 - peerDependenciesMeta: - '@rolldown/plugin-babel': - optional: true - babel-plugin-react-compiler: - optional: true - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - axios@1.18.1: - resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - baseline-browser-mapping@2.10.42: - resolution: {integrity: sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==} - engines: {node: '>=6.0.0'} - hasBin: true - - brace-expansion@5.0.7: - resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} - engines: {node: 18 || 20 || >=22} - - browserslist@4.28.5: - resolution: {integrity: sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - caniuse-lite@1.0.30001803: - resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie@1.1.1: - resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} - engines: {node: '>=18'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - date-fns@4.4.0: - resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - electron-to-chromium@1.5.389: - resolution: {integrity: sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==} - - enhanced-resolve@5.21.6: - resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} - engines: {node: '>=10.13.0'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.2: - resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-plugin-react-hooks@7.1.1: - resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - - eslint-plugin-react-refresh@0.5.3: - resolution: {integrity: sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==} - peerDependencies: - eslint: ^9 || ^10 - - eslint-scope@9.1.2: - resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@10.6.0: - resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@11.2.0: - resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - follow-redirects@1.16.0: - resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - form-data@4.0.6: - resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} - engines: {node: '>= 6'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.4: - resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} - engines: {node: '>= 0.4'} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - html-parse-stringify@3.0.1: - resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - i18next@26.3.6: - resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==} - peerDependencies: - typescript: ^5 || ^6 || ^7 - peerDependenciesMeta: - typescript: - optional: true - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.6: - resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} - engines: {node: '>= 4'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lucide-react@1.24.0: - resolution: {integrity: sha512-YT6mBD8lGKkg4nM39enlm94/sfJIiW0YKUT60fBy4YK8tai31ylg1VhGNWxkpSKHo9UagfnZqwIff3HTDQwXeA==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.15: - resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - node-releases@2.0.51: - resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} - engines: {node: '>=18'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.5: - resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} - engines: {node: '>=12'} - - postcss@8.5.16: - resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - proxy-from-env@2.1.0: - resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} - engines: {node: '>=10'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - react-dom@19.2.7: - resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} - peerDependencies: - react: ^19.2.7 - - react-i18next@17.0.9: - resolution: {integrity: sha512-buLzOSqHtXxjf+qgSrLWNTXVZ1jSwO6kUv3uJqSP1roGBPgNnbhFm7OmdVwWcgf2gIbUyP0J333uPyx+Btsi3w==} - peerDependencies: - i18next: '>= 26.2.0' - react: '>= 16.8.0' - react-dom: '*' - react-native: '*' - typescript: ^5 || ^6 || ^7 - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - typescript: - optional: true - - react-router-dom@7.18.1: - resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - - react-router@7.18.1: - resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - peerDependenciesMeta: - react-dom: - optional: true - - react@19.2.7: - resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} - engines: {node: '>=0.10.0'} - - reselect@5.2.0: - resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} - - rolldown@1.1.5: - resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} - engines: {node: '>=10'} - hasBin: true - - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - sonner@2.0.7: - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - tailwindcss@4.3.2: - resolution: {integrity: sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==} - - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - - tinyglobby@0.2.17: - resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} - engines: {node: '>=12.0.0'} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typescript-eslint@8.63.0: - resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@8.3.0: - resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - 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 - - vite@8.1.4: - resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.3.0 - esbuild: ^0.27.0 || ^0.28.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - void-elements@3.1.0: - resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} - engines: {node: '>=0.10.0'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - - zustand@5.0.14: - resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - -snapshots: - - '@babel/code-frame@7.29.7': - dependencies: - '@babel/helper-validator-identifier': 7.29.7 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.7': {} - - '@babel/core@7.29.7': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) - '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.7': - dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.29.7': - dependencies: - '@babel/compat-data': 7.29.7 - '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.5 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.29.7': {} - - '@babel/helper-module-imports@7.29.7': - dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': - dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.29.7': {} - - '@babel/helper-validator-identifier@7.29.7': {} - - '@babel/helper-validator-option@7.29.7': {} - - '@babel/helpers@7.29.7': - dependencies: - '@babel/template': 7.29.7 - '@babel/types': 7.29.7 - - '@babel/parser@7.29.7': - dependencies: - '@babel/types': 7.29.7 - - '@babel/runtime@7.29.7': {} - - '@babel/template@7.29.7': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - - '@babel/traverse@7.29.7': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/types': 7.29.7 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.7': - dependencies: - '@babel/helper-string-parser': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - - '@base-ui/react@1.6.0(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@babel/runtime': 7.29.7 - '@base-ui/utils': 0.3.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@floating-ui/utils': 0.2.11 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - use-sync-external-store: 1.6.0(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.17 - date-fns: 4.4.0 - - '@base-ui/utils@0.3.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@babel/runtime': 7.29.7 - '@floating-ui/utils': 0.2.11 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - reselect: 5.2.0 - use-sync-external-store: 1.6.0(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.17 - - '@emnapi/core@1.11.1': - dependencies: - '@emnapi/wasi-threads': 1.2.2 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.11.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.2': - dependencies: - tslib: 2.8.1 - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))': - dependencies: - eslint: 10.6.0(jiti@2.7.0) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.23.5': - dependencies: - '@eslint/object-schema': 3.0.5 - debug: 4.4.3 - minimatch: 10.2.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.6.0': - dependencies: - '@eslint/core': 1.2.1 - - '@eslint/core@1.2.1': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0))': - optionalDependencies: - eslint: 10.6.0(jiti@2.7.0) - - '@eslint/object-schema@3.0.5': {} - - '@eslint/plugin-kit@0.7.2': - dependencies: - '@eslint/core': 1.2.1 - levn: 0.4.1 - - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 - - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - - '@floating-ui/react-dom@2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@floating-ui/dom': 1.7.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - '@floating-ui/utils@0.2.11': {} - - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 - - '@humanfs/node@0.16.8': - dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 - '@humanwhocodes/retry': 0.4.3 - - '@humanfs/types@0.15.0': {} - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': - dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@tybys/wasm-util': 0.10.3 - optional: true - - '@oxc-project/types@0.139.0': {} - - '@rolldown/binding-android-arm64@1.1.5': - optional: true - - '@rolldown/binding-darwin-arm64@1.1.5': - optional: true - - '@rolldown/binding-darwin-x64@1.1.5': - optional: true - - '@rolldown/binding-freebsd-x64@1.1.5': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.1.5': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.1.5': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.1.5': - optional: true - - '@rolldown/binding-linux-x64-musl@1.1.5': - optional: true - - '@rolldown/binding-openharmony-arm64@1.1.5': - optional: true - - '@rolldown/binding-wasm32-wasi@1.1.5': - dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.1.5': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.1.5': - optional: true - - '@rolldown/pluginutils@1.0.1': {} - - '@tailwindcss/node@4.3.2': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.21.6 - jiti: 2.7.0 - lightningcss: 1.32.0 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.3.2 - - '@tailwindcss/oxide-android-arm64@4.3.2': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.3.2': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.3.2': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.3.2': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.3.2': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.3.2': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.3.2': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.3.2': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.3.2': - optional: true - - '@tailwindcss/oxide@4.3.2': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.3.2 - '@tailwindcss/oxide-darwin-arm64': 4.3.2 - '@tailwindcss/oxide-darwin-x64': 4.3.2 - '@tailwindcss/oxide-freebsd-x64': 4.3.2 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.2 - '@tailwindcss/oxide-linux-arm64-gnu': 4.3.2 - '@tailwindcss/oxide-linux-arm64-musl': 4.3.2 - '@tailwindcss/oxide-linux-x64-gnu': 4.3.2 - '@tailwindcss/oxide-linux-x64-musl': 4.3.2 - '@tailwindcss/oxide-wasm32-wasi': 4.3.2 - '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 - '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 - - '@tailwindcss/vite@4.3.2(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0))': - dependencies: - '@tailwindcss/node': 4.3.2 - '@tailwindcss/oxide': 4.3.2 - tailwindcss: 4.3.2 - vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0) - - '@tanstack/query-core@5.101.2': {} - - '@tanstack/react-query@5.101.2(react@19.2.7)': - dependencies: - '@tanstack/query-core': 5.101.2 - react: 19.2.7 - - '@tybys/wasm-util@0.10.3': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/esrecurse@4.3.1': {} - - '@types/estree@1.0.9': {} - - '@types/json-schema@7.0.15': {} - - '@types/node@26.1.1': - dependencies: - undici-types: 8.3.0 - - '@types/react-dom@19.2.3(@types/react@19.2.17)': - dependencies: - '@types/react': 19.2.17 - - '@types/react@19.2.17': - dependencies: - csstype: 3.2.3 - - '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/type-utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.63.0 - eslint: 10.6.0(jiti@2.7.0) - ignore: 7.0.6 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.63.0 - debug: 4.4.3 - eslint: 10.6.0(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.63.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) - '@typescript-eslint/types': 8.63.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.63.0': - dependencies: - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/visitor-keys': 8.63.0 - - '@typescript-eslint/tsconfig-utils@8.63.0(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - debug: 4.4.3 - eslint: 10.6.0(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.63.0': {} - - '@typescript-eslint/typescript-estree@8.63.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.63.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/visitor-keys': 8.63.0 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.8.5 - tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - eslint: 10.6.0(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.63.0': - dependencies: - '@typescript-eslint/types': 8.63.0 - eslint-visitor-keys: 5.0.1 - - '@vitejs/plugin-react@6.0.3(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0))': - dependencies: - '@rolldown/pluginutils': 1.0.1 - vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0) - - acorn-jsx@5.3.2(acorn@8.17.0): - dependencies: - acorn: 8.17.0 - - acorn@8.17.0: {} - - agent-base@6.0.2: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - asynckit@0.4.0: {} - - axios@1.18.1: - dependencies: - follow-redirects: 1.16.0 - form-data: 4.0.6 - https-proxy-agent: 5.0.1 - proxy-from-env: 2.1.0 - transitivePeerDependencies: - - debug - - supports-color - - balanced-match@4.0.4: {} - - baseline-browser-mapping@2.10.42: {} - - brace-expansion@5.0.7: - dependencies: - balanced-match: 4.0.4 - - browserslist@4.28.5: - dependencies: - baseline-browser-mapping: 2.10.42 - caniuse-lite: 1.0.30001803 - electron-to-chromium: 1.5.389 - node-releases: 2.0.51 - update-browserslist-db: 1.2.3(browserslist@4.28.5) - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - caniuse-lite@1.0.30001803: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - convert-source-map@2.0.0: {} - - cookie@1.1.1: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.2.3: {} - - date-fns@4.4.0: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - delayed-stream@1.0.0: {} - - detect-libc@2.1.2: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - electron-to-chromium@1.5.389: {} - - enhanced-resolve@5.21.6: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.3 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.2: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.4 - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)): - dependencies: - '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 - eslint: 10.6.0(jiti@2.7.0) - hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-refresh@0.5.3(eslint@10.6.0(jiti@2.7.0)): - dependencies: - eslint: 10.6.0(jiti@2.7.0) - - eslint-scope@9.1.2: - dependencies: - '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.9 - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@10.6.0(jiti@2.7.0): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5 - '@eslint/config-helpers': 0.6.0 - '@eslint/core': 1.2.1 - '@eslint/plugin-kit': 0.7.2 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - espree: 11.2.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.7.0 - transitivePeerDependencies: - - supports-color - - espree@11.2.0: - dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) - eslint-visitor-keys: 5.0.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fdir@6.5.0(picomatch@4.0.5): - optionalDependencies: - picomatch: 4.0.5 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - follow-redirects@1.16.0: {} - - form-data@4.0.6: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.4 - mime-types: 2.1.35 - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.4 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.2 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.4: - dependencies: - function-bind: 1.1.2 - - hermes-estree@0.25.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - html-parse-stringify@3.0.1: - dependencies: - void-elements: 3.1.0 - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - i18next@26.3.6(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 - - ignore@5.3.2: {} - - ignore@7.0.6: {} - - imurmurhash@0.1.4: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - isexe@2.0.0: {} - - jiti@2.7.0: {} - - js-tokens@4.0.0: {} - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lucide-react@1.24.0(react@19.2.7): - dependencies: - react: 19.2.7 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - math-intrinsics@1.1.0: {} - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.7 - - ms@2.1.3: {} - - nanoid@3.3.15: {} - - natural-compare@1.4.0: {} - - node-releases@2.0.51: {} - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - picocolors@1.1.1: {} - - picomatch@4.0.5: {} - - postcss@8.5.16: - dependencies: - nanoid: 3.3.15 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - proxy-from-env@2.1.0: {} - - punycode@2.3.1: {} - - react-dom@19.2.7(react@19.2.7): - dependencies: - react: 19.2.7 - scheduler: 0.27.0 - - react-i18next@17.0.9(i18next@26.3.6(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3): - dependencies: - '@babel/runtime': 7.29.7 - html-parse-stringify: 3.0.1 - i18next: 26.3.6(typescript@5.9.3) - react: 19.2.7 - use-sync-external-store: 1.6.0(react@19.2.7) - optionalDependencies: - react-dom: 19.2.7(react@19.2.7) - typescript: 5.9.3 - - react-router-dom@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-router: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - - react-router@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - cookie: 1.1.1 - react: 19.2.7 - set-cookie-parser: 2.7.2 - optionalDependencies: - react-dom: 19.2.7(react@19.2.7) - - react@19.2.7: {} - - reselect@5.2.0: {} - - rolldown@1.1.5: - dependencies: - '@oxc-project/types': 0.139.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.1.5 - '@rolldown/binding-darwin-arm64': 1.1.5 - '@rolldown/binding-darwin-x64': 1.1.5 - '@rolldown/binding-freebsd-x64': 1.1.5 - '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 - '@rolldown/binding-linux-arm64-gnu': 1.1.5 - '@rolldown/binding-linux-arm64-musl': 1.1.5 - '@rolldown/binding-linux-ppc64-gnu': 1.1.5 - '@rolldown/binding-linux-s390x-gnu': 1.1.5 - '@rolldown/binding-linux-x64-gnu': 1.1.5 - '@rolldown/binding-linux-x64-musl': 1.1.5 - '@rolldown/binding-openharmony-arm64': 1.1.5 - '@rolldown/binding-wasm32-wasi': 1.1.5 - '@rolldown/binding-win32-arm64-msvc': 1.1.5 - '@rolldown/binding-win32-x64-msvc': 1.1.5 - - scheduler@0.27.0: {} - - semver@6.3.1: {} - - semver@7.8.5: {} - - set-cookie-parser@2.7.2: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - sonner@2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - source-map-js@1.2.1: {} - - tailwindcss@4.3.2: {} - - tapable@2.3.3: {} - - tinyglobby@0.2.17: - dependencies: - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 - - ts-api-utils@2.5.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - tslib@2.8.1: - optional: true - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typescript-eslint@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) - eslint: 10.6.0(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - undici-types@8.3.0: {} - - update-browserslist-db@1.2.3(browserslist@4.28.5): - dependencies: - browserslist: 4.28.5 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - use-sync-external-store@1.6.0(react@19.2.7): - dependencies: - react: 19.2.7 - - vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0): - dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.5 - postcss: 8.5.16 - rolldown: 1.1.5 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 26.1.1 - fsevents: 2.3.3 - jiti: 2.7.0 - - void-elements@3.1.0: {} - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - yallist@3.1.1: {} - - yocto-queue@0.1.0: {} - - zod-validation-error@4.0.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - - zod@4.4.3: {} - - zustand@5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)): - optionalDependencies: - '@types/react': 19.2.17 - react: 19.2.7 - use-sync-external-store: 1.6.0(react@19.2.7) diff --git a/apps/frontend-v2/pnpm-workspace.yaml b/apps/frontend-v2/pnpm-workspace.yaml deleted file mode 100644 index 00f6fc4..0000000 --- a/apps/frontend-v2/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -allowBuilds: - esbuild: set this to true or false diff --git a/apps/frontend-v2/src/api/account/account.service.ts b/apps/frontend-v2/src/api/account/account.service.ts deleted file mode 100644 index 71313dd..0000000 --- a/apps/frontend-v2/src/api/account/account.service.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { authApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { User } from "../auth/auth.types"; - -export const accountService = { - async updateProfileAsync(firstName: string, lastName: string): Promise { - try { return (await authApi.post("/identity/manage/profile", { firstName, lastName })).data; } - catch (error) { throw normalizeApiError(error, "api.account.updateProfile"); } - }, - async uploadAvatarAsync(file: File) { - try { - const form = new FormData(); form.append("file", file); - return (await authApi.post<{ id: string; fileName: string; contentType: string }>("/identity/manage/avatar", form)).data; - } catch (error) { throw normalizeApiError(error, "api.account.uploadAvatar"); } - }, - async deleteAvatarAsync() { - try { await authApi.delete("/identity/manage/avatar"); } - catch (error) { throw normalizeApiError(error, "api.account.removeAvatar"); } - }, -}; diff --git a/apps/frontend-v2/src/api/auth/auth.service.ts b/apps/frontend-v2/src/api/auth/auth.service.ts deleted file mode 100644 index fe19da6..0000000 --- a/apps/frontend-v2/src/api/auth/auth.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { authApi, publicApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { AuthCredentials, AuthSessionResponse, RegisterCredentials, User } from "./auth.types"; -import { mapMeResponse } from "./auth.types"; - -export const authService = { - async registerAsync(credentials: RegisterCredentials): Promise { - try { return (await publicApi.post("/identity/register", credentials)).data; } - catch (error) { throw normalizeApiError(error, "api.auth.createAccount"); } - }, - async loginAsync(credentials: AuthCredentials): Promise { - try { return (await publicApi.post("/identity/login", credentials)).data; } - catch (error) { throw normalizeApiError(error, "api.auth.signIn"); } - }, - async refreshAsync(): Promise { - try { return (await publicApi.post("/identity/refresh")).data; } - catch (error) { throw normalizeApiError(error, "api.auth.restoreSession"); } - }, - async logoutAsync() { - try { await authApi.post("/identity/logout"); } - catch (error) { throw normalizeApiError(error, "api.auth.signOut"); } - }, - async logoutAllAsync() { - try { await authApi.post("/identity/logout-all"); } - catch (error) { throw normalizeApiError(error, "api.auth.signOutAll"); } - }, - async getMeAsync(): Promise { - try { return mapMeResponse((await authApi.get("/identity/me")).data); } - catch (error) { throw normalizeApiError(error, "api.auth.loadAccount"); } - }, -}; diff --git a/apps/frontend-v2/src/api/auth/auth.types.ts b/apps/frontend-v2/src/api/auth/auth.types.ts deleted file mode 100644 index 9e32cdf..0000000 --- a/apps/frontend-v2/src/api/auth/auth.types.ts +++ /dev/null @@ -1,47 +0,0 @@ -export interface OrganizationSummary { - id: string; - name: string; -} - -export interface User { - id: string; - username: string; - fullName: string; - email: string; - organizations: OrganizationSummary[]; - avatarUrl?: string | null; -} - -export interface AuthSessionResponse { - accessToken: string; - accessTokenExpiresAt: string; - user: { id: string; email: string; userName: string; firstName: string; lastName: string }; -} - -export interface AuthCredentials { - email: string; - password: string; -} - -export interface RegisterCredentials extends AuthCredentials { - firstName: string; - lastName: string; -} - -interface MeResponse { - id: string; - fullName: string; - email: string; - userName: string; - organizations?: OrganizationSummary[]; -} - -export function mapMeResponse(response: MeResponse): User { - return { - id: response.id, - username: response.userName, - fullName: response.fullName, - email: response.email, - organizations: response.organizations ?? [], - }; -} diff --git a/apps/frontend-v2/src/api/bills/bills.service.ts b/apps/frontend-v2/src/api/bills/bills.service.ts deleted file mode 100644 index 586eecb..0000000 --- a/apps/frontend-v2/src/api/bills/bills.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { authApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { Bill, BillDocument, BillInput, BillListFilters, Paged } from "./bills.types"; - -type BillWire = Omit & { category: string; status: string; billSeriesType?: string | null; billSeriesFrequency?: string | null; paymentDate?: string | null; paidDate?: string | null; attachments?: BillDocument[] }; -const normalize = (value: string) => value.toLowerCase(); -const map = (wire: BillWire): Bill => ({ ...wire, category: normalize(wire.category) as Bill["category"], status: normalize(wire.status) as Bill["status"], billSeriesType: wire.billSeriesType ? normalize(wire.billSeriesType) as Bill["billSeriesType"] : null, billSeriesFrequency: wire.billSeriesFrequency ? normalize(wire.billSeriesFrequency) as Bill["billSeriesFrequency"] : null, paymentDate: wire.paymentDate ?? wire.paidDate ?? null, documents: wire.attachments ?? [], billSeriesId: wire.billSeriesId ?? null, occurrenceNumber: wire.occurrenceNumber ?? null, totalOccurrences: wire.totalOccurrences ?? null, billSeriesIsActive: wire.billSeriesIsActive ?? false, amountPaid: wire.amountPaid ?? null }); - -export const billsService = { - async listAsync(filters: BillListFilters): Promise> { - try { - const response = await authApi.get>(`/organizations/${filters.organizationId}/bills`, { params: { page: filters.page, pageSize: filters.pageSize, from: filters.from?.toISOString(), to: filters.to?.toISOString(), status: filters.status, description: filters.description || undefined } }); - return { ...response.data, data: response.data.data.map(map) }; - } catch (error) { throw normalizeApiError(error, "api.bills.load"); } - }, - async getAsync(organizationId: string, billId: string) { - try { return map((await authApi.get(`/organizations/${organizationId}/bills/${billId}`)).data); } - catch (error) { throw normalizeApiError(error, "api.bills.loadOne"); } - }, - async createAsync(organizationId: string, input: BillInput) { - try { return map((await authApi.post(`/organizations/${organizationId}/bills`, input)).data); } - catch (error) { throw normalizeApiError(error, "api.bills.create"); } - }, - async updateAsync(organizationId: string, billId: string, input: Omit) { - try { return map((await authApi.patch(`/organizations/${organizationId}/bills/${billId}`, input)).data); } - catch (error) { throw normalizeApiError(error, "api.bills.update"); } - }, - async deleteAsync(organizationId: string, billId: string) { - try { await authApi.delete(`/organizations/${organizationId}/bills/${billId}`); } - catch (error) { throw normalizeApiError(error, "api.bills.delete"); } - }, - async uploadDocumentAsync(organizationId: string, billId: string, file: File, fileCategory: string) { - try { const form = new FormData(); form.append("file", file); form.append("fileCategory", fileCategory); return (await authApi.post(`/organizations/${organizationId}/bills/${billId}/documents`, form)).data; } - catch (error) { throw normalizeApiError(error, "api.bills.uploadDocument"); } - }, - async getDocumentAsync(organizationId: string, billId: string, documentId: string) { - try { return (await authApi.get(`/organizations/${organizationId}/bills/${billId}/documents/${documentId}`, { responseType: "blob" })).data; } - catch (error) { throw normalizeApiError(error, "api.bills.openDocument"); } - }, - async getDocumentDownloadUrlAsync(organizationId: string, billId: string, documentId: string) { - try { return (await authApi.get<{ url: string; fileName: string; contentType: string; expiresAt: string }>(`/organizations/${organizationId}/bills/${billId}/documents/${documentId}/download-url`)).data; } - catch (error) { throw normalizeApiError(error, "api.bills.prepareDownload"); } - }, - async deleteDocumentAsync(organizationId: string, billId: string, documentId: string) { - try { await authApi.delete(`/organizations/${organizationId}/bills/${billId}/documents/${documentId}`); } - catch (error) { throw normalizeApiError(error, "api.bills.removeDocument"); } - }, - async stopSeriesAsync(organizationId: string, seriesId: string) { - try { await authApi.post(`/organizations/${organizationId}/bills/series/${seriesId}/stop`); } - catch (error) { throw normalizeApiError(error, "api.bills.stopFuture"); } - }, -}; diff --git a/apps/frontend-v2/src/api/bills/bills.types.ts b/apps/frontend-v2/src/api/bills/bills.types.ts deleted file mode 100644 index 2c692c7..0000000 --- a/apps/frontend-v2/src/api/bills/bills.types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type BillCategory = "housing" | "utilities" | "food" | "transportation" | "healthcare" | "subscriptions" | "education" | "insurance" | "personal" | "taxes" | "miscellaneous" | "travel" | "gifts" | "pets" | "services"; -export type BillStatus = "created" | "upcoming" | "due" | "overdue" | "paid" | "cancelled"; -export type BillSeriesType = "recurring" | "installment"; -export type BillFrequency = "daily" | "weekly" | "monthly" | "annually"; -export type FileCategory = "Invoice" | "Receipt" | "Boleto" | "Other"; -export interface BillDocument { id: string; fileName: string; contentType: string; fileCategory: string; attachmentType: string } -export interface Bill { id: string; description: string; category: BillCategory; status: BillStatus; amountDue: number; amountPaid: number | null; dueDate: string; paymentDate: string | null; billSeriesId: string | null; occurrenceNumber: number | null; totalOccurrences: number | null; billSeriesType: BillSeriesType | null; billSeriesFrequency: BillFrequency | null; billSeriesIsActive: boolean; documents: BillDocument[] } -export interface Paged { data: T[]; page: number; pageSize: number; totalRecords: number; totalPages: number } -export interface BillListFilters { organizationId: string; page: number; pageSize: number; from?: Date; to?: Date; status?: BillStatus; description?: string } -export interface BillInput { description: string; category: BillCategory; status: BillStatus; dueDate: string; paymentDate: string | null; amountDue: number; amountPaid: number | null; frequency?: BillFrequency | null; installments?: number | null } diff --git a/apps/frontend-v2/src/api/dashboard/dashboard.service.ts b/apps/frontend-v2/src/api/dashboard/dashboard.service.ts deleted file mode 100644 index 5e54cb1..0000000 --- a/apps/frontend-v2/src/api/dashboard/dashboard.service.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { authApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { DashboardBill, DashboardExpense, DashboardSummary } from "./dashboard.types"; - -type DateFilters = { from?: Date; to?: Date }; -const params = (filters?: DateFilters) => ({ from: filters?.from?.toISOString(), to: filters?.to?.toISOString() }); -const lower = (value: string) => value.toLowerCase(); - -export const dashboardService = { - async getSummaryAsync(organizationId: string, filters?: DateFilters) { - try { return (await authApi.get(`/organizations/${organizationId}/dashboard/summary`, { params: params(filters) })).data; } - catch (error) { throw normalizeApiError(error, "api.dashboard.summary"); } - }, - async getUpcomingBillsAsync(organizationId: string, filters?: DateFilters): Promise { - try { const data = (await authApi.get<{ data: DashboardBill[] }>(`/organizations/${organizationId}/dashboard/upcoming-bills`, { params: params(filters) })).data.data; return data.map((item) => ({ ...item, category: lower(item.category), status: lower(item.status) })); } - catch (error) { throw normalizeApiError(error, "api.dashboard.upcoming"); } - }, - async getRecentExpensesAsync(organizationId: string, filters?: DateFilters): Promise { - try { const data = (await authApi.get<{ data: DashboardExpense[] }>(`/organizations/${organizationId}/dashboard/recent-expenses`, { params: params(filters) })).data.data; return data.map((item) => ({ ...item, category: lower(item.category) })); } - catch (error) { throw normalizeApiError(error, "api.dashboard.recent"); } - }, -}; diff --git a/apps/frontend-v2/src/api/dashboard/dashboard.types.ts b/apps/frontend-v2/src/api/dashboard/dashboard.types.ts deleted file mode 100644 index 88b7d90..0000000 --- a/apps/frontend-v2/src/api/dashboard/dashboard.types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface DashboardSummary { monthlyBudget: number | null; spentThisMonth: number; remainingBudget: number | null; spentPercentage: number | null; upcomingBillsAmount: number; upcomingBillsCount: number } -export interface DashboardBill { id: string; description: string; category: string; status: string; amountDue: number; createdAt: string; dueDate: string } -export interface DashboardExpense { id: string; description: string; amount: number; date: string; category: string } diff --git a/apps/frontend-v2/src/api/expenses/expenses.service.ts b/apps/frontend-v2/src/api/expenses/expenses.service.ts deleted file mode 100644 index 69cb3a9..0000000 --- a/apps/frontend-v2/src/api/expenses/expenses.service.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { authApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { Expense, ExpenseInput, ExpenseListFilters, ExpensePage } from "./expenses.types"; -import type { BillDocument } from "../bills/bills.types"; - -type ExpenseWire = Omit & { category: string; status: string; attachments?: BillDocument[] }; -const map = (wire: ExpenseWire): Expense => ({ ...wire, category: wire.category.toLowerCase() as Expense["category"], status: wire.status.toLowerCase() as Expense["status"], documents: wire.attachments ?? [] }); - -export const expensesService = { - async listAsync(filters: ExpenseListFilters): Promise { - try { const response = await authApi.get<{ data: ExpenseWire[]; page: number; pageSize: number; totalRecords: number; totalPages: number }>(`/organizations/${filters.organizationId}/expenses`, { params: { page: filters.page, pageSize: filters.pageSize, from: filters.from?.toISOString(), to: filters.to?.toISOString() } }); return { ...response.data, data: response.data.data.map(map) }; } - catch (error) { throw normalizeApiError(error, "api.expenses.load"); } - }, - async getAsync(organizationId: string, expenseId: string) { - try { return map((await authApi.get(`/organizations/${organizationId}/expenses/${expenseId}`)).data); } - catch (error) { throw normalizeApiError(error, "api.expenses.loadOne"); } - }, - async createAsync(organizationId: string, input: ExpenseInput & { createdBy: string }) { - try { return map((await authApi.post(`/organizations/${organizationId}/expenses`, input)).data); } - catch (error) { throw normalizeApiError(error, "api.expenses.create"); } - }, - async updateAsync(organizationId: string, expenseId: string, input: ExpenseInput) { - try { return map((await authApi.patch(`/organizations/${organizationId}/expenses/${expenseId}`, input)).data); } - catch (error) { throw normalizeApiError(error, "api.expenses.update"); } - }, - async deleteAsync(organizationId: string, expenseId: string) { - try { await authApi.delete(`/organizations/${organizationId}/expenses/${expenseId}`); } - catch (error) { throw normalizeApiError(error, "api.expenses.delete"); } - }, - async uploadDocumentAsync(organizationId: string, expenseId: string, file: File, fileCategory: string) { - try { const form = new FormData(); form.append("file", file); form.append("fileCategory", fileCategory); return (await authApi.post(`/organizations/${organizationId}/expenses/${expenseId}/documents`, form)).data; } - catch (error) { throw normalizeApiError(error, "api.expenses.uploadDocument"); } - }, - async getDocumentAsync(organizationId: string, expenseId: string, attachmentId: string) { - try { return (await authApi.get(`/organizations/${organizationId}/expenses/${expenseId}/documents/${attachmentId}`, { responseType: "blob" })).data; } - catch (error) { throw normalizeApiError(error, "api.expenses.openDocument"); } - }, - async deleteDocumentAsync(organizationId: string, expenseId: string, attachmentId: string) { - try { await authApi.delete(`/organizations/${organizationId}/expenses/${expenseId}/documents/${attachmentId}`); } - catch (error) { throw normalizeApiError(error, "api.expenses.removeDocument"); } - }, -}; diff --git a/apps/frontend-v2/src/api/expenses/expenses.types.ts b/apps/frontend-v2/src/api/expenses/expenses.types.ts deleted file mode 100644 index 0025a0d..0000000 --- a/apps/frontend-v2/src/api/expenses/expenses.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { BillCategory, BillDocument, Paged } from "../bills/bills.types"; -export type ExpenseCategory = BillCategory; -export type ExpenseStatus = "pending" | "paid" | "cancelled"; -export interface Expense { id: string; description: string; category: ExpenseCategory; status: ExpenseStatus; amount: number; occurredAt: string; createdBy: string; documents: BillDocument[] } -export interface ExpenseListFilters { organizationId: string; page: number; pageSize: number; from?: Date; to?: Date } -export type ExpensePage = Paged; -export interface ExpenseInput { description: string; category: ExpenseCategory; amount: number; status: ExpenseStatus; occurredAt: string; createdBy?: string } diff --git a/apps/frontend-v2/src/api/notifications/notifications.service.ts b/apps/frontend-v2/src/api/notifications/notifications.service.ts deleted file mode 100644 index d9174c1..0000000 --- a/apps/frontend-v2/src/api/notifications/notifications.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { authApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { NotificationPage, NotificationPreferences } from "./notifications.types"; - -export const notificationsService = { - async listAsync(organizationId: string): Promise { - try { return (await authApi.get(`/organizations/${organizationId}/notifications`, { params: { page: 1, pageSize: 25, unreadOnly: true } })).data; } - catch (error) { throw normalizeApiError(error, "api.notifications.load"); } - }, - async unreadCountAsync(organizationId: string): Promise { - try { return (await authApi.get<{ count: number }>(`/organizations/${organizationId}/notifications/unread-count`)).data.count; } - catch (error) { throw normalizeApiError(error, "api.notifications.load"); } - }, - async markReadAsync(organizationId: string, notificationId: string): Promise { - try { await authApi.patch(`/organizations/${organizationId}/notifications/${notificationId}/read`); } - catch (error) { throw normalizeApiError(error, "api.notifications.markRead"); } - }, - async markAllReadAsync(organizationId: string): Promise { - try { await authApi.post(`/organizations/${organizationId}/notifications/read-all`); } - catch (error) { throw normalizeApiError(error, "api.notifications.markRead"); } - }, - async getPreferencesAsync(organizationId: string): Promise { - try { return (await authApi.get(`/organizations/${organizationId}/notification-preferences`)).data; } - catch (error) { throw normalizeApiError(error, "api.notifications.loadPreferences"); } - }, - async updatePreferencesAsync(organizationId: string, enabled: boolean): Promise { - try { return (await authApi.put(`/organizations/${organizationId}/notification-preferences`, { emailBillRemindersEnabled: enabled })).data; } - catch (error) { throw normalizeApiError(error, "api.notifications.savePreferences"); } - }, -}; diff --git a/apps/frontend-v2/src/api/organizations/organizations.service.ts b/apps/frontend-v2/src/api/organizations/organizations.service.ts deleted file mode 100644 index 77eec5c..0000000 --- a/apps/frontend-v2/src/api/organizations/organizations.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { authApi } from "../shared/client"; -import { normalizeApiError } from "../shared/errors"; -import type { OrganizationSummary } from "../auth/auth.types"; -import type { Budget, InvitationResult, OrganizationDetails } from "./organizations.types"; - -export type OrganizationMemberRole = "Owner" | "Admin" | "Member"; -export type EditableOrganizationMemberRole = "Admin" | "Member"; - -export const organizationsService = { - async listAsync(): Promise { - try { return (await authApi.get("/organizations")).data; } - catch (error) { throw normalizeApiError(error, "api.organizations.load"); } - }, - async getAsync(organizationId: string): Promise { - try { return (await authApi.get(`/organizations/${organizationId}`)).data; } - catch (error) { throw normalizeApiError(error, "api.organizations.loadOne"); } - }, - async createAsync(name: string): Promise { - try { return (await authApi.post("/organizations", { name })).data; } - catch (error) { throw normalizeApiError(error, "api.organizations.create"); } - }, - async updateAsync(organizationId: string, name: string): Promise { - try { return (await authApi.patch(`/organizations/${organizationId}`, { name })).data; } - catch (error) { throw normalizeApiError(error, "api.organizations.update"); } - }, - async getBudgetAsync(organizationId: string): Promise { - try { return (await authApi.get(`/organizations/${organizationId}/budget`)).data; } - catch (error) { const normalized = normalizeApiError(error, "api.organizations.loadBudget"); if (normalized.status === 404) return null; throw normalized; } - }, - async upsertBudgetAsync(organizationId: string, amount: number): Promise { - try { return (await authApi.put(`/organizations/${organizationId}/budget`, { amount })).data; } - catch (error) { throw normalizeApiError(error, "api.organizations.saveBudget"); } - }, - async createInviteAsync(organizationId: string, email: string, role: EditableOrganizationMemberRole): Promise { - try { - const roleValue = { Admin: 2, Member: 3 }[role]; - return (await authApi.post(`/organizations/${organizationId}/invite`, { email, role: roleValue })).data; - } catch (error) { throw normalizeApiError(error, "api.organizations.createInvitation"); } - }, - async updateMemberRoleAsync(organizationId: string, userId: string, role: EditableOrganizationMemberRole): Promise { - try { await authApi.patch(`/organizations/${organizationId}/members/${userId}/role`, { role }); } - catch (error) { throw normalizeApiError(error, "api.organizations.updateRole"); } - }, - async removeMemberAsync(organizationId: string, userId: string): Promise { - try { await authApi.delete(`/organizations/${organizationId}/members/${userId}`); } - catch (error) { throw normalizeApiError(error, "api.organizations.removeMember"); } - }, - async joinAsync(token: string): Promise { - try { await authApi.post(`/organizations/join?token=${encodeURIComponent(token)}`); } - catch (error) { throw normalizeApiError(error, "api.organizations.join"); } - }, -}; diff --git a/apps/frontend-v2/src/api/organizations/organizations.types.ts b/apps/frontend-v2/src/api/organizations/organizations.types.ts deleted file mode 100644 index d84fc64..0000000 --- a/apps/frontend-v2/src/api/organizations/organizations.types.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { OrganizationSummary } from "../auth/auth.types"; -export type { OrganizationSummary } from "../auth/auth.types"; - -export interface OrganizationDetails extends OrganizationSummary { - createdAt: string; - updatedAt?: string | null; - budget: { id: string; amount: number; createdAt: string; updatedAt?: string | null } | null; - members: Array<{ - id: string; - username: string; - email: string; - role: "Owner" | "Admin" | "Member"; - joinedAt: string; - }>; -} - -export interface InvitationResult { id: string; token: string; expiresAt: string } -export interface Budget { id: string; organizationId?: string; amount: number; createdAt: string; updatedAt?: string | null } diff --git a/apps/frontend-v2/src/app.tsx b/apps/frontend-v2/src/app.tsx deleted file mode 100644 index a36ffe9..0000000 --- a/apps/frontend-v2/src/app.tsx +++ /dev/null @@ -1,421 +0,0 @@ -import { useEffect, useMemo, useRef, useState, type CSSProperties, type FormEvent, type ReactNode } from "react"; - -import { useMutation } from "@tanstack/react-query"; -import { - ArrowDownRight, ArrowRight, ArrowUpRight, Banknote, BarChart3, Building2, Check, ChevronRight, - CircleDollarSign, FilePlus2, Filter, Globe2, Home, LockKeyhole, Mail, MoreHorizontal, Plus, - ReceiptText, RotateCcw, Search, ShieldCheck, Sparkles, Settings2, SunMedium, TrendingUp, UserPlus, - UsersRound, WalletCards, -} from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { Link, Navigate, Route, Routes, useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom"; -import { toast } from "sonner"; -import { z } from "zod"; - -import type { Bill, BillCategory, BillFrequency, BillSeriesType, BillStatus, FileCategory } from "./api/bills/bills.types"; -import { billsService } from "./api/bills/bills.service"; -import type { Expense, ExpenseCategory, ExpenseStatus } from "./api/expenses/expenses.types"; -import { expensesService } from "./api/expenses/expenses.service"; -import { organizationsService } from "./api/organizations/organizations.service"; -import { useAuth } from "./auth/auth-provider"; -import { useOrganizationStore } from "./auth/auth-store"; -import { formatCurrency, formatDate, formatLongDate, inputDate, relativeDate } from "./format"; -import { useAccountMutations, useBillMutations, useBillsQuery, useBudgetQuery, useDashboardQueries, useExpenseMutations, useExpensesQuery, useNotificationMutations, useNotificationPreferencesQuery, useOrganizationMemberMutations, useOrganizationMutations, useOrganizationQuery, useBillQuery, useExpenseQuery } from "./hooks/use-queries"; -import { useDebounce } from "./hooks/use-debounce"; -import { useTheme } from "./hooks/use-theme"; -import { ActionMenu, AppShell, Avatar, Button, DataIcon, EmptyState, IconButton, KpiSparkline, MetricCard, Modal, PageContainer, PageHeader, PeriodPicker, PublicLayout, QuickAction, SectionHeading, StatusPill } from "./ui"; -import type { DashboardBill, DashboardExpense } from "./api/dashboard/dashboard.types"; - -const categoryLabels: Record = { - housing: "types.housing", utilities: "types.utilities", food: "types.food", transportation: "types.transportation", healthcare: "types.healthcare", subscriptions: "types.subscriptions", education: "types.education", insurance: "types.insurance", personal: "types.personal", taxes: "types.taxes", miscellaneous: "types.miscellaneous", travel: "types.travel", gifts: "types.gifts", pets: "types.pets", services: "types.services", -}; -const categories = Object.keys(categoryLabels) as [BillCategory, ...BillCategory[]]; -const documentCategories: FileCategory[] = ["Invoice", "Receipt", "Boleto", "Other"]; -const acceptedDocumentTypes = ".pdf,.jpg,.jpeg,.png,.doc,.docx"; -const maxDocumentSizeBytes = 10 * 1024 * 1024; -const acceptedAvatarTypes = ["image/jpeg", "image/png"]; - -function isAcceptedDocument(file: File) { - const extension = `.${file.name.split(".").pop()?.toLowerCase() ?? ""}`; - return acceptedDocumentTypes.split(",").includes(extension) && file.size <= maxDocumentSizeBytes; -} -type OrganizationMemberRole = "Owner" | "Admin" | "Member"; - -function isKnownMemberRole(role: unknown): role is OrganizationMemberRole { - return role === "Owner" || role === "Admin" || role === "Member"; -} - -function isEditableMemberRole(role: unknown): role is "Admin" | "Member" { - return role === "Admin" || role === "Member"; -} - -function useLocale() { - const { i18n } = useTranslation(); - return i18n.language === "pt-BR" ? "pt-BR" : "en-US"; -} - -function useSelectedOrganization() { - const { user } = useAuth(); - const selectedId = useOrganizationStore((state) => state.selectedOrganizationId); - const id = user?.organizations.some((organization) => organization.id === selectedId) ? selectedId : user?.organizations[0]?.id ?? null; - return id; -} - -function LoadingState({ label }: { label?: string }) { - const { t } = useTranslation(); - return
; -} - -function ErrorState({ message, onRetry }: { message: string; onRetry: () => void }) { - const { t } = useTranslation(); - return {t("errors.tryAgain")}} />; -} - -function ProtectedRoute({ children }: { children: ReactNode }) { - const { t } = useTranslation(); - const auth = useAuth(); - const location = useLocation(); - if (auth.status === "initializing") return ; - if (auth.status !== "authenticated") { - const returnTo = `${location.pathname}${location.search}`; - return ; - } - if (!auth.user?.organizations.length && location.pathname !== "/account/create-organization") return ; - return <>{children}; -} - -export function App() { - return - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - ; -} - -function HomePage() { - const { t, i18n } = useTranslation(); - const { status } = useAuth(); - const authenticated = status === "authenticated"; - return

{t("home.eyebrow")}

{t("home.title")}

{t("home.body")}

{t("home.cta")} {t("home.secondary")}
{t("home.routes", { count: 41 })}
{t("home.cashFlow")}
{t("home.available")}{formatCurrency(2940, i18n.language)} {t("home.liveData")}
0108152230
{t("home.upcomingBills")} {formatCurrency(2469.9, i18n.language)} {t("home.spentThisMonth")} {formatCurrency(2260, i18n.language)}
+{formatCurrency(320, i18n.language)}{t("home.paymentCleared")}
{t("home.readyNext")}{t("home.liveContext")}

{t("home.signal")}

{t("home.nextStep")}

01

{t("home.committed")}

{t("home.committedBody")}

02

{t("home.pattern")}

{t("home.patternBody")}

03

{t("home.shared")}

{t("home.sharedBody")}

; -} - -function safeReturnTo(value: string | null) { - return value?.startsWith("/") && !value.startsWith("//") ? value : "/dashboard"; -} - -function AuthPage({ mode }: { mode: "sign-in" | "sign-up" }) { - const { t, i18n } = useTranslation(); - const auth = useAuth(); - const navigate = useNavigate(); - const [searchParams] = useSearchParams(); - const [error, setError] = useState(""); - const [pending, setPending] = useState(false); - const isSignIn = mode === "sign-in"; - const submit = async (event: FormEvent) => { - event.preventDefault(); setError(""); - const data = new FormData(event.currentTarget); - const schema = z.object({ email: z.string().email(), password: z.string().min(isSignIn ? 1 : 8) }); - const values = { email: String(data.get("email") ?? ""), password: String(data.get("password") ?? "") }; - const parsed = schema.safeParse(values); - if (!parsed.success) { setError(isSignIn ? t("auth.validCredentials") : t("auth.validRegistration")); return; } - setPending(true); - try { - const user = await auth.signIn(isSignIn ? values : { ...values, firstName: String(data.get("firstName") ?? ""), lastName: String(data.get("lastName") ?? "") }); - toast.success(isSignIn ? t("auth.welcomeBack") : t("auth.accountCreated")); - navigate(user.organizations.length ? safeReturnTo(searchParams.get("returnTo")) : "/account/create-organization", { replace: true }); - } catch (nextError) { setError(nextError instanceof Error ? nextError.message : t("auth.unableContinue")); } - finally { setPending(false); } - }; - return

BitFinance / {t("common.financeDesk")}

{isSignIn ? t("auth.signInTitle") : t("auth.signUpTitle")}

{isSignIn ? t("auth.signInBody") : t("auth.signUpBody")}

{isSignIn ? t("auth.protectedSession") : t("auth.minimumPassword")}
BF / live
← {t("common.backHome")}
{isSignIn ? : }

01 / {isSignIn ? t("auth.signInStep") : t("auth.getStarted")}

{isSignIn ? t("common.signIn") : t("common.signUp")}

{!isSignIn &&
}{error &&

{error}

}

{isSignIn ? t("auth.noAccount") : t("auth.haveAccount")} {isSignIn ? t("common.signUp") : t("common.signIn")}

{t("auth.serverData")}
; -} - -function JoinPage() { - const { t } = useTranslation(); - const auth = useAuth(); const [params] = useSearchParams(); const token = params.get("token"); const navigate = useNavigate(); const [message, setMessage] = useState(""); - const join = useMutation({ - mutationFn: async () => { - const previousOrganizationIds = new Set(auth.user?.organizations.map((organization) => organization.id) ?? []); - await organizationsService.joinAsync(token!); - return previousOrganizationIds; - }, - onSuccess: async (previousOrganizationIds) => { - const nextUser = await auth.refreshUser(); - const joinedOrganization = nextUser.organizations.find((organization) => !previousOrganizationIds.has(organization.id)); - const selectedOrganization = joinedOrganization ?? nextUser.organizations[0]; - if (selectedOrganization) useOrganizationStore.getState().setSelectedOrganizationId(selectedOrganization.id); - toast.success(t("join.joined")); - navigate("/dashboard", { replace: true }); - }, - onError: (error) => setMessage(error instanceof Error ? error.message : t("join.invalid")), - }); - const signInUrl = `/auth/sign-in?returnTo=${encodeURIComponent(`/join-organization?token=${encodeURIComponent(token ?? "")}`)}`; - return

{t("join.eyebrow")}

{token ? t("join.title") : t("join.missingTitle")}

{token ? t("join.body") : t("join.missingBody")}

{message &&

{message}

}{auth.status === "authenticated" && token ? : {t("common.signIn")} }
; -} - -function CreateOrganizationPage() { - const { t } = useTranslation(); const auth = useAuth(); const navigate = useNavigate(); const [name, setName] = useState(""); - const create = useMutation({ mutationFn: () => organizationsService.createAsync(name.trim()), onSuccess: async (organization) => { await auth.refreshUser(); useOrganizationStore.getState().setSelectedOrganizationId(organization.id); toast.success(t("createOrganization.created")); navigate("/dashboard", { replace: true }); } }); - if (auth.status === "initializing") return ; - return

{t("createOrganization.eyebrow")}

{t("createOrganization.title")}

{t("createOrganization.body")}

{create.error &&

{create.error instanceof Error ? create.error.message : t("createOrganization.unable")}

}
; -} - -function useCurrentMonth() { - const [searchParams] = useSearchParams(); - const fromParam = searchParams.get("from"); - const toParam = searchParams.get("to"); - return useMemo(() => { - const now = new Date(); - const fallback = { from: new Date(now.getFullYear(), now.getMonth(), 1), to: new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999) }; - const parse = (value: string | null, endOfDay = false) => { - if (!value || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return null; - const date = new Date(`${value}T${endOfDay ? "23:59:59.999" : "00:00:00.000"}`); - return Number.isNaN(date.getTime()) ? null : date; - }; - const from = parse(fromParam); - const to = parse(toParam, true); - return from && to && from <= to ? { from, to } : fallback; - }, [fromParam, toParam]); -} - -function DashboardPage() { - const { t } = useTranslation(); const locale = useLocale(); const organizationId = useSelectedOrganization(); const month = useCurrentMonth(); const { user } = useAuth(); const queries = useDashboardQueries(organizationId, month.from, month.to); const summary = queries.summary.data; const upcoming = queries.upcoming.data ?? []; const recent = queries.recent.data ?? []; - if (!organizationId) return {t("dashboard.createWorkspace")}} />; - const loading = queries.summary.isPending || queries.upcoming.isPending || queries.recent.isPending; const failed = queries.summary.error || queries.upcoming.error || queries.recent.error; const name = user?.fullName.split(" ")[0] ?? t("dashboard.greetingFallback"); const budgetLabel = summary?.monthlyBudget == null ? t("dashboard.notSet") : formatCurrency(summary.monthlyBudget, locale); const spent = summary?.spentThisMonth ?? 0; const spentPercentage = summary?.spentPercentage ?? 0; - return {formatDate(month.from.toISOString(), locale)} — {formatDate(month.to.toISOString(), locale)} } />{loading && !summary ? : failed && !summary ? { void queries.summary.refetch(); void queries.upcoming.refetch(); void queries.recent.refetch(); }} /> : <>
{t("dashboard.onTrack")}

{t("dashboard.committedMoney", { amount: formatCurrency(summary?.upcomingBillsAmount ?? 0, locale) })}

{queries.upcoming.error ? { void queries.upcoming.refetch(); }} /> : }{queries.recent.error ? { void queries.recent.refetch(); }} /> :
{t("common.viewAll")} } />
{upcoming.slice(0, 3).map((bill) => {bill.description}{formatDate(bill.dueDate, locale)} · {t(categoryLabels[bill.category])}{formatCurrency(bill.amountDue, locale)})}{!upcoming.length && }
{t("common.viewAll")} } />
item.amount) : [0]} color="#23b89a" />{formatCurrency(spent, locale)}{t("common.transactionCount", { count: recent.length })}
}
}
; -} - -function categoryPercentage(items: DashboardExpense[], categoriesToCount: string[]) { const total = items.reduce((sum, item) => sum + item.amount, 0); return total ? Math.round(items.filter((item) => categoriesToCount.includes(item.category)).reduce((sum, item) => sum + item.amount, 0) / total * 100) : 0; } -function CategoryBar({ label, value, color }: { label: string; value: number; color: string }) { return
{label}{value}%
; } -function CashflowTimeline({ bills, expenses, locale }: { bills: DashboardBill[]; expenses: DashboardExpense[]; locale: string }) { const { t } = useTranslation(); const events = [...bills.map((bill) => ({ date: bill.dueDate, label: bill.description, amount: bill.amountDue, kind: "bill" as const })), ...expenses.slice(0, 3).map((expense) => ({ date: expense.date, label: expense.description, amount: expense.amount, kind: "expense" as const }))].sort((a, b) => a.date.localeCompare(b.date)); return

{t("dashboard.flow")}

{t("dashboard.flowBody")}

{t("dashboard.timelineCommitments")} {t("dashboard.timelineMoved")}
{events.map((event, index) =>
{formatDate(event.date, locale)}{event.label}{event.kind === "expense" ? "−" : ""}{formatCurrency(event.amount, locale)}
)}
{!events.length && }
; } - -function BillsPage() { - const { t } = useTranslation(); const locale = useLocale(); const organizationId = useSelectedOrganization(); const month = useCurrentMonth(); const [search, setSearch] = useState(""); const debouncedSearch = useDebounce(search); const [status, setStatus] = useState("all"); const [series, setSeries] = useState("all"); const [page, setPage] = useState(1); const [modal, setModal] = useState<"add" | "edit" | null>(null); const [selected, setSelected] = useState(null); const query = useBillsQuery(organizationId ? { organizationId, page, pageSize: 20, from: month.from, to: month.to, status: status === "all" ? undefined : status, description: debouncedSearch } : null); const mutations = useBillMutations(organizationId); const rows = (query.data?.data ?? []).filter((bill) => series === "all" || bill.billSeriesType === series); const total = rows.reduce((sum, bill) => sum + bill.amountDue, 0); const due = rows.filter((bill) => ["due", "overdue"].includes(bill.status)).reduce((sum, bill) => sum + bill.amountDue, 0); const paid = rows.filter((bill) => bill.status === "paid").reduce((sum, bill) => sum + (bill.amountPaid ?? 0), 0); const clear = () => { setSearch(""); setStatus("all"); setSeries("all"); setPage(1); }; const remove = (id: string) => { if (window.confirm(t("common.deleteBillConfirm"))) mutations.remove.mutate(id, { onSuccess: () => toast.success(t("bills.removed")), onError: (error) => toast.error(error.message) }); }; const markPaid = (bill: Bill) => mutations.update.mutate({ id: bill.id, input: { description: bill.description, category: bill.category, status: "paid", dueDate: bill.dueDate, paymentDate: new Date().toISOString(), amountDue: bill.amountDue, amountPaid: bill.amountDue } }, { onSuccess: () => toast.success(t("bills.markedPaid")), onError: (error) => toast.error(error.message) }); - const upload = async (bill: Bill, files: File[]) => { - if (files.some((file) => !isAcceptedDocument(file))) { - toast.error(t("bills.invalidFile")); - return; - } - - try { - await Promise.all(files.map((file) => mutations.upload.mutateAsync({ id: bill.id, file, category: "Other" }))); - toast.success(t("bills.uploaded")); - } catch (error) { - toast.error(error instanceof Error ? error.message : t("bills.invalidFile")); - } - }; - - if (!organizationId) return ; - return setModal("add")}> {t("bills.add")}} />
{t("bills.total")}{formatCurrency(total, locale)}
{t("bills.due")}{formatCurrency(due, locale)}
{t("bills.paid")}{formatCurrency(paid, locale)}
{(search || status !== "all" || series !== "all") && }
{query.isPending ? : query.error ? { void query.refetch(); }} /> : <>
{t("bills.commitment")}{t("bills.dueDate")}{t("bills.type")}{t("common.amount")}{t("bills.status")}
{rows.length ? rows.map((bill) => { setSelected(bill); setModal("edit"); }} onDelete={() => remove(bill.id)} onPaid={() => markPaid(bill)} onUpload={(files) => upload(bill, files)} />) : {t("common.clearFilters")}} />}}
{query.data && query.data.totalPages > 1 && }{modal === "add" && setModal(null)} organizationId={organizationId} />}{modal === "edit" && selected && { setModal(null); setSelected(null); }} organizationId={organizationId} />}
; -} - -function Pagination({ page, totalPages, onPageChange }: { page: number; totalPages: number; onPageChange: (page: number) => void }) { const { t } = useTranslation(); return
{page} / {totalPages}
; } -function BillRow({ - bill, - locale, - onDetails, - onDelete, - onPaid, - onUpload, -}: { - bill: Bill; - locale: string; - onDetails: () => void; - onDelete: () => void; - onPaid: () => void; - onUpload: (files: File[]) => Promise; -}) { - const { t } = useTranslation(); - const inputRef = useRef(null); - - return ( -
-
- - - {bill.description} - - {t(categoryLabels[bill.category])} - {bill.billSeriesType === "installment" && ` · ${t("common.installmentCount", { current: bill.occurrenceNumber, total: bill.totalOccurrences })}`} - - -
- - {formatDate(bill.dueDate, locale)} - {relativeDate(bill.dueDate, locale)} - - - {bill.billSeriesType ? ( - - - {t(`types.${bill.billSeriesType}`)} - - ) : ( - {t("common.oneTime")} - )} - - {formatCurrency(bill.amountDue, locale)} - -
- { - const files = Array.from(event.target.files ?? []); - if (files.length > 0) { - void onUpload(files); - } - event.currentTarget.value = ""; - }} - /> - inputRef.current?.click()} onDelete={onDelete} /> -
-
- ); -} - -function BillModal({ bill, onClose, organizationId }: { bill?: Bill; onClose: () => void; organizationId: string }) { const { t } = useTranslation(); const mutations = useBillMutations(organizationId); const submit = (event: FormEvent) => { event.preventDefault(); const data = new FormData(event.currentTarget); const series = String(data.get("series") ?? "one-time"); const input = { description: String(data.get("description") ?? ""), category: String(data.get("category") ?? "miscellaneous") as BillCategory, status: (bill?.status ?? "upcoming") as BillStatus, dueDate: new Date(`${String(data.get("date"))}T12:00:00.000Z`).toISOString(), paymentDate: bill?.paymentDate ?? null, amountDue: Number(data.get("amount") ?? 0), amountPaid: bill?.amountPaid ?? null, frequency: series === "one-time" ? null : String(data.get("frequency") ?? "monthly") as BillFrequency, installments: series === "installment" ? Number(data.get("installments") ?? 1) : null }; const done = () => { toast.success(bill ? t("bills.updated") : t("bills.created")); onClose(); }; if (bill) mutations.update.mutate({ id: bill.id, input }, { onSuccess: done, onError: (error) => toast.error(error.message) }); else mutations.create.mutate(input, { onSuccess: done, onError: (error) => toast.error(error.message) }); }; return
{!bill && <>}
; } - -function BillDetailsPage() { const { t } = useTranslation(); const { billId } = useParams(); const organizationId = useSelectedOrganization(); const locale = useLocale(); const query = useBillQuery(organizationId, billId); const mutations = useBillMutations(organizationId); const inputRef = useRef(null); const [fileCategory, setFileCategory] = useState("Other"); const bill = query.data; const upload = async (files: File[]) => { - if (files.some((file) => !isAcceptedDocument(file))) { - toast.error(t("bills.invalidFile")); - return; - } - - if (!billId) { - return; - } - - try { - await Promise.all(files.map((file) => mutations.upload.mutateAsync({ id: billId, file, category: fileCategory }))); - toast.success(t("bills.uploaded")); - } catch (error) { - toast.error(error instanceof Error ? error.message : t("bills.invalidFile")); - } - }; const open = async (documentId: string) => { const blob = await billsService.getDocumentAsync(organizationId!, billId!, documentId); const url = URL.createObjectURL(blob); window.open(url, "_blank", "noopener,noreferrer"); window.setTimeout(() => URL.revokeObjectURL(url), 30_000); }; const download = async (documentId: string) => { const response = await billsService.getDocumentDownloadUrlAsync(organizationId!, billId!, documentId); window.open(response.url, "_blank", "noopener,noreferrer"); }; if (query.isPending) return ; if (query.error || !bill) return { void query.refetch(); }} />; return ← {t("nav.bills")} mutations.update.mutate({ id: bill.id, input: { description: bill.description, category: bill.category, status: "paid", dueDate: bill.dueDate, paymentDate: new Date().toISOString(), amountDue: bill.amountDue, amountPaid: bill.amountDue } }, { onSuccess: () => toast.success(t("bills.markedPaid")), onError: (error) => toast.error(error.message) })}>{t("bills.markPaid")} : null} />
{t("bills.amountDue")}{formatCurrency(bill.amountDue, locale)}
{t("bills.dueDate")}
{formatLongDate(bill.dueDate, locale)}
{t("common.category")}
{t(categoryLabels[bill.category])}
{t("common.schedule")}
{bill.billSeriesType ? `${t(`types.${bill.billSeriesType}`)}${bill.billSeriesFrequency ? ` · ${t(`bills.${bill.billSeriesFrequency}`)}` : ""}` : t("common.oneTime")}
{bill.billSeriesId && bill.billSeriesIsActive && }
{ const files = Array.from(event.target.files ?? []); if (files.length > 0) void upload(files); event.currentTarget.value = ""; }} />
} />{bill.documents.length ? bill.documents.map((document) =>
{document.fileName}{t(`documents.${document.fileCategory}`)} { if (window.confirm(t("common.removeDocumentConfirm"))) mutations.removeDocument.mutate({ billId: bill.id, documentId: document.id }, { onSuccess: () => toast.success(t("bills.documentRemoved")), onError: (error) => toast.error(error.message) }); }}>
) : }
; } - -function ExpensesPage() { const { t } = useTranslation(); const locale = useLocale(); const organizationId = useSelectedOrganization(); const month = useCurrentMonth(); const { user } = useAuth(); const [search, setSearch] = useState(""); const [status, setStatus] = useState("all"); const [page, setPage] = useState(1); const [modal, setModal] = useState<"add" | "edit" | null>(null); const [selected, setSelected] = useState(null); const query = useExpensesQuery(organizationId ? { organizationId, page, pageSize: 20, from: month.from, to: month.to } : null); const mutations = useExpenseMutations(organizationId); const rows = (query.data?.data ?? []).filter((expense) => expense.description.toLowerCase().includes(search.toLowerCase()) && (status === "all" || expense.status === status)); const total = rows.reduce((sum, expense) => sum + expense.amount, 0); const remove = (id: string) => { if (window.confirm(t("common.deleteExpenseConfirm"))) mutations.remove.mutate(id, { onSuccess: () => toast.success(t("expenses.removed")), onError: (error) => toast.error(error.message) }); }; if (!organizationId || !user) return ; return setModal("add")}> {t("expenses.add")}} />
{t("expenses.total")}{formatCurrency(total, locale)}
{t("expenses.transactions")}{rows.length}
{t("expenses.average")}{formatCurrency(rows.length ? total / rows.length : 0, locale)}

{t("expenses.localFilters")}

{query.isPending ? : query.error ? { void query.refetch(); }} /> : <>
{t("expenses.expense")}{t("expenses.date")}{t("expenses.category")}{t("expenses.amount")}{t("expenses.status")}
{rows.length ? rows.map((expense) => { setSelected(expense); setModal("edit"); }} onDelete={() => remove(expense.id)} />) : }}
{query.data && query.data.totalPages > 1 && }{modal && { setModal(null); setSelected(null); }} organizationId={organizationId} userId={user.id} />}
; } -function ExpenseRow({ expense, locale, onDetails, onDelete }: { expense: Expense; locale: string; onDetails: () => void; onDelete: () => void }) { const { t } = useTranslation(); return
{expense.description}{t("expenses.added", { date: relativeDate(expense.occurredAt, locale) })}
{formatDate(expense.occurredAt, locale)}{t(categoryLabels[expense.category])}{formatCurrency(expense.amount, locale)}
; } -function ExpenseModal({ expense, onClose, organizationId, userId }: { expense?: Expense; onClose: () => void; organizationId: string; userId: string }) { const { t } = useTranslation(); const mutations = useExpenseMutations(organizationId); const submit = (event: FormEvent) => { event.preventDefault(); const data = new FormData(event.currentTarget); const input = { description: String(data.get("description") ?? ""), category: String(data.get("category") ?? "miscellaneous") as ExpenseCategory, amount: Number(data.get("amount") ?? 0), status: (expense?.status ?? "paid") as ExpenseStatus, occurredAt: new Date(`${String(data.get("date"))}T12:00:00.000Z`).toISOString() }; const done = () => { toast.success(expense ? t("expenses.updated") : t("expenses.created")); onClose(); }; if (expense) mutations.update.mutate({ id: expense.id, input }, { onSuccess: done, onError: (error) => toast.error(error.message) }); else mutations.create.mutate({ ...input, createdBy: userId }, { onSuccess: done, onError: (error) => toast.error(error.message) }); }; return
; } -function ExpenseDetailsPage() { const { t } = useTranslation(); const { expenseId } = useParams(); const organizationId = useSelectedOrganization(); const locale = useLocale(); const query = useExpenseQuery(organizationId, expenseId); const mutations = useExpenseMutations(organizationId); const inputRef = useRef(null); const [fileCategory, setFileCategory] = useState("Receipt"); const expense = query.data; const upload = (file: File) => { const valid = acceptedDocumentTypes.split(",").some((type) => file.name.toLowerCase().endsWith(type.replace(".", ""))) && file.size <= 10 * 1024 * 1024; if (!valid) { toast.error(t("bills.invalidFile")); return; } if (expenseId) mutations.upload.mutate({ id: expenseId, file, category: fileCategory }, { onSuccess: () => toast.success(t("bills.uploaded")), onError: (error) => toast.error(error.message) }); }; const open = async (documentId: string) => { const blob = await expensesService.getDocumentAsync(organizationId!, expenseId!, documentId); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = "expense-document"; link.click(); window.setTimeout(() => URL.revokeObjectURL(url), 30_000); }; if (query.isPending) return ; if (query.error || !expense) return { void query.refetch(); }} />; return ← {t("nav.expenses")}
{t("expenses.amount")}{formatCurrency(expense.amount, locale)}
{t("expenses.occurred")}
{formatLongDate(expense.occurredAt, locale)}
{t("common.category")}
{t(categoryLabels[expense.category])}
{t("expenses.createdBy")}
{expense.createdBy}
{ const file = event.target.files?.[0]; if (file) upload(file); event.currentTarget.value = ""; }} />
} />{expense.documents.length ? expense.documents.map((document) =>
{document.fileName}{t(`documents.${document.fileCategory}`)} { if (window.confirm(t("common.removeDocumentConfirm"))) mutations.removeDocument.mutate({ expenseId: expense.id, attachmentId: document.id }, { onSuccess: () => toast.success(t("bills.documentRemoved")), onError: (error) => toast.error(error.message) }); }}>
) : }
; } - -// The form mirrors a newly selected server record; this synchronization is intentional. -// eslint-disable-next-line react-hooks/set-state-in-effect -function OrganizationPage() { const { t } = useTranslation(); const locale = useLocale(); const organizationId = useSelectedOrganization(); const detail = useOrganizationQuery(organizationId); const budgetQuery = useBudgetQuery(organizationId); const mutations = useOrganizationMutations(organizationId); const [name, setName] = useState(""); const [budget, setBudget] = useState(""); useEffect(() => { if (detail.data) { setName(detail.data.name); setBudget(String(budgetQuery.data?.amount ?? detail.data.budget?.amount ?? "")); } }, [budgetQuery.data, detail.data]); if (!organizationId || detail.isPending) return ; if (detail.error || !detail.data) return { void detail.refetch(); }} />; const organization = detail.data; const budgetData = budgetQuery.data !== undefined ? budgetQuery.data : organization.budget; return {t("nav.members")}} />

{t("organization.active")}

{organization.name}

{t("organization.created", { date: formatLongDate(organization.createdAt, locale) })}

{t("common.active")}
{ event.preventDefault(); mutations.update.mutate(name, { onSuccess: () => toast.success(t("organization.settingsSaved")), onError: (error) => toast.error(error.message) }); }}>
{t("organization.monthlyLimit")}{budgetData ? formatCurrency(budgetData.amount, locale) : t("organization.notConfigured")}
{ event.preventDefault(); mutations.budget.mutate(Number(budget), { onSuccess: () => toast.success(t("organization.budgetSaved")), onError: (error) => toast.error(error.message) }); }}> setBudget(event.target.value)} />
{t("organization.dashboardUpdate")}
{t("organization.manageMembers")} } />
{organization.members.slice(0, 3).map((member) =>
{member.username}{member.email}
)}
; } - -function MembersPage() { - const { t } = useTranslation(); - const locale = useLocale(); - const auth = useAuth(); - const navigate = useNavigate(); - const organizationId = useSelectedOrganization(); - const detail = useOrganizationQuery(organizationId); - const memberMutations = useOrganizationMemberMutations(organizationId); - const [inviteOpen, setInviteOpen] = useState(false); - const [invite, setInvite] = useState<{ url: string; expiresAt: string } | null>(null); - const currentMember = detail.data?.members.find((member) => member.id === auth.user?.id); - const currentRole = isKnownMemberRole(currentMember?.role) ? currentMember.role : undefined; - const inviteRoles: Array<"Admin" | "Member"> = currentRole === "Owner" ? ["Admin", "Member"] : ["Member"]; - const canInvite = currentRole === "Owner" || currentRole === "Admin"; - const createInvite = useMutation({ - mutationFn: ({ email, role }: { email: string; role: "Admin" | "Member" }) => organizationsService.createInviteAsync(organizationId!, email, role), - onSuccess: (result) => { - setInvite({ url: `${window.location.origin}/join-organization?token=${encodeURIComponent(result.token)}`, expiresAt: result.expiresAt }); - setInviteOpen(false); - toast.success(t("organization.invitationCreated")); - }, - onError: (error) => toast.error(error instanceof Error ? error.message : t("organization.invitationError")), - }); - - if (!organizationId || detail.isPending) return ; - if (detail.error || !detail.data) return { void detail.refetch(); }} />; - - const copy = async () => { - if (invite) { - await navigator.clipboard.writeText(invite.url); - toast.success(t("organization.invitationCopied")); - } - }; - const canChangeRole = (member: typeof detail.data.members[number]) => currentRole === "Owner" && isEditableMemberRole(member.role); - const canRemove = (member: typeof detail.data.members[number]) => member.id === auth.user?.id || (currentRole === "Owner" && isEditableMemberRole(member.role)) || (currentRole === "Admin" && member.role === "Member"); - const removeMember = (member: typeof detail.data.members[number]) => { - const isSelf = member.id === auth.user?.id; - const confirmed = window.confirm(isSelf ? t("common.leaveOrganizationConfirm") : t("common.removeMemberConfirm", { name: member.username })); - if (!confirmed) return; - memberMutations.remove.mutate(member.id, { - onSuccess: async () => { - if (!isSelf) { - toast.success(t("organization.memberRemoved")); - return; - } - const nextUser = await auth.refreshUser(); - const nextOrganization = nextUser.organizations.find((organization) => organization.id !== organizationId); - useOrganizationStore.getState().setSelectedOrganizationId(nextOrganization?.id ?? null); - toast.success(t("organization.left")); - navigate(nextOrganization ? "/dashboard" : "/account/create-organization", { replace: true }); - }, - onError: (error) => toast.error(error instanceof Error ? error.message : t("organization.removeError")), - }); - }; - - return - setInviteOpen(true)}> {t("common.invite")} : undefined} /> -
-
{t("organization.accessOverview")}{t("common.peopleCount", { count: detail.data.members.length })}

{t("organization.everyoneAccess")}

{t("organization.protected")}
-
{detail.data.members.map((member) => { - const role = isKnownMemberRole(member.role) ? member.role : null; - const roleClass = role ? role.toLowerCase() : "unknown"; - return
- - {member.username}{member.email} - {role ? t(`roles.${role}`) : t("organization.roleUnavailable")} - {member.joinedAt ? t("common.joined", { date: formatLongDate(member.joinedAt, locale) }) : t("organization.joinedUnavailable")} - {(canChangeRole(member) || canRemove(member)) &&
- {canChangeRole(member) && } - {canRemove(member) && } -
} -
; - })}
-
- {invite &&
{ void copy(); }}>{t("common.copy")}} />
} - {inviteOpen && canInvite && setInviteOpen(false)}>
{ event.preventDefault(); const data = new FormData(event.currentTarget); createInvite.mutate({ email: String(data.get("email")), role: String(data.get("role")) as "Admin" | "Member" }); }}>
} -
; -} - -function AccountPage() { - const { t, i18n } = useTranslation(); const auth = useAuth(); const navigate = useNavigate(); const mutations = useAccountMutations(); const user = auth.user; - const organizationId = useSelectedOrganization(); const notificationPreferences = useNotificationPreferencesQuery(organizationId); const notificationMutations = useNotificationMutations(organizationId); - const [firstName, setFirstName] = useState(user?.fullName.split(" ")[0] ?? ""); const [lastName, setLastName] = useState(user?.fullName.split(" ").slice(1).join(" ") ?? ""); - const { theme, setTheme } = useTheme(); const avatarInput = useRef(null); - if (!user) return null; - const save = async (event: FormEvent) => { event.preventDefault(); try { await mutations.profile.mutateAsync({ firstName, lastName }); await auth.refreshUser(); toast.success(t("account.profileSaved")); } catch (error) { toast.error(error instanceof Error ? error.message : t("account.unableSave")); } }; - const upload = async (file: File) => { - if (!acceptedAvatarTypes.includes(file.type) || file.size > 2 * 1024 * 1024) { toast.error(t("account.invalidAvatar")); return; } - try { - await mutations.avatar.mutateAsync(file); - // The backend has no avatar-read endpoint, so the object URL is session-local. - auth.setAvatarPreview(file); - await auth.refreshUser(); - toast.success(t("account.avatarUpdated")); - } catch (error) { toast.error(error instanceof Error ? error.message : t("account.unableUpload")); } - }; - return
{user.fullName}{user.email}
{ const file = event.target.files?.[0]; if (file) void upload(file); event.currentTarget.value = ""; }} />
{ void save(event); }}>
{t("account.language")}{t("account.languageDescription")}
{t("account.theme")}{t("account.themeDescription")}
{t("account.billReminderEmails")}{notificationPreferences.data?.emailAvailable ? t("account.billReminderEmailsDescription") : t("account.billReminderEmailsUpgrade")}
; -} -function MorePage() { const { t } = useTranslation(); return
; } -function NotFoundPage() { const { t } = useTranslation(); return

{t("common.notFound")}

{t("common.pageMoved")}

{t("common.findFinanceDesk")}

{t("common.backToDesk")}
; } diff --git a/apps/frontend-v2/src/auth/auth-provider.tsx b/apps/frontend-v2/src/auth/auth-provider.tsx deleted file mode 100644 index f196db4..0000000 --- a/apps/frontend-v2/src/auth/auth-provider.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; -import { useQueryClient } from "@tanstack/react-query"; - -import { authService } from "../api/auth/auth.service"; -import type { AuthCredentials, RegisterCredentials, User } from "../api/auth/auth.types"; -import { setSessionExpiredListener } from "../api/shared/session-events"; -import { clearAccessToken, setAccessToken } from "../lib/auth-token"; -import { queryKeys } from "../lib/query-keys"; -import { useOrganizationStore } from "./auth-store"; - -type AuthStatus = "initializing" | "authenticated" | "unauthenticated"; -interface AuthContextValue { status: AuthStatus; user: User | null; signIn: (credentials: AuthCredentials | RegisterCredentials) => Promise; refreshUser: () => Promise; setAvatarPreview: (file: File) => void; clearAvatarPreview: () => void; signOut: (allDevices?: boolean) => Promise } -const AuthContext = createContext(null); - -function selectInitialOrganization(user: User) { - const current = useOrganizationStore.getState().selectedOrganizationId; - const valid = user.organizations.some((organization) => organization.id === current); - useOrganizationStore.getState().setSelectedOrganizationId(valid ? current : user.organizations[0]?.id ?? null); -} - -export function AuthProvider({ children }: { children: ReactNode }) { - const queryClient = useQueryClient(); - const [status, setStatus] = useState("initializing"); - const [user, setUser] = useState(null); - const avatarPreviewRef = useRef(null); - - const clearAvatarPreview = useCallback(() => { - if (avatarPreviewRef.current) URL.revokeObjectURL(avatarPreviewRef.current); - avatarPreviewRef.current = null; - setUser((current) => current ? { ...current, avatarUrl: null } : current); - }, []); - - const setAvatarPreview = useCallback((file: File) => { - if (avatarPreviewRef.current) URL.revokeObjectURL(avatarPreviewRef.current); - const nextPreview = URL.createObjectURL(file); - avatarPreviewRef.current = nextPreview; - setUser((current) => current ? { ...current, avatarUrl: nextPreview } : current); - }, []); - - const refreshUser = useCallback(async () => { - const next = await authService.getMeAsync(); - const withPreview = { ...next, avatarUrl: avatarPreviewRef.current }; - setUser(withPreview); selectInitialOrganization(withPreview); setStatus("authenticated"); - queryClient.setQueryData(queryKeys.auth.me(), withPreview); - return withPreview; - }, [queryClient]); - - useEffect(() => { - const expire = () => { clearAccessToken(); clearAvatarPreview(); setUser(null); setStatus("unauthenticated"); void queryClient.clear(); }; - setSessionExpiredListener(expire); - void authService.refreshAsync().then((session) => { setAccessToken(session.accessToken, session.accessTokenExpiresAt); return refreshUser(); }).catch(expire); - return () => setSessionExpiredListener(null); - }, [clearAvatarPreview, queryClient, refreshUser]); - - const value = useMemo(() => ({ - status, user, - signIn: async (credentials) => { - const session = "firstName" in credentials ? await authService.registerAsync(credentials) : await authService.loginAsync(credentials); - setAccessToken(session.accessToken, session.accessTokenExpiresAt); - return refreshUser(); - }, - refreshUser, - setAvatarPreview, - clearAvatarPreview, - signOut: async (allDevices = false) => { - try { await authService[allDevices ? "logoutAllAsync" : "logoutAsync"](); } finally { clearAccessToken(); clearAvatarPreview(); setUser(null); setStatus("unauthenticated"); useOrganizationStore.getState().setSelectedOrganizationId(null); await queryClient.clear(); } - }, - }), [clearAvatarPreview, queryClient, refreshUser, setAvatarPreview, status, user]); - - useEffect(() => () => { - if (avatarPreviewRef.current) URL.revokeObjectURL(avatarPreviewRef.current); - }, []); - - return {children}; -} - -// This hook intentionally shares the provider's context for the app shell and routes. -// eslint-disable-next-line react-refresh/only-export-components -export function useAuth() { - const value = useContext(AuthContext); - if (!value) throw new Error("useAuth must be used inside AuthProvider"); - return value; -} diff --git a/apps/frontend-v2/src/auth/auth-store.ts b/apps/frontend-v2/src/auth/auth-store.ts deleted file mode 100644 index 42889b1..0000000 --- a/apps/frontend-v2/src/auth/auth-store.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { create } from "zustand"; -import { persist } from "zustand/middleware"; - -interface OrganizationState { selectedOrganizationId: string | null; setSelectedOrganizationId: (id: string | null) => void } - -export const useOrganizationStore = create()(persist((set) => ({ - selectedOrganizationId: null, - setSelectedOrganizationId: (selectedOrganizationId) => set({ selectedOrganizationId }), -}), { name: "bitfinance-v2-preferences", partialize: (state) => ({ selectedOrganizationId: state.selectedOrganizationId }) })); diff --git a/apps/frontend-v2/src/base-action-menu.tsx b/apps/frontend-v2/src/base-action-menu.tsx deleted file mode 100644 index 9d97395..0000000 --- a/apps/frontend-v2/src/base-action-menu.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Menu as BaseMenu } from "@base-ui/react/menu"; -import { ArrowUpRight, CircleDollarSign, FilePlus2, MoreHorizontal, RotateCcw, Settings2 } from "lucide-react"; -import { useNavigate } from "react-router-dom"; -import { useTranslation } from "react-i18next"; - -export function BaseActionMenu({ onEdit, onPaid, onDelete, onUpload, detailHref, canPay = false }: { onEdit: () => void; onPaid?: () => void; onDelete: () => void; onUpload?: () => void; detailHref?: string; canPay?: boolean }) { - const navigate = useNavigate(); - const { t } = useTranslation(); - return {t("common.edit")} {t("common.details")}{canPay && onPaid && {t("bills.markPaid")}}{detailHref && navigate(detailHref)}> {t("common.viewDetails")}}{onUpload && {t("common.addFile")}} {t("common.delete")}; -} diff --git a/apps/frontend-v2/src/env.ts b/apps/frontend-v2/src/env.ts deleted file mode 100644 index 5c53feb..0000000 --- a/apps/frontend-v2/src/env.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from "zod"; - -const envSchema = z.object({ - VITE_API_URL: z.string().url().or(z.string().startsWith("/")), - VITE_HEALTH_URL: z.string().url().or(z.string().startsWith("/")), -}); - -const parsed = envSchema.safeParse({ - VITE_API_URL: import.meta.env.VITE_API_URL ?? "/api/v1", - VITE_HEALTH_URL: import.meta.env.VITE_HEALTH_URL ?? "/health", -}); - -if (!parsed.success) { - throw new Error(`Invalid frontend environment: ${parsed.error.message}`); -} - -export const env = parsed.data; diff --git a/apps/frontend-v2/src/format.ts b/apps/frontend-v2/src/format.ts deleted file mode 100644 index 33e65bb..0000000 --- a/apps/frontend-v2/src/format.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { format, formatDistanceToNow } from "date-fns"; -import { ptBR } from "date-fns/locale"; - -export function formatCurrency(value: number, locale = "en-US") { - return new Intl.NumberFormat(locale, { style: "currency", currency: locale === "pt-BR" ? "BRL" : "USD", maximumFractionDigits: 2 }).format(value); -} - -export function formatDate(value: string, locale = "en-US") { - return new Intl.DateTimeFormat(locale, { month: "short", day: "numeric" }).format(new Date(value)); -} - -export function formatLongDate(value: string, locale = "en-US") { - return new Intl.DateTimeFormat(locale, { month: "long", day: "numeric", year: "numeric" }).format(new Date(value)); -} - -export function relativeDate(value: string, locale = "en-US") { - return formatDistanceToNow(new Date(value), { addSuffix: true, locale: locale === "pt-BR" ? ptBR : undefined }); -} - -export function inputDate(value: string) { - return format(new Date(value), "yyyy-MM-dd"); -} - -export function initials(firstName: string, lastName: string) { - return `${firstName[0] ?? ""}${lastName[0] ?? ""}`.toUpperCase(); -} diff --git a/apps/frontend-v2/src/hooks/use-debounce.ts b/apps/frontend-v2/src/hooks/use-debounce.ts deleted file mode 100644 index d6a67a6..0000000 --- a/apps/frontend-v2/src/hooks/use-debounce.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useEffect, useState } from "react"; - -export function useDebounce(value: T, delay = 300) { - const [debounced, setDebounced] = useState(value); - useEffect(() => { const timer = window.setTimeout(() => setDebounced(value), delay); return () => window.clearTimeout(timer); }, [value, delay]); - return debounced; -} diff --git a/apps/frontend-v2/src/hooks/use-queries.ts b/apps/frontend-v2/src/hooks/use-queries.ts deleted file mode 100644 index ef61f58..0000000 --- a/apps/frontend-v2/src/hooks/use-queries.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; - -import { accountService } from "../api/account/account.service"; -import { authService } from "../api/auth/auth.service"; -import { billsService } from "../api/bills/bills.service"; -import { dashboardService } from "../api/dashboard/dashboard.service"; -import { expensesService } from "../api/expenses/expenses.service"; -import { healthService } from "../api/health/health.service"; -import { organizationsService } from "../api/organizations/organizations.service"; -import { notificationsService } from "../api/notifications/notifications.service"; -import type { BillInput, BillListFilters } from "../api/bills/bills.types"; -import type { ExpenseInput, ExpenseListFilters } from "../api/expenses/expenses.types"; -import type { EditableOrganizationMemberRole } from "../api/organizations/organizations.service"; -import { queryKeys } from "../lib/query-keys"; - -export function useHealthQuery() { return useQuery({ queryKey: queryKeys.health.all, queryFn: healthService.getAsync, retry: 0, staleTime: 60_000 }); } -export function useOrganizationsQuery(enabled = true) { return useQuery({ queryKey: queryKeys.organizations.list(), queryFn: organizationsService.listAsync, enabled }); } -export function useOrganizationQuery(organizationId: string | null) { return useQuery({ queryKey: queryKeys.organizations.detail(organizationId ?? ""), queryFn: () => organizationsService.getAsync(organizationId!), enabled: Boolean(organizationId) }); } -export function useBudgetQuery(organizationId: string | null) { return useQuery({ queryKey: queryKeys.organizations.budget(organizationId ?? ""), queryFn: () => organizationsService.getBudgetAsync(organizationId!), enabled: Boolean(organizationId) }); } -export function useDashboardQueries(organizationId: string | null, from?: Date, to?: Date) { - const enabled = Boolean(organizationId); - return { - summary: useQuery({ queryKey: queryKeys.dashboard.summary(organizationId ?? "", from, to), queryFn: () => dashboardService.getSummaryAsync(organizationId!, { from, to }), enabled }), - upcoming: useQuery({ queryKey: queryKeys.dashboard.upcoming(organizationId ?? "", from, to), queryFn: () => dashboardService.getUpcomingBillsAsync(organizationId!, { from, to }), enabled }), - recent: useQuery({ queryKey: queryKeys.dashboard.recent(organizationId ?? "", from, to), queryFn: () => dashboardService.getRecentExpensesAsync(organizationId!, { from, to }), enabled }), - }; -} -export function useBillsQuery(filters: BillListFilters | null) { return useQuery({ queryKey: filters ? queryKeys.bills.list(filters.organizationId, filters.page, filters.pageSize, filters.from, filters.to, filters.status, filters.description) : ["bills", "disabled"], queryFn: () => billsService.listAsync(filters!), enabled: Boolean(filters) }); } -export function useBillQuery(organizationId: string | null, billId?: string) { return useQuery({ queryKey: queryKeys.bills.detail(organizationId ?? "", billId ?? ""), queryFn: () => billsService.getAsync(organizationId!, billId!), enabled: Boolean(organizationId && billId) }); } -export function useExpensesQuery(filters: ExpenseListFilters | null) { return useQuery({ queryKey: filters ? queryKeys.expenses.list(filters.organizationId, filters.page, filters.pageSize, filters.from, filters.to) : ["expenses", "disabled"], queryFn: () => expensesService.listAsync(filters!), enabled: Boolean(filters) }); } -export function useExpenseQuery(organizationId: string | null, expenseId?: string) { return useQuery({ queryKey: queryKeys.expenses.detail(organizationId ?? "", expenseId ?? ""), queryFn: () => expensesService.getAsync(organizationId!, expenseId!), enabled: Boolean(organizationId && expenseId) }); } -export function useNotificationsQuery(organizationId: string | null, enabled = true) { return useQuery({ queryKey: queryKeys.notifications.list(organizationId ?? ""), queryFn: () => notificationsService.listAsync(organizationId!), enabled: Boolean(organizationId) && enabled, refetchInterval: 60_000 }); } -export function useNotificationUnreadCountQuery(organizationId: string | null) { return useQuery({ queryKey: queryKeys.notifications.unread(organizationId ?? ""), queryFn: () => notificationsService.unreadCountAsync(organizationId!), enabled: Boolean(organizationId), refetchInterval: 60_000 }); } -export function useNotificationPreferencesQuery(organizationId: string | null) { return useQuery({ queryKey: queryKeys.notifications.preferences(organizationId ?? ""), queryFn: () => notificationsService.getPreferencesAsync(organizationId!), enabled: Boolean(organizationId) }); } -export function useNotificationMutations(organizationId: string | null) { - const client = useQueryClient(); - const invalidate = () => void client.invalidateQueries({ queryKey: queryKeys.notifications.all }); - return { - markRead: useMutation({ mutationFn: (notificationId: string) => notificationsService.markReadAsync(organizationId!, notificationId), onSuccess: invalidate }), - markAllRead: useMutation({ mutationFn: () => notificationsService.markAllReadAsync(organizationId!), onSuccess: invalidate }), - updatePreferences: useMutation({ mutationFn: (enabled: boolean) => notificationsService.updatePreferencesAsync(organizationId!, enabled), onSuccess: invalidate }), - }; -} - -export function useOrganizationMutations(organizationId: string | null) { - const client = useQueryClient(); - const invalidate = () => { void client.invalidateQueries({ queryKey: queryKeys.organizations.all }); void client.invalidateQueries({ queryKey: queryKeys.auth.me() }); void client.invalidateQueries({ queryKey: queryKeys.dashboard.all }); }; - const update = useMutation({ mutationFn: (name: string) => organizationsService.updateAsync(organizationId!, name), onSuccess: invalidate }); - const budget = useMutation({ mutationFn: (amount: number) => organizationsService.upsertBudgetAsync(organizationId!, amount), onSuccess: () => { invalidate(); void client.invalidateQueries({ queryKey: queryKeys.organizations.budget(organizationId!) }); } }); - return { update, budget }; -} -export function useOrganizationMemberMutations(organizationId: string | null) { - const client = useQueryClient(); - const invalidate = () => { - void client.invalidateQueries({ queryKey: queryKeys.organizations.all }); - void client.invalidateQueries({ queryKey: queryKeys.auth.me() }); - }; - return { - updateRole: useMutation({ - mutationFn: ({ userId, role }: { userId: string; role: EditableOrganizationMemberRole }) => organizationsService.updateMemberRoleAsync(organizationId!, userId, role), - onSuccess: invalidate, - }), - remove: useMutation({ - mutationFn: (userId: string) => organizationsService.removeMemberAsync(organizationId!, userId), - onSuccess: invalidate, - }), - }; -} -export function useAccountMutations() { - const client = useQueryClient(); - const invalidate = () => void client.invalidateQueries({ queryKey: queryKeys.auth.me() }); - return { profile: useMutation({ mutationFn: ({ firstName, lastName }: { firstName: string; lastName: string }) => accountService.updateProfileAsync(firstName, lastName), onSuccess: invalidate }), avatar: useMutation({ mutationFn: accountService.uploadAvatarAsync, onSuccess: invalidate }), deleteAvatar: useMutation({ mutationFn: accountService.deleteAvatarAsync, onSuccess: invalidate }), logoutAll: useMutation({ mutationFn: authService.logoutAllAsync }) }; -} -export function useBillMutations(organizationId: string | null) { - const client = useQueryClient(); - const invalidate = () => { void client.invalidateQueries({ queryKey: queryKeys.bills.all }); void client.invalidateQueries({ queryKey: queryKeys.dashboard.all }); }; - return { create: useMutation({ mutationFn: (input: BillInput) => billsService.createAsync(organizationId!, input), onSuccess: invalidate }), update: useMutation({ mutationFn: ({ id, input }: { id: string; input: Omit }) => billsService.updateAsync(organizationId!, id, input), onSuccess: invalidate }), remove: useMutation({ mutationFn: (id: string) => billsService.deleteAsync(organizationId!, id), onSuccess: invalidate }), upload: useMutation({ mutationFn: ({ id, file, category }: { id: string; file: File; category: string }) => billsService.uploadDocumentAsync(organizationId!, id, file, category), onSuccess: invalidate }), removeDocument: useMutation({ mutationFn: ({ billId, documentId }: { billId: string; documentId: string }) => billsService.deleteDocumentAsync(organizationId!, billId, documentId), onSuccess: invalidate }), stopSeries: useMutation({ mutationFn: (seriesId: string) => billsService.stopSeriesAsync(organizationId!, seriesId), onSuccess: invalidate }) }; -} -export function useExpenseMutations(organizationId: string | null) { - const client = useQueryClient(); - const invalidate = () => { void client.invalidateQueries({ queryKey: queryKeys.expenses.all }); void client.invalidateQueries({ queryKey: queryKeys.dashboard.all }); }; - return { create: useMutation({ mutationFn: (input: ExpenseInput & { createdBy: string }) => expensesService.createAsync(organizationId!, input), onSuccess: invalidate }), update: useMutation({ mutationFn: ({ id, input }: { id: string; input: ExpenseInput }) => expensesService.updateAsync(organizationId!, id, input), onSuccess: invalidate }), remove: useMutation({ mutationFn: (id: string) => expensesService.deleteAsync(organizationId!, id), onSuccess: invalidate }), upload: useMutation({ mutationFn: ({ id, file, category }: { id: string; file: File; category: string }) => expensesService.uploadDocumentAsync(organizationId!, id, file, category), onSuccess: invalidate }), removeDocument: useMutation({ mutationFn: ({ expenseId, attachmentId }: { expenseId: string; attachmentId: string }) => expensesService.deleteDocumentAsync(organizationId!, expenseId, attachmentId), onSuccess: invalidate }) }; -} diff --git a/apps/frontend-v2/src/i18n.ts b/apps/frontend-v2/src/i18n.ts deleted file mode 100644 index 446f862..0000000 --- a/apps/frontend-v2/src/i18n.ts +++ /dev/null @@ -1,72 +0,0 @@ -import i18next from "i18next"; -import { initReactI18next } from "react-i18next"; - -export const resources = { - "en-US": { translation: { - meta: { title: "BitFinance — finance desk", description: "BitFinance — a clearer view of your money." }, - nav: { overview: "Overview", bills: "Bills", expenses: "Expenses", organization: "Organization", members: "Members", account: "Account" }, - common: { - save: "Save changes", cancel: "Cancel", close: "Close", add: "Add", edit: "Edit", delete: "Delete", search: "Search", all: "All", today: "Today", viewAll: "View all", loading: "Loading", noResults: "No results", clearFilters: "Clear filters", signIn: "Sign in", signUp: "Create account", continue: "Continue", invite: "Invite member", copy: "Copy invite link", update: "Update", open: "Open", download: "Download", remove: "Remove", apply: "Apply", previous: "Previous", next: "Next", actions: "Actions", more: "More", details: "details", viewDetails: "View details", backHome: "Back to home", closeMenu: "Close menu", openMenu: "Open menu", notifications: "Notifications", selectOrganization: "Select organization", primaryNavigation: "Primary navigation", mobileNavigation: "Mobile navigation", workspace: "Workspace", workspaceSettings: "Workspace settings", cashFlow: "Cash flow", healthyThisMonth: "Healthy this month", liveWorkspace: "Live workspace", financeDesk: "finance desk", active: "Active", protected: "Protected", profile: "Profile", appearance: "Appearance", language: "Language", theme: "Theme", english: "English", portuguese: "Português", light: "Light", dark: "Dark", people: "people", peopleCount_one: "{{count}} person", peopleCount_other: "{{count}} people", transactions: "transactions", transactionCount_one: "across {{count}} transaction", transactionCount_other: "across {{count}} transactions", commitments: "commitments", commitmentCount_one: "{{count}} commitment", commitmentCount_other: "{{count}} commitments", statuses: "statuses", types: "types", amount: "Amount", category: "Category", description: "Description", date: "Date", frequency: "Frequency", schedule: "Schedule", installments: "Installments (optional)", emailAddress: "Email address", role: "Role", documentCategory: "Document category", attachments: "Attachments", addFile: "Add file", removeFile: "Remove {{name}}", selectPeriod: "Select dashboard period", choosePeriod: "Choose a period", periodUpdated: "Dashboard data updates after applying.", from: "From", to: "To", endDateError: "The end date must be on or after the start date.", thisMonth: "This month", moreActions: "More actions", pageMoved: "That page moved.", findFinanceDesk: "Use the navigation to find your live finance desk.", backToDesk: "Back to the desk", notFound: "404 / not found", oneTime: "One time", added: "Added {{date}}", joined: "Joined {{date}}", expires: "Expires {{date}}", created: "Created {{date}}", peopleWithAccess: "People with access", connectedRoutes: "{{count}} routes connected to one calm workspace", acrossTransactions: "across {{count}} transactions", commitmentCount: "{{count}} commitments", titleWithName: "{{title}}, {{name}}", installmentCount: "{{current}}/{{total}} installment", removeDocumentConfirm: "Remove this document?", deleteBillConfirm: "Delete this bill?", deleteExpenseConfirm: "Delete this expense?", removeAvatarConfirm: "Remove your avatar?", signOutAllConfirm: "Sign out from every device?", leaveOrganizationConfirm: "Leave this organization?", stopFutureBillsConfirm: "Stop future bills? Existing occurrences remain.", removeMemberConfirm: "Remove {{name}} from this organization?" }, - home: { - eyebrow: "A clearer view of your money", title: "Make room for the life you’re planning.", body: "BitFinance brings bills, spending, and shared decisions into one calm workspace — so your next move is always visible.", cta: "Open the live desk", secondary: "See how it works", signal: "Built for real-life money moments", routes: "{{count}} routes connected to one calm workspace", cashFlow: "Cash flow", available: "Available", liveData: "Live workspace data", upcomingBills: "Upcoming bills", spentThisMonth: "Spent this month", paymentCleared: "payment cleared", readyNext: "Ready for the next decision", liveContext: "with live account context", nextStep: "Every number has a next step.", committed: "Know what’s committed", committedBody: "See upcoming obligations before they crowd out the choices you actually want to make.", pattern: "Notice the pattern", patternBody: "Turn a pile of transactions into a rhythm you can talk about together.", shared: "Keep it shared", sharedBody: "Invite the people who need context, without turning your home into a spreadsheet.", footer: "© 2026 BitFinance. A clearer view of your money." }, - auth: { signInTitle: "Welcome back", signInBody: "Your money desk is ready for today’s decisions.", signUpTitle: "Start with a clearer picture", signUpBody: "Create a workspace for the people and plans that matter.", email: "Email address", password: "Password", firstName: "First name", lastName: "Last name", noAccount: "New to BitFinance?", haveAccount: "Already have an account?", protectedSession: "Your session stays private on this device.", minimumPassword: "Your account starts with an eight-character minimum password.", signInStep: "sign in", getStarted: "get started", serverData: "Live account data stays on the server", validCredentials: "Use a valid email and password.", validRegistration: "Use a valid email and a password with at least 8 characters.", welcomeBack: "Welcome back", accountCreated: "Account created", unableContinue: "Unable to continue." }, - join: { eyebrow: "Invitation / live", title: "Join this organization", missingTitle: "Invitation link missing", body: "Accept the invitation after signing in to add this organization to your workspace.", missingBody: "Ask the sender for a fresh invitation link.", joined: "You joined the organization", invalid: "This invitation cannot be used." }, - createOrganization: { eyebrow: "New workspace / 01", title: "Create a money desk", body: "Give the workspace a name. You can invite people and set a budget from the organization area.", workspaceName: "Workspace name", creating: "Creating", preparing: "Preparing your workspace", unable: "Unable to create the workspace.", created: "Organization created" }, - dashboard: { eyebrow: "Selected period", title: "Good morning", body: "Here’s the shape of your money in the selected period.", budget: "Monthly budget", spent: "Spent so far", remaining: "Available", upcoming: "Upcoming", flow: "Cash-flow map", flowBody: "Your selected period, plotted as decisions instead of noise.", upcomingTitle: "Coming up", recentTitle: "Recent spending", categories: "Where it goes", onTrack: "You’re on track", setBudget: "Set a budget", greetingFallback: "there", createOrganization: "Create an organization first", needsOrganization: "Your dashboard needs an organization context.", createWorkspace: "Create workspace", notSet: "Not set", dataUnavailable: "Some dashboard data could not be loaded.", committedMoney: "Your committed money is {{amount}} this period.", budgetUsed: "of budget used", configureLimit: "Configure a monthly limit", currentLimit: "Current month limit", noBudget: "No budget configured", availableToSpend: "Available to spend", upcomingUnavailable: "Upcoming bills are unavailable.", recentUnavailable: "Recent expenses are unavailable.", nextDecisions: "The next decisions in line", noUpcoming: "No upcoming bills", nextCommitments: "Your next commitments will appear here.", selectedPeriodRead: "A small read on the selected period", foodHome: "Food & home", transport: "Transport", personal: "Personal", keepCommitment: "Keep a commitment visible", recordExpense: "Record what just happened", monthBoundary: "Give the month a boundary", commitments: "commitments", timelineCommitments: "commitments", timelineMoved: "moved", noMovement: "No movement in this period", timelineEmpty: "Bills and expenses will appear on the timeline." }, - bills: { eyebrow: "Scheduled money", title: "Bills", body: "Keep every commitment visible before it becomes urgent.", add: "Add bill", total: "Total scheduled", due: "Due soon", paid: "Paid this month", search: "Search bills", empty: "No bills match these filters.", selectOrganization: "Select an organization", scoped: "Bills are scoped to an organization.", commitment: "Commitment", dueDate: "Due date", type: "Type", status: "Status", allStatuses: "All statuses", allTypes: "All types", recurring: "Recurring", installments: "Installments", updated: "Bill updated", created: "Bill created", removed: "Bill removed", markedPaid: "Bill marked as paid", markPaid: "Mark as paid", edit: "Edit bill", formDescription: "Give this commitment a name, an amount, and a due date.", oneTime: "One time", installment: "Installment", daily: "Daily", weekly: "Weekly", monthly: "Monthly", annually: "Annually", invalidFile: "Use a PDF, JPG, PNG, DOC, or DOCX file up to 10 MiB.", uploaded: "Document uploaded", documentRemoved: "Document removed", notFound: "Bill not found.", detail: "Bill detail", amountDue: "Amount due", stopFuture: "Stop future bills", futureStopped: "Future bills stopped", attachmentDescription: "Open a document in a new tab, or save a copy with download.", noAttachments: "No attachments yet", receiptHint: "Add a receipt or boleto when you have one." }, - expenses: { eyebrow: "Money already moved", title: "Expenses", body: "A lightweight record of what happened — and what it means.", add: "Add expense", total: "Total spent", transactions: "transactions", search: "Search expenses", empty: "No expenses match these filters.", selectOrganization: "Select an organization", scoped: "Expenses are scoped to an organization.", average: "Average", localFilters: "Search and status filter the expenses shown on this page.", expense: "Expense", date: "Date", category: "Category", amount: "Amount", status: "Status", allStatuses: "All statuses", paid: "Paid", pending: "Pending", cancelled: "Cancelled", added: "Added {{date}}", updated: "Expense updated", created: "Expense added", removed: "Expense removed", edit: "Edit expense", formDescription: "Note what was spent and when it happened.", notFound: "Expense not found.", detail: "Expense detail", occurred: "Occurred", createdBy: "Created by", attachmentDescription: "Download a copy of an attached document.", noAttachments: "No attachments yet", receiptHint: "Add a receipt when you have one." }, - organization: { eyebrow: "Shared workspace", title: "Organization", body: "Set the rules and context behind the numbers.", settings: "Workspace settings", budget: "Monthly budget", members: "People with access", memberBody: "Invite the people who help make the calls.", name: "Workspace name", membersTitle: "Members", membersBody: "A simple view of who is part of this money desk.", active: "Active workspace", created: "Created {{date}}", onlyEditable: "Rename the workspace shown across your desk.", settingsSaved: "Workspace settings saved", boundary: "A boundary for the month, not a judgment.", monthlyLimit: "Monthly limit", notConfigured: "Not configured", budgetSaved: "Budget saved", monthlyBudget: "Monthly budget", dashboardUpdate: "Budget updates the dashboard", manageMembers: "Manage members", accessOverview: "Access overview", everyoneAccess: "Everyone with access to this workspace.", protected: "Protected", invitationCreated: "Invitation created", invitationCopied: "Invite link copied", invitationError: "Unable to create the invitation.", memberRemoved: "Member removed", left: "You left the organization", invitationReady: "Invitation ready", invitationDescription: "The invitation is valid for 24 hours and does not add a member until accepted.", invitationLink: "Invitation link", email: "Email address", role: "Role", roleFor: "Role for", roleUpdated: "Member role updated", roleError: "Unable to update this member's role.", leave: "Leave organization", remove: "Remove", removeError: "Unable to remove this member.", roleUnavailable: "Role unavailable", joinedUnavailable: "Joined date unavailable", membersUnavailable: "Members could not be loaded.", notFound: "Organization not found." }, - account: { eyebrow: "Your preferences", title: "Account", body: "Make the desk feel like yours.", profile: "Profile", appearance: "Appearance", language: "Language", theme: "Theme", signOut: "Sign out", reset: "Session preferences", profileDescription: "The name and email shown to your workspace.", changeAvatar: "Change avatar", removeAvatar: "Remove avatar", languageDescription: "Choose your interface language", themeDescription: "Choose a light or dark desk", billReminderEmails: "Bill reminder emails", billReminderEmailsDescription: "Email me before, on, and after a bill is due", billReminderEmailsUpgrade: "Available on Basic and Premium plans", signOutAll: "Sign out all devices", profileSaved: "Profile saved", unableSave: "Unable to save profile", invalidAvatar: "Use a JPG, JPEG, or PNG avatar up to 2 MiB.", avatarUpdated: "Avatar updated", unableUpload: "Unable to upload avatar", avatarRemoved: "Avatar removed" }, - notifications: { currentOrganization: "For the selected organization", markAllRead: "Mark all read", unreadCount: "{{count}} unread notifications", empty: "Nothing new here yet.", billDueSoon: { title: "Bill due soon", body: "{{billDescription}} is due in three days." }, billDueToday: { title: "Bill due today", body: "{{billDescription}} is due today." }, billOverdue: { title: "Bill overdue", body: "{{billDescription}} is now overdue." }, memberJoined: { title: "Member joined", body: "{{memberName}} joined the organization." }, memberRoleChanged: { title: "Member role changed", body: "{{memberName}} is now {{newRole}}." }, memberRemoved: { title: "Member removed", body: "{{memberName}} was removed from the organization." } }, - more: { eyebrow: "More / workspace", title: "More", body: "The useful edges of your finance desk", budgetSettings: "Budget and workspace settings", access: "People with access", profilePreferences: "Profile and preferences" }, - errors: { attention: "Something needs attention", tryAgain: "Try again", requestCanceled: "Request canceled.", validation: "Please check the highlighted fields." }, - api: { healthFailed: "Health check failed with {{status}}", account: { updateProfile: "Unable to update your profile.", uploadAvatar: "Unable to upload your avatar.", removeAvatar: "Unable to remove your avatar." }, auth: { createAccount: "Unable to create your account.", signIn: "Unable to sign in.", restoreSession: "Unable to restore your session.", signOut: "Unable to sign out.", signOutAll: "Unable to sign out all sessions.", loadAccount: "Unable to load your account." }, bills: { load: "Unable to load bills.", loadOne: "Unable to load this bill.", create: "Unable to create the bill.", update: "Unable to update the bill.", delete: "Unable to delete the bill.", uploadDocument: "Unable to upload the bill document.", openDocument: "Unable to open the bill document.", prepareDownload: "Unable to prepare the download.", removeDocument: "Unable to remove the bill document.", stopFuture: "Unable to stop future bills." }, dashboard: { summary: "Unable to load the dashboard summary.", upcoming: "Unable to load upcoming bills.", recent: "Unable to load recent expenses." }, expenses: { load: "Unable to load expenses.", loadOne: "Unable to load this expense.", create: "Unable to create the expense.", update: "Unable to update the expense.", delete: "Unable to delete the expense.", uploadDocument: "Unable to upload the expense document.", openDocument: "Unable to open the expense document.", removeDocument: "Unable to remove the expense document." }, organizations: { load: "Unable to load organizations.", loadOne: "Unable to load this organization.", create: "Unable to create the organization.", update: "Unable to update the organization.", loadBudget: "Unable to load the budget.", saveBudget: "Unable to save the budget.", createInvitation: "Unable to create the invitation.", updateRole: "Unable to update this member's role.", removeMember: "Unable to remove this member.", join: "Unable to join the organization." }, notifications: { load: "Unable to load notifications.", markRead: "Unable to update notifications.", loadPreferences: "Unable to load notification preferences.", savePreferences: "Unable to save notification preferences." } }, - types: { housing: "Housing", utilities: "Utilities", food: "Food", transportation: "Transport", healthcare: "Healthcare", subscriptions: "Subscriptions", education: "Education", insurance: "Insurance", personal: "Personal", taxes: "Taxes", miscellaneous: "Misc", travel: "Travel", gifts: "Gifts", pets: "Pets", services: "Professional services", recurring: "Recurring", installment: "Installment", oneTime: "One time" }, - statuses: { upcoming: "Upcoming", due: "Due", overdue: "Overdue", paid: "Paid", pending: "Pending", cancelled: "Cancelled", unknown: "Unknown" }, - roles: { Owner: "Owner", Admin: "Admin", Member: "Member" }, - documents: { Invoice: "Invoice", Receipt: "Receipt", Boleto: "Boleto", Other: "Other" }, - } }, - "pt-BR": { translation: { - meta: { title: "BitFinance — mesa financeira", description: "BitFinance — uma visão mais clara do seu dinheiro." }, - nav: { overview: "Visão geral", bills: "Contas", expenses: "Despesas", organization: "Organização", members: "Membros", account: "Conta" }, - common: { - save: "Salvar alterações", cancel: "Cancelar", close: "Fechar", add: "Adicionar", edit: "Editar", delete: "Excluir", search: "Buscar", all: "Todos", today: "Hoje", viewAll: "Ver tudo", loading: "Carregando", noResults: "Sem resultados", clearFilters: "Limpar filtros", signIn: "Entrar", signUp: "Criar conta", continue: "Continuar", invite: "Convidar membro", copy: "Copiar convite", update: "Atualizar", open: "Abrir", download: "Baixar", remove: "Remover", apply: "Aplicar", previous: "Anterior", next: "Próxima", actions: "Ações", more: "Mais", details: "detalhes", viewDetails: "Ver detalhes", backHome: "Voltar ao início", closeMenu: "Fechar menu", openMenu: "Abrir menu", notifications: "Notificações", selectOrganization: "Selecionar organização", primaryNavigation: "Navegação principal", mobileNavigation: "Navegação móvel", workspace: "Espaço de trabalho", workspaceSettings: "Configurações do espaço", cashFlow: "Fluxo financeiro", healthyThisMonth: "Saudável neste mês", liveWorkspace: "Espaço ao vivo", financeDesk: "mesa financeira", active: "Ativo", protected: "Protegido", profile: "Perfil", appearance: "Aparência", language: "Idioma", theme: "Tema", english: "English", portuguese: "Português", light: "Claro", dark: "Escuro", people: "pessoas", peopleCount_one: "{{count}} pessoa", peopleCount_other: "{{count}} pessoas", transactions: "transações", transactionCount_one: "em {{count}} transação", transactionCount_other: "em {{count}} transações", commitments: "compromissos", commitmentCount_one: "{{count}} compromisso", commitmentCount_other: "{{count}} compromissos", statuses: "status", types: "tipos", amount: "Valor", category: "Categoria", description: "Descrição", date: "Data", frequency: "Frequência", schedule: "Programação", installments: "Parcelas (opcional)", emailAddress: "Endereço de e-mail", role: "Função", documentCategory: "Categoria do documento", attachments: "Anexos", addFile: "Adicionar arquivo", removeFile: "Remover {{name}}", selectPeriod: "Selecionar período do painel", choosePeriod: "Escolha um período", periodUpdated: "Os dados do painel serão atualizados após a aplicação.", from: "De", to: "Até", endDateError: "A data final deve ser igual ou posterior à data inicial.", thisMonth: "Este mês", moreActions: "Mais ações", pageMoved: "Essa página mudou.", findFinanceDesk: "Use a navegação para encontrar sua mesa financeira.", backToDesk: "Voltar para a mesa", notFound: "404 / não encontrado", oneTime: "Avulsa", added: "Adicionada {{date}}", joined: "Entrou em {{date}}", expires: "Expira em {{date}}", created: "Criada em {{date}}", peopleWithAccess: "Pessoas com acesso", connectedRoutes: "{{count}} rotas conectadas a um só espaço tranquilo", acrossTransactions: "em {{count}} transações", commitmentCount: "{{count}} compromissos", titleWithName: "{{title}}, {{name}}", installmentCount: "{{current}}/{{total}} parcela", removeDocumentConfirm: "Remover este documento?", deleteBillConfirm: "Excluir esta conta?", deleteExpenseConfirm: "Excluir esta despesa?", removeAvatarConfirm: "Remover seu avatar?", signOutAllConfirm: "Sair de todos os dispositivos?", leaveOrganizationConfirm: "Sair desta organização?", stopFutureBillsConfirm: "Parar contas futuras? As ocorrências existentes permanecerão.", removeMemberConfirm: "Remover {{name}} desta organização?" }, - home: { - eyebrow: "Uma visão mais clara do seu dinheiro", title: "Abra espaço para a vida que você está planejando.", body: "O BitFinance reúne contas, gastos e decisões compartilhadas em um só espaço tranquilo — para o próximo passo estar sempre visível.", cta: "Abrir a mesa ao vivo", secondary: "Ver como funciona", signal: "Feito para os momentos reais do dinheiro", routes: "{{count}} rotas conectadas a um só espaço tranquilo", cashFlow: "Fluxo financeiro", available: "Disponível", liveData: "Dados financeiros ao vivo", upcomingBills: "Próximas contas", spentThisMonth: "Gasto neste mês", paymentCleared: "pagamento compensado", readyNext: "Pronto para a próxima decisão", liveContext: "com o contexto da conta ao vivo", nextStep: "Todo número aponta para um próximo passo.", committed: "Saiba o que está comprometido", committedBody: "Veja as obrigações futuras antes que elas limitem as escolhas que você realmente quer fazer.", pattern: "Perceba o padrão", patternBody: "Transforme uma pilha de transações em um ritmo que vocês possam conversar juntos.", shared: "Mantenha tudo compartilhado", sharedBody: "Convide quem precisa de contexto sem transformar sua casa em uma planilha.", footer: "© 2026 BitFinance. Uma visão mais clara do seu dinheiro." }, - auth: { signInTitle: "Bem-vinda de volta", signInBody: "Sua mesa financeira está pronta para as decisões de hoje.", signUpTitle: "Comece com uma visão mais clara", signUpBody: "Crie um espaço para as pessoas e planos que importam.", email: "E-mail", password: "Senha", firstName: "Nome", lastName: "Sobrenome", noAccount: "Ainda não usa o BitFinance?", haveAccount: "Já possui uma conta?", protectedSession: "Sua sessão permanece privada neste dispositivo.", minimumPassword: "Sua conta começa com uma senha de no mínimo oito caracteres.", signInStep: "entrar", getStarted: "começar", serverData: "Os dados da sua conta ficam no servidor", validCredentials: "Use um e-mail e uma senha válidos.", validRegistration: "Use um e-mail válido e uma senha com pelo menos 8 caracteres.", welcomeBack: "Bem-vinda de volta", accountCreated: "Conta criada", unableContinue: "Não foi possível continuar." }, - join: { eyebrow: "Convite / ao vivo", title: "Entrar nesta organização", missingTitle: "Link de convite ausente", body: "Aceite o convite depois de entrar para adicionar esta organização ao seu espaço de trabalho.", missingBody: "Peça ao remetente um novo link de convite.", joined: "Você entrou na organização", invalid: "Este convite não pode ser usado." }, - createOrganization: { eyebrow: "Novo espaço / 01", title: "Crie uma mesa financeira", body: "Dê um nome ao espaço. Você poderá convidar pessoas e definir um orçamento na área da organização.", workspaceName: "Nome do espaço", creating: "Criando", preparing: "Preparando seu espaço", unable: "Não foi possível criar o espaço.", created: "Organização criada" }, - dashboard: { eyebrow: "Período selecionado", title: "Bom dia", body: "Este é o desenho do seu dinheiro no período selecionado.", budget: "Orçamento mensal", spent: "Gasto até agora", remaining: "Disponível", upcoming: "A seguir", flow: "Mapa do fluxo", flowBody: "Seu período selecionado, organizado como decisões em vez de ruído.", upcomingTitle: "A seguir", recentTitle: "Gastos recentes", categories: "Para onde vai", onTrack: "Você está no caminho", setBudget: "Definir orçamento", greetingFallback: "aí", createOrganization: "Crie uma organização primeiro", needsOrganization: "Seu painel precisa do contexto de uma organização.", createWorkspace: "Criar espaço", notSet: "Não definido", dataUnavailable: "Não foi possível carregar alguns dados do painel.", committedMoney: "Seu dinheiro comprometido é {{amount}} neste período.", budgetUsed: "do orçamento usado", configureLimit: "Configure um limite mensal", currentLimit: "Limite do mês atual", noBudget: "Nenhum orçamento configurado", availableToSpend: "Disponível para gastar", upcomingUnavailable: "As próximas contas não estão disponíveis.", recentUnavailable: "As despesas recentes não estão disponíveis.", nextDecisions: "As próximas decisões na fila", noUpcoming: "Nenhuma conta próxima", nextCommitments: "Seus próximos compromissos aparecerão aqui.", selectedPeriodRead: "Uma leitura breve do período selecionado", foodHome: "Alimentação e casa", transport: "Transporte", personal: "Pessoal", keepCommitment: "Mantenha um compromisso visível", recordExpense: "Registre o que acabou de acontecer", monthBoundary: "Dê um limite ao mês", commitments: "compromissos", timelineCommitments: "compromissos", timelineMoved: "movimentações", noMovement: "Nenhuma movimentação neste período", timelineEmpty: "Contas e despesas aparecerão na linha do tempo." }, - bills: { eyebrow: "Dinheiro programado", title: "Contas", body: "Mantenha cada compromisso visível antes que vire urgência.", add: "Adicionar conta", total: "Total programado", due: "Vence em breve", paid: "Pago neste mês", search: "Buscar contas", empty: "Nenhuma conta corresponde a estes filtros.", selectOrganization: "Selecione uma organização", scoped: "As contas pertencem a uma organização.", commitment: "Compromisso", dueDate: "Vencimento", type: "Tipo", status: "Status", allStatuses: "Todos os status", allTypes: "Todos os tipos", recurring: "Recorrente", installments: "Parcelas", updated: "Conta atualizada", created: "Conta criada", removed: "Conta removida", markedPaid: "Conta marcada como paga", markPaid: "Marcar como paga", edit: "Editar conta", formDescription: "Dê um nome, um valor e um vencimento a este compromisso.", oneTime: "Avulsa", installment: "Parcelada", daily: "Diária", weekly: "Semanal", monthly: "Mensal", annually: "Anual", invalidFile: "Use um arquivo PDF, JPG, PNG, DOC ou DOCX de até 10 MiB.", uploaded: "Documento enviado", documentRemoved: "Documento removido", notFound: "Conta não encontrada.", detail: "Detalhes da conta", amountDue: "Valor devido", stopFuture: "Parar contas futuras", futureStopped: "Contas futuras interrompidas", attachmentDescription: "Abra um documento em uma nova aba ou salve uma cópia com o download.", noAttachments: "Nenhum anexo ainda", receiptHint: "Adicione um recibo ou boleto quando tiver um." }, - expenses: { eyebrow: "Dinheiro que já saiu", title: "Despesas", body: "Um registro leve do que aconteceu — e do que isso significa.", add: "Adicionar despesa", total: "Total gasto", transactions: "transações", search: "Buscar despesas", empty: "Nenhuma despesa corresponde a estes filtros.", selectOrganization: "Selecione uma organização", scoped: "As despesas pertencem a uma organização.", average: "Média", localFilters: "A busca e o status filtram as despesas exibidas nesta página.", expense: "Despesa", date: "Data", category: "Categoria", amount: "Valor", status: "Status", allStatuses: "Todos os status", paid: "Paga", pending: "Pendente", cancelled: "Cancelada", added: "Adicionada {{date}}", updated: "Despesa atualizada", created: "Despesa adicionada", removed: "Despesa removida", edit: "Editar despesa", formDescription: "Anote o que foi gasto e quando aconteceu.", notFound: "Despesa não encontrada.", detail: "Detalhes da despesa", occurred: "Aconteceu em", createdBy: "Criada por", attachmentDescription: "Baixe uma cópia de um documento anexado.", noAttachments: "Nenhum anexo ainda", receiptHint: "Adicione um recibo quando tiver um." }, - organization: { eyebrow: "Espaço compartilhado", title: "Organização", body: "Defina as regras e o contexto por trás dos números.", settings: "Configurações do espaço", budget: "Orçamento mensal", members: "Pessoas com acesso", memberBody: "Convide quem ajuda a tomar as decisões.", name: "Nome do espaço", membersTitle: "Membros", membersBody: "Uma visão simples de quem faz parte desta mesa financeira.", active: "Espaço ativo", created: "Criada em {{date}}", onlyEditable: "Renomeie o espaço exibido em toda a sua mesa.", settingsSaved: "Configurações do espaço salvas", boundary: "Um limite para o mês, não um julgamento.", monthlyLimit: "Limite mensal", notConfigured: "Não configurado", budgetSaved: "Orçamento salvo", monthlyBudget: "Orçamento mensal", dashboardUpdate: "O orçamento atualiza o painel", manageMembers: "Gerenciar membros", accessOverview: "Visão geral do acesso", everyoneAccess: "Todas as pessoas com acesso a este espaço.", protected: "Protegido", invitationCreated: "Convite criado", invitationCopied: "Link de convite copiado", invitationError: "Não foi possível criar o convite.", memberRemoved: "Membro removido", left: "Você saiu da organização", invitationReady: "Convite pronto", invitationDescription: "O convite é válido por 24 horas e não adiciona um membro até ser aceito.", invitationLink: "Link de convite", email: "Endereço de e-mail", role: "Função", roleFor: "Função de", roleUpdated: "Função do membro atualizada", roleError: "Não foi possível atualizar a função deste membro.", leave: "Sair da organização", remove: "Remover", removeError: "Não foi possível remover este membro.", roleUnavailable: "Função indisponível", joinedUnavailable: "Data de entrada indisponível", membersUnavailable: "Não foi possível carregar os membros.", notFound: "Organização não encontrada." }, - account: { eyebrow: "Suas preferências", title: "Conta", body: "Deixe a mesa com a sua cara.", profile: "Perfil", appearance: "Aparência", language: "Idioma", theme: "Tema", signOut: "Sair", reset: "Preferências da sessão", profileDescription: "O nome e o e-mail exibidos para seu espaço.", changeAvatar: "Alterar avatar", removeAvatar: "Remover avatar", languageDescription: "Escolha o idioma da interface", themeDescription: "Escolha uma mesa clara ou escura", billReminderEmails: "Lembretes de contas por e-mail", billReminderEmailsDescription: "Avise por e-mail antes, no dia e após o vencimento", billReminderEmailsUpgrade: "Disponível nos planos Basic e Premium", signOutAll: "Sair de todos os dispositivos", profileSaved: "Perfil salvo", unableSave: "Não foi possível salvar o perfil", invalidAvatar: "Use um avatar JPG, JPEG ou PNG de até 2 MiB.", avatarUpdated: "Avatar atualizado", unableUpload: "Não foi possível enviar o avatar", avatarRemoved: "Avatar removido" }, - notifications: { currentOrganization: "Da organização selecionada", markAllRead: "Marcar todas como lidas", unreadCount: "{{count}} notificações não lidas", empty: "Nenhuma novidade por aqui.", billDueSoon: { title: "Conta vence em breve", body: "{{billDescription}} vence em três dias." }, billDueToday: { title: "Conta vence hoje", body: "{{billDescription}} vence hoje." }, billOverdue: { title: "Conta atrasada", body: "{{billDescription}} está atrasada." }, memberJoined: { title: "Membro entrou", body: "{{memberName}} entrou na organização." }, memberRoleChanged: { title: "Função alterada", body: "{{memberName}} agora é {{newRole}}." }, memberRemoved: { title: "Membro removido", body: "{{memberName}} foi removido da organização." } }, - more: { eyebrow: "Mais / espaço", title: "Mais", body: "Os atalhos úteis da sua mesa financeira", budgetSettings: "Orçamento e configurações do espaço", access: "Pessoas com acesso", profilePreferences: "Perfil e preferências" }, - errors: { attention: "Algo precisa de atenção", tryAgain: "Tentar novamente", requestCanceled: "Solicitação cancelada.", validation: "Verifique os campos destacados." }, - api: { healthFailed: "A verificação de saúde falhou com {{status}}", account: { updateProfile: "Não foi possível atualizar seu perfil.", uploadAvatar: "Não foi possível enviar seu avatar.", removeAvatar: "Não foi possível remover seu avatar." }, auth: { createAccount: "Não foi possível criar sua conta.", signIn: "Não foi possível entrar.", restoreSession: "Não foi possível restaurar sua sessão.", signOut: "Não foi possível sair.", signOutAll: "Não foi possível sair de todas as sessões.", loadAccount: "Não foi possível carregar sua conta." }, bills: { load: "Não foi possível carregar as contas.", loadOne: "Não foi possível carregar esta conta.", create: "Não foi possível criar a conta.", update: "Não foi possível atualizar a conta.", delete: "Não foi possível excluir a conta.", uploadDocument: "Não foi possível enviar o documento da conta.", openDocument: "Não foi possível abrir o documento da conta.", prepareDownload: "Não foi possível preparar o download.", removeDocument: "Não foi possível remover o documento da conta.", stopFuture: "Não foi possível interromper as contas futuras." }, dashboard: { summary: "Não foi possível carregar o resumo do painel.", upcoming: "Não foi possível carregar as próximas contas.", recent: "Não foi possível carregar as despesas recentes." }, expenses: { load: "Não foi possível carregar as despesas.", loadOne: "Não foi possível carregar esta despesa.", create: "Não foi possível criar a despesa.", update: "Não foi possível atualizar a despesa.", delete: "Não foi possível excluir a despesa.", uploadDocument: "Não foi possível enviar o documento da despesa.", openDocument: "Não foi possível abrir o documento da despesa.", removeDocument: "Não foi possível remover o documento da despesa." }, organizations: { load: "Não foi possível carregar as organizações.", loadOne: "Não foi possível carregar esta organização.", create: "Não foi possível criar a organização.", update: "Não foi possível atualizar a organização.", loadBudget: "Não foi possível carregar o orçamento.", saveBudget: "Não foi possível salvar o orçamento.", createInvitation: "Não foi possível criar o convite.", updateRole: "Não foi possível atualizar a função deste membro.", removeMember: "Não foi possível remover este membro.", join: "Não foi possível entrar na organização." }, notifications: { load: "Não foi possível carregar as notificações.", markRead: "Não foi possível atualizar as notificações.", loadPreferences: "Não foi possível carregar as preferências de notificação.", savePreferences: "Não foi possível salvar as preferências de notificação." } }, - types: { housing: "Moradia", utilities: "Serviços", food: "Alimentação", transportation: "Transporte", healthcare: "Saúde", subscriptions: "Assinaturas", education: "Educação", insurance: "Seguro", personal: "Pessoal", taxes: "Impostos", miscellaneous: "Diversos", travel: "Viagens", gifts: "Presentes", pets: "Animais de estimação", services: "Serviços profissionais", recurring: "Recorrente", installment: "Parcelada", oneTime: "Avulsa" }, - statuses: { upcoming: "Próxima", due: "Vence em breve", overdue: "Atrasada", paid: "Paga", pending: "Pendente", cancelled: "Cancelada", unknown: "Desconhecido" }, - roles: { Owner: "Proprietário", Admin: "Administrador", Member: "Membro" }, - documents: { Invoice: "Fatura", Receipt: "Recibo", Boleto: "Boleto", Other: "Outro" }, - } }, -} as const; - -function updateDocumentLanguage(language: string) { - const locale = language === "pt-BR" ? "pt-BR" : "en-US"; - document.documentElement.lang = locale; - document.title = i18next.t("meta.title", { lng: locale }); - const description = document.querySelector('meta[name="description"]'); - if (description) description.content = i18next.t("meta.description", { lng: locale }); -} - -void i18next.use(initReactI18next).init({ - resources, - lng: localStorage.getItem("bitfinance-v2-locale") ?? "en-US", - fallbackLng: "en-US", - interpolation: { escapeValue: false }, -}); -i18next.on("languageChanged", updateDocumentLanguage); -updateDocumentLanguage(i18next.language); - -export default i18next; diff --git a/apps/frontend-v2/src/lib/auth-token.ts b/apps/frontend-v2/src/lib/auth-token.ts deleted file mode 100644 index 2eb1783..0000000 --- a/apps/frontend-v2/src/lib/auth-token.ts +++ /dev/null @@ -1,24 +0,0 @@ -let accessToken: string | null = null; -let accessTokenExpiresAt: string | null = null; - -export function getAccessToken() { - return accessToken; -} - -export function setAccessToken(token: string, expiresAt: string) { - accessToken = token; - accessTokenExpiresAt = expiresAt; -} - -export function clearAccessToken() { - accessToken = null; - accessTokenExpiresAt = null; -} - -export function getAccessTokenExpiresAt() { - return accessTokenExpiresAt; -} - -export function isAccessTokenExpired() { - return !accessTokenExpiresAt || Date.now() >= new Date(accessTokenExpiresAt).getTime() - 30_000; -} diff --git a/apps/frontend-v2/src/lib/query-keys.ts b/apps/frontend-v2/src/lib/query-keys.ts deleted file mode 100644 index d8da524..0000000 --- a/apps/frontend-v2/src/lib/query-keys.ts +++ /dev/null @@ -1,34 +0,0 @@ -const dateKey = (value?: Date | null) => value?.toISOString() ?? null; - -export const queryKeys = { - auth: { all: ["auth"] as const, me: () => ["auth", "me"] as const }, - health: { all: ["health"] as const }, - organizations: { - all: ["organizations"] as const, - list: () => ["organizations", "list"] as const, - detail: (organizationId: string) => ["organizations", "detail", organizationId] as const, - budget: (organizationId: string) => ["organizations", "budget", organizationId] as const, - }, - dashboard: { - all: ["dashboard"] as const, - summary: (organizationId: string, from?: Date, to?: Date) => ["dashboard", "summary", organizationId, dateKey(from), dateKey(to)] as const, - upcoming: (organizationId: string, from?: Date, to?: Date) => ["dashboard", "upcoming", organizationId, dateKey(from), dateKey(to)] as const, - recent: (organizationId: string, from?: Date, to?: Date) => ["dashboard", "recent", organizationId, dateKey(from), dateKey(to)] as const, - }, - bills: { - all: ["bills"] as const, - list: (organizationId: string, page: number, pageSize: number, from?: Date, to?: Date, status?: string, description?: string) => ["bills", "list", organizationId, page, pageSize, dateKey(from), dateKey(to), status ?? null, description ?? null] as const, - detail: (organizationId: string, billId: string) => ["bills", "detail", organizationId, billId] as const, - }, - expenses: { - all: ["expenses"] as const, - list: (organizationId: string, page: number, pageSize: number, from?: Date, to?: Date) => ["expenses", "list", organizationId, page, pageSize, dateKey(from), dateKey(to)] as const, - detail: (organizationId: string, expenseId: string) => ["expenses", "detail", organizationId, expenseId] as const, - }, - notifications: { - all: ["notifications"] as const, - list: (organizationId: string) => ["notifications", organizationId, "list"] as const, - unread: (organizationId: string) => ["notifications", organizationId, "unread"] as const, - preferences: (organizationId: string) => ["notifications", organizationId, "preferences"] as const, - }, -} as const; diff --git a/apps/frontend-v2/src/main.tsx b/apps/frontend-v2/src/main.tsx deleted file mode 100644 index 96542d0..0000000 --- a/apps/frontend-v2/src/main.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import { QueryClientProvider } from "@tanstack/react-query"; -import { BrowserRouter } from "react-router-dom"; -import { Toaster } from "sonner"; - -import "./i18n"; -import { AuthProvider } from "./auth/auth-provider"; -import { App } from "./app"; -import { queryClient } from "./lib/query-client"; -import "./styles.css"; - -if (localStorage.getItem("bitfinance-v2-theme") === "dark") { - document.documentElement.dataset.theme = "dark"; -} - -createRoot(document.getElementById("root")!).render( - - - - - - - - - - , -); diff --git a/apps/frontend-v2/src/notification-bell.tsx b/apps/frontend-v2/src/notification-bell.tsx deleted file mode 100644 index 9d2cd63..0000000 --- a/apps/frontend-v2/src/notification-bell.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { Bell, CheckCheck, ReceiptText, UsersRound } from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; - -import type { AppNotification, NotificationType } from "./api/notifications/notifications.types"; -import { useOrganizationStore } from "./auth/auth-store"; -import { useNotificationMutations, useNotificationsQuery, useNotificationUnreadCountQuery } from "./hooks/use-queries"; - -const billTypes = new Set(["BillDueSoon", "BillDueToday", "BillOverdue"]); - -function NotificationCopy({ notification }: { notification: AppNotification }) { - const { t } = useTranslation(); - const key = notification.type.charAt(0).toLowerCase() + notification.type.slice(1); - return {t(`notifications.${key}.title`)}{t(`notifications.${key}.body`, { ...notification.parameters })}; -} - -export function NotificationBell() { - const { t } = useTranslation(); - const organizationId = useOrganizationStore((state) => state.selectedOrganizationId); - const [open, setOpen] = useState(false); - const root = useRef(null); - const notifications = useNotificationsQuery(organizationId, open); - const unread = useNotificationUnreadCountQuery(organizationId); - const mutations = useNotificationMutations(organizationId); - - useEffect(() => { - if (!open) return; - const close = (event: PointerEvent) => { if (!root.current?.contains(event.target as Node)) setOpen(false); }; - const escape = (event: KeyboardEvent) => { if (event.key === "Escape") setOpen(false); }; - document.addEventListener("pointerdown", close); - document.addEventListener("keydown", escape); - return () => { document.removeEventListener("pointerdown", close); document.removeEventListener("keydown", escape); }; - }, [open]); - - const items = notifications.data?.data ?? []; - return
- - {open &&
-
{t("common.notifications")}{t("notifications.currentOrganization")}{(unread.data ?? 0) > 0 && }
-
- {notifications.isPending &&

{t("common.loading")}

} - {notifications.isError &&

{t("api.notifications.load")}

} - {!notifications.isPending && !notifications.isError && items.length === 0 &&

{t("notifications.empty")}

} - {items.map((notification) => { - const Icon = billTypes.has(notification.type) ? ReceiptText : UsersRound; - return { setOpen(false); if (!notification.readAt) mutations.markRead.mutate(notification.id); }}>; - })} -
-
} -
; -} diff --git a/apps/frontend-v2/src/styles.css b/apps/frontend-v2/src/styles.css deleted file mode 100644 index 59584ef..0000000 --- a/apps/frontend-v2/src/styles.css +++ /dev/null @@ -1,257 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Figtree:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&family=Space+Grotesk:wght@500;600;700&display=swap"); -@import "tailwindcss"; - -:root { - font-family: "Figtree", ui-sans-serif, system-ui, sans-serif; - color: #132238; - background: #f6f8fa; - font-synthesis: none; - text-rendering: optimizeLegibility; - --ink: #132238; - --ink-soft: #536273; - --ink-deep: #132238; - --muted: #8390a1; - --paper: #f6f8fa; - --surface: #ffffff; - --line: #e3e8ee; - --line-strong: #cfd7e1; - --blue: #2f5bea; - --blue-soft: #eaf0ff; - --mint: #23b89a; - --mint-soft: #e5f8f3; - --amber: #e9a23b; - --amber-soft: #fff4df; - --coral: #e65b65; - --coral-soft: #ffecef; - --shadow: 0 18px 50px rgba(19, 34, 56, 0.08); - --radius: 16px; -} - -* { box-sizing: border-box; } -html { min-width: 320px; background: var(--paper); } -body { margin: 0; min-width: 320px; min-height: 100vh; background: var(--paper); color: var(--ink); } -button, input, select, textarea { font: inherit; } -button, a { -webkit-tap-highlight-color: transparent; } -button { cursor: pointer; } -a { color: inherit; text-decoration: none; } -::selection { background: rgba(47, 91, 234, 0.18); } - -.app-shell { display: flex; min-height: 100vh; } -.sidebar { position: fixed; inset: 0 auto 0 0; z-index: 20; display: flex; width: 248px; flex-direction: column; border-right: 1px solid var(--line); background: #f9fbfc; } -.sidebar__brand { display: flex; height: 76px; align-items: center; gap: 10px; padding: 0 25px; border-bottom: 1px solid var(--line); } -.sidebar__brand-label { color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 10px; letter-spacing: .11em; text-transform: uppercase; } -.sidebar__org { padding: 22px 16px 14px; } -.sidebar__nav { flex: 1; padding: 8px 12px; overflow-y: auto; } -.sidebar__section-label { margin: 10px 13px 8px; color: #9ca8b6; font-family: "IBM Plex Mono", monospace; font-size: 10px; letter-spacing: .12em; text-transform: uppercase; } -.sidebar__section-label--spaced { margin-top: 27px; } -.sidebar__footer { padding: 16px; border-top: 1px solid var(--line); } -.sidebar__signal { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; padding: 10px; border: 1px solid #cdeee5; border-radius: 11px; background: #effbf8; color: var(--mint); } -.sidebar__signal span:not(.signal-dot) { display: grid; gap: 2px; } -.sidebar__signal strong { color: var(--ink); font-size: 12px; font-weight: 600; } -.sidebar__signal small { color: var(--mint); font-size: 10px; } -.signal-dot, .live-dot { display: inline-block; width: 7px; height: 7px; flex: 0 0 auto; border-radius: 999px; background: var(--mint); box-shadow: 0 0 0 4px rgba(35, 184, 154, .14); } -.sidebar__signal .signal-dot { width: 6px; height: 6px; margin-left: auto; box-shadow: none; } -.main-content { display: flex; min-width: 0; flex: 1; flex-direction: column; margin-left: 248px; } -.content-topbar { position: relative; z-index: 50; display: flex; height: 76px; align-items: center; justify-content: space-between; padding: 0 38px; border-bottom: 1px solid var(--line); background: rgba(249, 251, 252, .78); backdrop-filter: blur(16px); } -.content-topbar__crumb { display: flex; align-items: center; gap: 9px; color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 11px; letter-spacing: .02em; } -.content-topbar__crumb span:not(.live-dot) { color: #bbc3cd; } -.content-topbar__actions { display: flex; align-items: center; gap: 10px; } -.mobile-topbar, .mobile-bottom-nav { display: none; } -.content-scroll { min-height: calc(100vh - 76px); overflow-x: hidden; } - -.brand-mark { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); font-family: "Space Grotesk", sans-serif; font-size: 20px; font-weight: 700; letter-spacing: -.06em; } -.brand-mark__dot { width: 13px; height: 13px; border-radius: 4px 7px 4px 7px; background: var(--blue); transform: rotate(45deg); } -.brand-mark__word span { color: var(--blue); } -.brand-mark--compact { font-size: 18px; } -.brand-mark--compact .brand-mark__dot { width: 12px; height: 12px; } -.button { display: inline-flex; min-height: 42px; align-items: center; justify-content: center; gap: 8px; border: 1px solid transparent; border-radius: 10px; padding: 0 15px; background: var(--blue); color: white; font-size: 13px; font-weight: 600; line-height: 1; transition: transform .18s ease, box-shadow .18s ease, background .18s ease; } -.button:hover { box-shadow: 0 8px 18px rgba(47, 91, 234, .18); transform: translateY(-1px); } -.button:focus-visible, .icon-button:focus-visible, input:focus-visible, select:focus-visible, a:focus-visible, .nav-link:focus-visible { outline: 3px solid rgba(47, 91, 234, .24); outline-offset: 2px; } -.button--secondary { border-color: var(--line-strong); background: var(--surface); color: var(--ink); } -.button--secondary:hover { border-color: var(--blue); background: var(--blue-soft); box-shadow: none; } -.button--ghost { background: transparent; color: var(--ink-soft); } -.button--ghost:hover { background: var(--blue-soft); box-shadow: none; } -.button--danger { background: var(--coral); } -.button--small { min-height: 34px; padding: 0 12px; font-size: 12px; } -.button--large { min-height: 50px; padding: 0 19px; } -.button--full { width: 100%; } -.button:disabled { cursor: not-allowed; opacity: .48; transform: none; box-shadow: none; } -.icon-button { display: inline-grid; width: 36px; height: 36px; place-items: center; border: 1px solid transparent; border-radius: 9px; background: transparent; color: var(--ink-soft); } -.icon-button:hover { border-color: var(--line); background: var(--surface); color: var(--ink); } -.notification-bell { position: relative; }.notification-bell__trigger { position: relative; }.notification-bell__badge { position: absolute; top: -5px; right: -6px; display: grid; min-width: 17px; height: 17px; place-items: center; border: 2px solid var(--paper); border-radius: 999px; padding: 0 3px; background: var(--coral); color: white; font-family: "IBM Plex Mono", monospace; font-size: 8px; font-weight: 700; }.notification-panel { position: absolute; z-index: 80; top: calc(100% + 10px); right: 0; width: min(390px, calc(100vw - 36px)); overflow: hidden; border: 1px solid var(--line); border-radius: 15px; background: var(--surface); box-shadow: 0 20px 55px rgba(13, 24, 40, .18); animation: modal-in .16s ease both; }.notification-panel__header { display: flex; min-height: 67px; align-items: center; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--line); padding: 13px 16px; }.notification-panel__header > span { display: grid; gap: 3px; }.notification-panel__header strong { font-family: "Space Grotesk", sans-serif; font-size: 15px; }.notification-panel__header small { color: var(--muted); font-size: 9px; }.notification-panel__header button { display: flex; align-items: center; gap: 5px; border: 0; padding: 5px; background: transparent; color: var(--blue); font-size: 9px; font-weight: 700; }.notification-panel__header button:disabled { opacity: .5; }.notification-panel__list { max-height: min(470px, calc(100vh - 170px)); overflow-y: auto; }.notification-panel__state { margin: 0; padding: 34px 18px; color: var(--muted); text-align: center; font-size: 11px; }.notification-item { position: relative; display: grid; grid-template-columns: auto 1fr; gap: 11px; border-bottom: 1px solid var(--line); padding: 14px 16px; color: var(--ink); }.notification-item:last-child { border-bottom: 0; }.notification-item:hover { background: var(--paper); }.notification-item--unread { background: var(--blue-soft); }.notification-item--unread::before { position: absolute; top: 18px; left: 5px; width: 4px; height: 4px; border-radius: 50%; background: var(--blue); content: ""; }.notification-item__icon { display: grid; width: 31px; height: 31px; place-items: center; border-radius: 9px; background: var(--surface); color: var(--blue); box-shadow: inset 0 0 0 1px var(--line); }.notification-item__copy { display: grid; min-width: 0; gap: 3px; }.notification-item__copy strong { font-size: 11px; }.notification-item__copy small { overflow: hidden; color: var(--ink-soft); font-size: 10px; line-height: 1.4; text-overflow: ellipsis; white-space: nowrap; }.notification-item__copy time { color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 8px; } -.text-link { color: var(--blue); font-size: 13px; font-weight: 600; } -.text-link:hover, .inline-link:hover { text-decoration: underline; } -.back-link { display: inline-flex; margin-bottom: 18px; color: var(--muted); font-size: 13px; } -.back-link:hover { color: var(--blue); } -.eyebrow { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; color: var(--blue); font-family: "IBM Plex Mono", monospace; font-size: 10px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; } -.eyebrow-mark { display: inline-block; width: 17px; height: 1px; background: currentColor; } -.page-container { width: min(100%, 1360px); margin: 0 auto; padding: 42px 42px 80px; } -.page-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 30px; } -.page-header h1 { margin: 0; color: var(--ink); font-family: "Space Grotesk", sans-serif; font-size: clamp(30px, 3.1vw, 48px); font-weight: 600; letter-spacing: -.065em; line-height: 1.02; } -.page-header__description { max-width: 560px; margin: 12px 0 0; color: var(--ink-soft); font-size: 14px; line-height: 1.55; } -.page-header__actions { display: flex; align-items: center; gap: 9px; } -.page-header__actions:has(.period-control) { display: grid; align-self: flex-start; justify-items: start; gap: 7px; } -.page-header__actions:has(.period-control) > .eyebrow { margin: 0; } -.section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 15px; margin-bottom: 20px; } -.section-heading h2 { margin: 0; font-family: "Space Grotesk", sans-serif; font-size: 18px; letter-spacing: -.035em; } -.section-heading p { margin: 5px 0 0; color: var(--muted); font-size: 12px; line-height: 1.45; } -.section-heading__actions { display: flex; align-items: center; gap: 8px; } -.inline-link { display: inline-flex; align-items: center; gap: 5px; color: var(--blue); font-size: 12px; font-weight: 600; white-space: nowrap; } -.surface-card { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: 0 3px 12px rgba(19, 34, 56, .025); } - -.org-switcher { position: relative; display: flex; min-height: 42px; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 10px; padding: 0 10px; background: var(--surface); color: var(--ink-soft); } -.org-switcher select { width: 140px; appearance: none; border: 0; outline: 0; background: transparent; color: var(--ink); font-size: 12px; font-weight: 600; cursor: pointer; } -.org-switcher > svg:last-child { margin-left: auto; pointer-events: none; } -.nav-link { display: flex; min-height: 42px; align-items: center; gap: 11px; margin: 2px 0; border-radius: 9px; padding: 0 12px; color: var(--ink-soft); font-size: 13px; font-weight: 500; transition: background .15s ease, color .15s ease; } -.nav-link:hover { background: #eef2f6; color: var(--ink); } -.nav-link--active { background: var(--blue-soft); color: var(--blue); font-weight: 650; } -.sidebar-user { display: flex; min-width: 0; align-items: center; gap: 6px; border-top: 1px solid var(--line); padding-top: 12px; } -.user-menu { display: flex; min-width: 0; flex: 1; align-items: center; gap: 9px; border-radius: 9px; padding: 4px; color: var(--ink); text-align: left; } -.user-menu:hover { background: var(--surface); } -.user-menu span:not(.avatar) { display: grid; min-width: 0; gap: 2px; } -.user-menu strong { font-size: 12px; font-weight: 650; } -.user-menu small { overflow: hidden; color: var(--muted); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; } -.sidebar-user__logout { flex: 0 0 auto; } -.avatar { display: inline-grid; flex: 0 0 auto; place-items: center; border-radius: 10px; background: #dbe5ff; color: var(--blue); font-family: "IBM Plex Mono", monospace; font-size: 11px; font-weight: 600; object-fit: cover; } -.avatar--sm { width: 30px; height: 30px; border-radius: 8px; font-size: 9px; } -.avatar--md { width: 40px; height: 40px; } -.avatar--lg { width: 60px; height: 60px; border-radius: 15px; font-size: 16px; } -.metrics-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 14px; } -.metric-card { min-height: 151px; container-type: inline-size; border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; background: var(--surface); overflow: hidden; } -.metric-card__top { display: flex; align-items: center; justify-content: space-between; color: var(--muted); font-size: 11px; font-weight: 600; } -.metric-card__top svg { color: var(--blue); } -.metric-card strong { display: block; margin-top: 17px; font-family: "Space Grotesk", sans-serif; font-size: 26px; font-variant-numeric: tabular-nums; letter-spacing: -.055em; white-space: nowrap; } -@container (max-width: 190px) { .metric-card > strong { font-size: 22px; letter-spacing: -.07em; } } -.metric-card p { margin: 4px 0 0; color: var(--muted); font-size: 11px; } -.metric-card--mint { background: linear-gradient(135deg, #fff 36%, #f0fbf8); } -.metric-card--mint .metric-card__top svg { color: var(--mint); } -.metric-card--amber { background: linear-gradient(135deg, #fff 36%, #fff9ec); } -.metric-card--amber .metric-card__top svg { color: var(--amber); } -.metric-card--ink { background: var(--ink-deep); color: white; } -.metric-card--ink .metric-card__top, .metric-card--ink p { color: #aab9cd; } -.metric-card--ink .metric-card__top svg { color: #8faaff; } -.meter { height: 4px; margin-top: 12px; overflow: hidden; border-radius: 99px; background: #e9eff8; } -.meter span { display: block; height: 100%; border-radius: inherit; background: var(--blue); } -.dashboard-intro { display: flex; align-items: center; justify-content: space-between; margin: -10px 0 21px; color: var(--ink-soft); font-size: 12px; } -.dashboard-intro__label { color: var(--mint); font-family: "IBM Plex Mono", monospace; font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; } -.dashboard-intro p { margin: 4px 0 0; } -.dashboard-intro p strong { color: var(--ink); } -.dashboard-intro__trend { display: flex; align-items: center; gap: 7px; color: var(--mint); } -.dashboard-intro__trend span { display: grid; font-family: "IBM Plex Mono", monospace; font-size: 11px; } -.dashboard-intro__trend small { color: var(--muted); font-family: "Figtree", sans-serif; font-size: 10px; } -.period-picker { position: relative; } -.period-control { display: inline-flex; min-width: 155px; min-height: 38px; align-items: center; justify-content: center; gap: 8px; border: 1px solid var(--line); border-radius: 9px; padding: 0 10px; background: var(--surface); color: var(--ink-soft); font-family: "IBM Plex Mono", monospace; font-size: 10px; white-space: nowrap; } -.period-control:hover, .period-control[aria-expanded="true"] { border-color: #b8c7ef; background: var(--blue-soft); color: var(--blue); } -.period-control__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--blue); } -.period-control__chevron { transition: transform .18s ease; } -.period-control__chevron--open { transform: rotate(90deg); } -.period-popover { position: absolute; z-index: 40; top: calc(100% + 8px); right: 0; display: grid; width: 310px; gap: 16px; border: 1px solid var(--line); border-radius: 14px; padding: 17px; background: var(--surface); box-shadow: 0 18px 50px rgba(19, 34, 56, .16); } -.period-popover__heading { display: flex; align-items: center; gap: 10px; color: var(--blue); } -.period-popover__heading > span { display: grid; gap: 2px; } -.period-popover__heading strong { color: var(--ink); font-size: 13px; } -.period-popover__heading small { color: var(--muted); font-size: 10px; } -.period-popover__fields { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; } -.period-popover__fields label { display: grid; gap: 6px; color: var(--ink-soft); font-size: 10px; font-weight: 600; } -.period-popover__fields input { width: 100%; min-width: 0; min-height: 38px; border: 1px solid var(--line-strong); border-radius: 8px; padding: 0 7px; outline: 0; background: var(--surface); color: var(--ink); font-size: 11px; } -.period-popover__fields input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(47, 91, 234, .1); } -.period-popover__error { margin: -7px 0 0; color: var(--coral); font-size: 10px; } -.period-popover__actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; } -.period-popover__reset { margin-right: auto; border: 0; background: transparent; color: var(--blue); font-size: 11px; font-weight: 600; } -.period-popover__reset:hover { text-decoration: underline; } -@media (max-width: 820px) { .period-picker, .period-control { width: 100%; }.period-popover { right: auto; left: 0; width: min(310px, calc(100vw - 36px)); } } -.timeline-card { position: relative; margin-bottom: 14px; border: 1px solid var(--line); border-radius: var(--radius); padding: 23px 24px 18px; background: var(--ink-deep); color: white; overflow: hidden; } -.timeline-card::after { position: absolute; top: -100px; right: -80px; width: 280px; height: 280px; border: 1px solid rgba(143, 170, 255, .18); border-radius: 50%; content: ""; box-shadow: 0 0 0 30px rgba(143, 170, 255, .04), 0 0 0 60px rgba(143, 170, 255, .025); } -.timeline-card__header { position: relative; z-index: 1; display: flex; justify-content: space-between; gap: 20px; } -.timeline-card .eyebrow { color: #8faaff; } -.timeline-card h2 { max-width: 420px; margin: 0; color: white; font-family: "Space Grotesk", sans-serif; font-size: 21px; letter-spacing: -.045em; line-height: 1.15; } -.timeline-card__legend { display: flex; align-items: center; align-self: flex-end; gap: 6px; color: #9baabe; font-family: "IBM Plex Mono", monospace; font-size: 9px; white-space: nowrap; } -.timeline-card__legend .tiny-dot:not(:first-child) { margin-left: 10px; } -.timeline { position: relative; z-index: 1; display: flex; min-width: max-content; align-items: flex-start; gap: 0; margin: 34px 0 4px; padding-top: 14px; } -.timeline::before { position: absolute; top: 38px; right: 0; left: 0; height: 1px; background: #3a4c68; content: ""; } -.timeline-event { position: relative; display: grid; min-width: 150px; gap: 8px; padding-right: 20px; color: #aebbd0; animation: timeline-in .45s both; animation-delay: calc(var(--event-index) * 55ms); } -.timeline-event__date { color: #8faaff; font-family: "IBM Plex Mono", monospace; font-size: 9px; line-height: 11px; } -.timeline-event__dot { position: relative; z-index: 1; width: 10px; height: 10px; border: 2px solid var(--ink-deep); border-radius: 50%; background: var(--amber); box-shadow: 0 0 0 4px rgba(233, 162, 59, .15); } -.timeline-event--expense .timeline-event__dot { background: var(--mint); box-shadow: 0 0 0 4px rgba(35, 184, 154, .15); } -.timeline-event__label { max-width: 140px; overflow: hidden; color: #e5ebf4; font-size: 11px; font-weight: 550; text-overflow: ellipsis; white-space: nowrap; } -.timeline-event strong { color: white; font-family: "IBM Plex Mono", monospace; font-size: 11px; font-weight: 500; } -.dashboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; } -.dashboard-grid > .surface-card { min-height: 310px; padding: 22px; } -.compact-list { display: grid; gap: 2px; } -.compact-row { display: flex; align-items: center; gap: 10px; border-radius: 10px; padding: 10px 6px; transition: background .15s ease; } -.compact-row:hover { background: var(--paper); } -.compact-row > span:nth-child(2) { display: grid; min-width: 0; gap: 4px; flex: 1; } -.compact-row strong { overflow: hidden; font-size: 12px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; } -.compact-row small { color: var(--muted); font-size: 10px; } -.compact-row__amount { display: grid; justify-items: end; gap: 5px; } -.data-icon { display: inline-grid; width: 34px; height: 34px; flex: 0 0 auto; place-items: center; border-radius: 10px; } -.data-icon--bill { background: var(--amber-soft); color: var(--amber); } -.data-icon--expense { background: var(--mint-soft); color: var(--mint); } -.data-icon--budget { background: var(--blue-soft); color: var(--blue); } -.data-icon--team { background: #f0eafa; color: #8064bd; } -.status-pill { display: inline-flex; width: max-content; align-items: center; justify-content: center; justify-self: start; border-radius: 999px; padding: 4px 7px; font-family: "IBM Plex Mono", monospace; font-size: 9px; font-weight: 500; line-height: 1; text-align: center; text-transform: capitalize; white-space: nowrap; } -.status-pill--upcoming, .status-pill--pending { background: var(--blue-soft); color: var(--blue); } -.status-pill--due { background: var(--amber-soft); color: #ac6d11; } -.status-pill--overdue, .status-pill--cancelled { background: var(--coral-soft); color: #b43d4a; } -.status-pill--paid { background: var(--mint-soft); color: #0c8b72; } -.recent-summary { display: grid; gap: 22px; } -.recent-summary__chart { display: flex; align-items: flex-end; justify-content: space-between; gap: 15px; } -.recent-summary__chart span { display: grid; gap: 3px; } -.recent-summary__chart strong { font-family: "Space Grotesk", sans-serif; font-size: 24px; letter-spacing: -.05em; } -.recent-summary__chart small { color: var(--muted); font-size: 10px; } -.sparkline { width: 52%; height: 64px; overflow: visible; } -.category-bars { display: grid; gap: 11px; } -.category-bar { display: grid; grid-template-columns: 1fr auto; gap: 6px; color: var(--ink-soft); font-family: "IBM Plex Mono", monospace; font-size: 10px; } -.category-bar > span:first-child { display: flex; align-items: center; gap: 6px; font-family: "Figtree", sans-serif; font-size: 11px; } -.category-bar > div { grid-column: 1 / -1; height: 4px; overflow: hidden; border-radius: 99px; background: var(--line); } -.category-bar__fill { display: block; height: 100%; border-radius: inherit; } -.category-bar__fill--mint { background: var(--mint); }.category-bar__fill--blue { background: var(--blue); }.category-bar__fill--amber { background: var(--amber); } -.tiny-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; }.tiny-dot--mint { background: var(--mint); }.tiny-dot--blue { background: var(--blue); }.tiny-dot--amber { background: var(--amber); }.tiny-dot--coral { background: var(--coral); } -.quick-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; } -.quick-action { display: flex; align-items: center; gap: 10px; border: 1px solid var(--line); border-radius: 12px; padding: 13px; background: var(--surface); transition: border-color .15s ease, transform .15s ease; } -.quick-action:hover { border-color: #aabdf7; transform: translateY(-2px); } -.quick-action__icon { display: inline-grid; width: 30px; height: 30px; place-items: center; border-radius: 8px; background: var(--blue-soft); color: var(--blue); } -.quick-action > span:nth-child(2) { display: grid; flex: 1; gap: 3px; } -.quick-action strong { font-size: 11px; }.quick-action small { color: var(--muted); font-size: 10px; }.quick-action > svg { color: var(--muted); } - -.stat-strip { display: grid; grid-template-columns: repeat(3, 1fr); margin-bottom: 17px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); } -.stat-strip > div { display: grid; gap: 8px; padding: 17px 20px; border-right: 1px solid var(--line); }.stat-strip > div:last-child { border-right: 0; }.stat-strip span { color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 10px; text-transform: uppercase; }.stat-strip strong { font-family: "Space Grotesk", sans-serif; font-size: 23px; letter-spacing: -.05em; }.text-amber { color: #b5791f; }.text-mint { color: var(--mint); } -.filter-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; } -.clear-filters-button { min-height: 40px; color: var(--blue); white-space: nowrap; } -.search-field, .select-field { display: flex; min-height: 40px; align-items: center; gap: 7px; border: 1px solid var(--line); border-radius: 9px; padding: 0 11px; background: var(--surface); color: var(--muted); }.search-field { flex: 1; max-width: 380px; }.search-field input, .select-field select { min-width: 0; border: 0; outline: 0; background: transparent; color: var(--ink); font-size: 12px; }.search-field input { width: 100%; }.select-field select { padding-right: 5px; cursor: pointer; } -.surface-card--table { overflow: visible; }.table-head, .table-row { display: grid; grid-template-columns: 2.2fr 1fr 1fr .9fr .9fr 78px; align-items: center; gap: 13px; padding: 0 20px; }.table-head { min-height: 42px; border-bottom: 1px solid var(--line); color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 9px; letter-spacing: .07em; text-transform: uppercase; }.table-row { position: relative; min-height: 76px; border-bottom: 1px solid #edf0f4; color: var(--ink-soft); font-size: 12px; }.table-row:last-child { border-bottom: 0; }.table-row > span, .table-row > strong { min-width: 0; }.table-row > span small, .table-row__primary small { display: block; margin-top: 4px; color: var(--muted); font-size: 10px; }.table-row__primary { display: flex; align-items: center; gap: 10px; min-width: 0; }.table-row__primary > span { display: grid; min-width: 0; }.table-row__primary strong { overflow: hidden; color: var(--ink); text-overflow: ellipsis; white-space: nowrap; }.table-row > strong { color: var(--ink); font-family: "IBM Plex Mono", monospace; font-size: 11px; font-weight: 600; }.type-label { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; text-transform: capitalize; }.muted { color: var(--muted); font-size: 11px; }.row-actions { position: relative; display: flex; align-items: center; justify-content: flex-end; gap: 6px; justify-self: end; }.action-menu { position: absolute; z-index: 10; top: 38px; right: 0; display: grid; min-width: 160px; padding: 5px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); box-shadow: var(--shadow); }.action-menu button, .action-menu a { display: flex; align-items: center; gap: 8px; border: 0; border-radius: 6px; padding: 8px 9px; background: transparent; color: var(--ink-soft); font-size: 11px; text-align: left; }.action-menu button:hover, .action-menu a:hover { background: var(--paper); color: var(--blue); }.action-menu__danger { color: var(--coral) !important; }.base-menu { z-index: 110; min-width: 164px; padding: 5px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); box-shadow: var(--shadow); outline: 0; }.base-menu__item { display: flex; align-items: center; gap: 8px; border-radius: 6px; padding: 8px 9px; color: var(--ink-soft); font-size: 11px; cursor: pointer; outline: 0; }.base-menu__item[data-highlighted] { background: var(--paper); color: var(--blue); }.base-menu__item--danger { color: var(--coral); } -.empty-state { display: grid; justify-items: center; gap: 8px; padding: 58px 20px; text-align: center; }.empty-state__icon { display: inline-grid; width: 44px; height: 44px; place-items: center; border-radius: 13px; background: var(--paper); color: var(--muted); }.empty-state h3 { margin: 4px 0 0; font-family: "Space Grotesk", sans-serif; font-size: 16px; }.empty-state p { max-width: 290px; margin: 0 0 8px; color: var(--muted); font-size: 12px; line-height: 1.5; } -.spinner { width: 26px; height: 26px; border: 3px solid var(--line-strong); border-top-color: var(--blue); border-radius: 50%; animation: spin .75s linear infinite; } -.detail-grid { display: grid; grid-template-columns: .9fr 1.1fr; gap: 14px; }.detail-card { min-height: 280px; padding: 23px; }.detail-card__amount { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }.detail-card__amount span:first-child { color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 10px; text-transform: uppercase; }.detail-card__amount strong { margin-top: 22px; margin-right: auto; font-family: "Space Grotesk", sans-serif; font-size: 33px; letter-spacing: -.06em; }.detail-list { display: grid; gap: 15px; margin: 22px 0 0; }.detail-list div { display: flex; justify-content: space-between; gap: 20px; }.detail-list dt { color: var(--muted); font-size: 11px; }.detail-list dd { margin: 0; color: var(--ink); font-size: 12px; font-weight: 600; text-align: right; }.attachment-row { display: flex; align-items: center; gap: 10px; padding: 12px 0; border-top: 1px solid var(--line); }.attachment-row > span:nth-child(2) { display: grid; flex: 1; gap: 4px; min-width: 0; }.attachment-row strong { overflow-wrap: anywhere; font-size: 12px; }.attachment-row small { color: var(--muted); font-size: 10px; } -.modal-backdrop { position: fixed; z-index: 100; inset: 0; display: grid; place-items: center; padding: 20px; background: rgba(13, 24, 40, .5); backdrop-filter: blur(5px); }.modal { width: min(100%, 500px); max-height: calc(100vh - 40px); overflow-y: auto; border: 1px solid var(--line); border-radius: 18px; padding: 24px; background: var(--surface); box-shadow: 0 24px 80px rgba(4, 14, 27, .25); animation: modal-in .2s ease both; }.modal--wide { width: min(100%, 680px); }.modal__header { display: flex; align-items: flex-start; justify-content: space-between; gap: 15px; margin-bottom: 24px; }.modal__header h2 { margin: 0; font-family: "Space Grotesk", sans-serif; font-size: 23px; letter-spacing: -.05em; }.modal__header p { margin: 7px 0 0; color: var(--muted); font-size: 12px; line-height: 1.5; }.modal-form { display: grid; gap: 15px; }.modal-form label, .field-label, .auth-form label, .account-form label { display: grid; gap: 7px; }.modal-form label > span, .field-label > span, .auth-form label > span, .account-form label > span { color: var(--ink-soft); font-size: 11px; font-weight: 600; }.modal-form input, .modal-form select, .field-label input, .auth-form input, .account-form input, .inline-form input, .preference-row select { min-height: 42px; width: 100%; border: 1px solid var(--line-strong); border-radius: 9px; padding: 0 12px; outline: 0; background: var(--surface); color: var(--ink); font-size: 13px; }.modal-form input:focus, .modal-form select:focus, .field-label input:focus, .auth-form input:focus, .account-form input:focus, .inline-form input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(47, 91, 234, .1); }.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }.modal-form__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; } -.organization-layout, .account-layout { display: grid; gap: 14px; }.organization-hero { display: flex; align-items: center; gap: 14px; padding: 22px; }.organization-hero__mark { display: inline-grid; width: 52px; height: 52px; place-items: center; border-radius: 15px; background: var(--blue-soft); color: var(--blue); }.organization-hero h2 { margin: 0; font-family: "Space Grotesk", sans-serif; font-size: 22px; letter-spacing: -.045em; }.organization-hero p:last-child { margin: 5px 0 0; color: var(--muted); font-size: 11px; }.organization-hero__status { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; color: var(--mint); font-family: "IBM Plex Mono", monospace; font-size: 10px; }.organization-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }.organization-grid > section, .organization-members-preview, .profile-card, .preferences-card { padding: 22px; }.budget-card { background: linear-gradient(135deg, #fff, #f5f8ff); }.budget-card__number { display: grid; gap: 6px; margin: 28px 0 17px; }.budget-card__number span { color: var(--muted); font-size: 11px; }.budget-card__number strong { font-family: "Space Grotesk", sans-serif; font-size: 36px; letter-spacing: -.06em; }.inline-form { display: flex; gap: 8px; }.inline-form input { flex: 1; }.budget-card__footer { display: flex; align-items: center; gap: 5px; margin-top: 18px; color: var(--muted); font-size: 10px; }.member-stack { display: flex; flex-wrap: wrap; gap: 9px; }.member-chip { display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 11px; padding: 8px 11px 8px 8px; }.member-chip > span:last-child { display: grid; gap: 2px; }.member-chip strong { font-size: 11px; }.member-chip small { color: var(--muted); font-size: 10px; }.members-card { padding: 22px; }.members-card__summary { display: flex; align-items: flex-start; justify-content: space-between; padding-bottom: 22px; border-bottom: 1px solid var(--line); }.members-card__summary strong { display: block; margin-top: 8px; font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -.06em; }.members-card__summary p { margin: 5px 0 0; color: var(--muted); font-size: 11px; }.members-card__badge { display: inline-flex; align-items: center; gap: 5px; color: var(--mint); font-size: 11px; font-weight: 600; }.members-list { display: grid; }.member-row { display: flex; min-height: 72px; align-items: center; gap: 12px; border-bottom: 1px solid var(--line); }.member-row:last-child { border-bottom: 0; }.member-row > span:nth-child(2) { display: grid; flex: 1; gap: 4px; }.member-row strong { font-size: 12px; }.member-row small, .member-row__joined { color: var(--muted); font-size: 10px; }.member-row__joined { margin-right: 8px; }.role-badge { border-radius: 999px; padding: 5px 8px; font-family: "IBM Plex Mono", monospace; font-size: 9px; }.role-badge--owner { background: var(--blue-soft); color: var(--blue); }.role-badge--admin { background: var(--amber-soft); color: #a56810; }.role-badge--member { background: var(--mint-soft); color: #0a8a70; } -.profile-card__identity { display: flex; align-items: center; gap: 12px; margin: 23px 0; }.profile-card__identity > div { display: grid; flex: 1; gap: 4px; }.profile-card__identity strong { font-family: "Space Grotesk", sans-serif; font-size: 16px; }.profile-card__identity span { color: var(--muted); font-size: 11px; }.account-form { align-items: end; }.preferences-card { display: grid; align-content: start; }.preference-row { display: flex; min-height: 67px; align-items: center; justify-content: space-between; gap: 12px; border-top: 1px solid var(--line); }.preference-row > span:first-child { display: flex; align-items: center; gap: 10px; color: var(--blue); }.preference-row > span:first-child > span { display: grid; gap: 4px; }.preference-row strong { color: var(--ink); font-size: 12px; }.preference-row small { color: var(--muted); font-size: 10px; }.preference-row select { width: auto; min-height: 34px; padding: 0 9px; font-size: 11px; }.theme-pills { display: flex; gap: 4px; }.theme-pill { border: 1px solid var(--line); border-radius: 7px; padding: 7px 9px; background: var(--surface); color: var(--muted); font-size: 10px; }.theme-pill--active { border-color: var(--blue); background: var(--blue-soft); color: var(--blue); }.preference-row--danger > span:first-child { color: var(--coral); }.account-signout { margin-top: 12px; padding-top: 16px; border-top: 1px solid var(--line); } -.switch { position: relative; display: inline-flex; flex: 0 0 auto; }.switch input { position: absolute; width: 1px; height: 1px; opacity: 0; }.switch span { width: 39px; height: 22px; border: 1px solid var(--line-strong); border-radius: 999px; background: var(--paper); transition: .18s ease; }.switch span::after { display: block; width: 16px; height: 16px; margin: 2px; border-radius: 50%; background: var(--muted); content: ""; transition: .18s ease; }.switch input:checked + span { border-color: var(--blue); background: var(--blue); }.switch input:checked + span::after { transform: translateX(17px); background: white; }.switch input:focus-visible + span { outline: 3px solid rgba(47, 91, 234, .24); outline-offset: 2px; }.switch input:disabled + span { cursor: not-allowed; opacity: .45; } -.more-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } - -.public-shell { min-height: 100vh; background: var(--paper); }.public-nav { display: flex; height: 82px; align-items: center; justify-content: space-between; width: min(100% - 72px, 1250px); margin: 0 auto; }.public-nav__actions { display: flex; align-items: center; gap: 19px; }.language-switch { display: inline-flex; align-items: center; gap: 5px; border: 0; background: transparent; color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 10px; font-weight: 600; }.landing { width: min(100% - 72px, 1250px); margin: 0 auto; }.landing-hero { display: grid; min-height: 620px; grid-template-columns: .85fr 1.15fr; align-items: center; gap: 60px; padding: 60px 0 80px; }.landing-hero__copy h1 { max-width: 600px; margin: 0; font-family: "Space Grotesk", sans-serif; font-size: clamp(48px, 6vw, 78px); font-weight: 600; letter-spacing: -.08em; line-height: .98; }.landing-hero__body { max-width: 480px; margin: 25px 0 28px; color: var(--ink-soft); font-size: 16px; line-height: 1.65; }.landing-hero__actions { display: flex; flex-wrap: wrap; gap: 9px; }.landing-hero__trust { display: flex; align-items: center; gap: 12px; margin-top: 36px; color: var(--muted); font-size: 11px; }.landing-hero__trust strong { color: var(--ink); }.avatar-stack { display: flex; }.avatar-stack .avatar { margin-right: -8px; border: 2px solid var(--paper); }.landing-hero__visual { position: relative; min-height: 470px; display: grid; place-items: center; }.hero-orbit { position: absolute; border: 1px solid rgba(47, 91, 234, .12); border-radius: 50%; transform: rotate(-19deg); }.hero-orbit--one { width: 390px; height: 490px; }.hero-orbit--two { width: 480px; height: 290px; border-color: rgba(35, 184, 154, .16); transform: rotate(27deg); }.hero-desk-card { position: relative; z-index: 1; width: min(100%, 430px); border: 1px solid #30445f; border-radius: 18px; padding: 21px; background: var(--ink-deep); color: white; box-shadow: 0 28px 60px rgba(19, 34, 56, .2); transform: rotate(2deg); }.hero-desk-card__header { display: flex; align-items: center; gap: 7px; color: #a7b8cf; font-family: "IBM Plex Mono", monospace; font-size: 9px; }.hero-desk-card__header > svg { margin-left: auto; }.hero-desk-card__balance { display: grid; gap: 7px; margin: 42px 0 34px; }.hero-desk-card__balance > span { color: #95a7bd; font-size: 11px; }.hero-desk-card__balance strong { font-family: "Space Grotesk", sans-serif; font-size: 41px; letter-spacing: -.07em; }.hero-desk-card__balance small { display: flex; align-items: center; gap: 5px; color: #7de1cd; font-size: 10px; }.hero-mini-timeline { position: relative; padding-top: 5px; }.hero-mini-timeline__line { display: block; height: 1px; background: #3c506b; }.hero-mini-timeline__dot { position: absolute; top: 0; width: 10px; height: 10px; border: 2px solid var(--ink); border-radius: 50%; }.hero-mini-timeline__dot--past { background: #7f91a9; }.hero-mini-timeline__dot--mint { background: var(--mint); }.hero-mini-timeline__dot--amber { background: var(--amber); }.hero-mini-timeline__dot--coral { background: var(--coral); }.hero-mini-timeline__labels { display: flex; justify-content: space-between; margin-top: 10px; color: #8294ad; font-family: "IBM Plex Mono", monospace; font-size: 9px; }.hero-desk-card__rows { display: grid; gap: 12px; margin-top: 29px; padding-top: 17px; border-top: 1px solid #30445f; }.hero-desk-card__rows span { display: flex; align-items: center; gap: 7px; color: #afbdd0; font-size: 10px; }.hero-desk-card__rows b { margin-left: auto; color: white; font-family: "IBM Plex Mono", monospace; font-size: 10px; font-weight: 500; }.hero-float { position: absolute; z-index: 2; display: flex; align-items: center; gap: 9px; border: 1px solid var(--line); border-radius: 13px; padding: 12px; background: rgba(255, 255, 255, .92); box-shadow: var(--shadow); }.hero-float svg { color: var(--mint); }.hero-float span:not(.hero-float__check) { display: grid; gap: 3px; }.hero-float strong { font-family: "IBM Plex Mono", monospace; font-size: 11px; }.hero-float small { color: var(--muted); font-size: 9px; }.hero-float--top { top: 74px; right: 6%; transform: rotate(4deg); }.hero-float--bottom { bottom: 63px; left: 2%; transform: rotate(-4deg); }.hero-float__check { display: inline-grid; width: 24px; height: 24px; place-items: center; border-radius: 8px; background: var(--mint-soft); color: var(--mint); }.landing-signal { padding: 70px 0 115px; border-top: 1px solid var(--line); }.landing-signal > div:first-child { display: flex; align-items: flex-end; justify-content: space-between; margin-bottom: 38px; }.landing-signal h2 { max-width: 330px; margin: 0; font-family: "Space Grotesk", sans-serif; font-size: 39px; letter-spacing: -.07em; line-height: 1; }.landing-signal__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 17px; }.landing-signal__grid article { position: relative; min-height: 205px; border-top: 1px solid var(--ink); padding: 19px 4px; }.landing-signal__grid article svg { color: var(--blue); }.feature-number { position: absolute; top: 18px; right: 3px; color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 10px; }.landing-signal__grid h3 { margin: 32px 0 8px; font-family: "Space Grotesk", sans-serif; font-size: 19px; letter-spacing: -.04em; }.landing-signal__grid p { max-width: 270px; margin: 0; color: var(--ink-soft); font-size: 12px; line-height: 1.55; }.public-footer { display: flex; width: min(100% - 72px, 1250px); align-items: center; justify-content: space-between; margin: 0 auto; padding: 22px 0 28px; border-top: 1px solid var(--line); color: var(--muted); font-size: 10px; }.public-footer .brand-mark { font-size: 15px; } -.auth-layout { display: grid; min-height: calc(100vh - 82px); grid-template-columns: .9fr 1.1fr; }.auth-aside { position: relative; display: flex; min-height: 630px; flex-direction: column; justify-content: center; padding: 65px max(8vw, 60px); background: var(--ink-deep); color: white; overflow: hidden; }.auth-aside::after { position: absolute; right: -140px; bottom: -180px; width: 430px; height: 430px; border: 1px solid rgba(143, 170, 255, .22); border-radius: 50%; content: ""; box-shadow: 0 0 0 35px rgba(143, 170, 255, .04), 0 0 0 70px rgba(143, 170, 255, .035); }.auth-aside__inner { position: relative; z-index: 1; max-width: 450px; }.auth-aside .eyebrow { color: #8faaff; }.auth-aside h1 { margin: 0; font-family: "Space Grotesk", sans-serif; font-size: clamp(40px, 5vw, 67px); letter-spacing: -.08em; line-height: .98; }.auth-aside__inner > p:not(.eyebrow) { max-width: 360px; margin: 24px 0 0; color: #adbbce; font-size: 15px; line-height: 1.6; }.auth-aside__note { display: flex; align-items: flex-start; gap: 10px; margin-top: 40px; border-top: 1px solid #31445e; padding-top: 17px; color: #8faaff; font-size: 11px; line-height: 1.4; }.auth-aside__stamp { position: absolute; bottom: 31px; left: max(8vw, 60px); color: #566a85; font-family: "IBM Plex Mono", monospace; font-size: 10px; letter-spacing: .13em; }.auth-panel { display: flex; flex-direction: column; padding: 35px max(8vw, 70px); background: var(--surface); }.auth-panel__top { display: flex; align-items: center; justify-content: space-between; }.auth-panel__top .language-switch { margin-left: auto; }.auth-form { width: min(100%, 410px); margin: auto; }.auth-form__heading { display: flex; align-items: center; gap: 12px; margin-bottom: 34px; }.auth-form__icon { display: inline-grid; width: 43px; height: 43px; place-items: center; border-radius: 12px; background: var(--blue-soft); color: var(--blue); }.auth-form__heading h2 { margin: 0; font-family: "Space Grotesk", sans-serif; font-size: 27px; letter-spacing: -.06em; }.auth-form__heading .eyebrow { margin-bottom: 5px; }.auth-form > label { margin-bottom: 15px; }.input-with-icon { position: relative; }.input-with-icon svg { position: absolute; top: 13px; left: 12px; color: var(--muted); }.input-with-icon input { padding-left: 38px; }.form-error { margin: -2px 0 12px; color: var(--coral); font-size: 11px; }.auth-form__switch { margin: 19px 0 0; color: var(--muted); font-size: 11px; text-align: center; }.auth-form__switch a { color: var(--blue); font-weight: 600; }.auth-panel__footer { margin-top: auto; color: var(--muted); font-family: "IBM Plex Mono", monospace; font-size: 9px; }.auth-panel__footer span { display: inline-flex; align-items: center; gap: 6px; } -.center-page { display: grid; min-height: calc(100vh - 140px); place-items: center; padding: 40px 20px; }.center-card { display: grid; width: min(100%, 430px); justify-items: center; gap: 13px; border: 1px solid var(--line); border-radius: 18px; padding: 42px; background: var(--surface); box-shadow: var(--shadow); text-align: center; }.center-card--wide { width: min(100%, 520px); }.center-card__icon { display: inline-grid; width: 52px; height: 52px; place-items: center; border-radius: 15px; background: var(--blue-soft); color: var(--blue); }.center-card h1 { margin: 2px 0 0; font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -.065em; }.center-card > p:not(.eyebrow) { max-width: 320px; margin: 0 0 10px; color: var(--muted); font-size: 13px; line-height: 1.55; }.center-card .field-label { width: 100%; margin: 10px 0; text-align: left; } - -@keyframes timeline-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } } -@keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: translateY(0) scale(1); } } -@keyframes spin { to { transform: rotate(360deg); } } -@media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; } } -@media (max-width: 1100px) { .sidebar { width: 215px; }.main-content { margin-left: 215px; }.content-topbar { padding: 0 25px; }.page-container { padding: 34px 25px 70px; }.landing-hero { gap: 25px; }.landing-hero__copy h1 { font-size: 60px; }.hero-orbit--one { width: 330px; height: 420px; }.hero-orbit--two { width: 400px; height: 250px; } } -@media (max-width: 820px) { .sidebar { display: none; }.main-content { margin-left: 0; }.content-topbar { display: none; }.mobile-topbar { display: flex; height: 68px; align-items: center; justify-content: space-between; padding: 0 18px; border-bottom: 1px solid var(--line); background: var(--surface); }.mobile-topbar__actions { display: flex; align-items: center; gap: 4px; }.mobile-topbar .org-switcher { min-height: 34px; padding: 0 7px; }.mobile-topbar .org-switcher select { width: 105px; font-size: 10px; }.content-scroll { min-height: calc(100vh - 132px); padding-bottom: 70px; }.mobile-bottom-nav { position: fixed; z-index: 30; right: 0; bottom: 0; left: 0; display: grid; grid-template-columns: repeat(4, 1fr); height: 64px; border-top: 1px solid var(--line); background: rgba(255, 255, 255, .95); backdrop-filter: blur(16px); }.mobile-nav-link { display: grid; align-content: center; justify-items: center; gap: 4px; color: var(--muted); font-size: 9px; }.mobile-nav-link--active { color: var(--blue); }.page-container { padding: 28px 18px 50px; }.page-header { align-items: flex-start; flex-direction: column; gap: 16px; margin-bottom: 24px; }.page-header__actions { width: 100%; }.page-header__actions > .button { flex: 1; }.metrics-grid { grid-template-columns: 1fr 1fr; }.dashboard-grid, .detail-grid, .organization-grid, .account-layout { grid-template-columns: 1fr; }.quick-actions, .more-grid { grid-template-columns: 1fr; }.timeline-card { overflow-x: auto; }.timeline-card__header { min-width: 620px; }.timeline { min-width: 850px; }.timeline-card__legend { margin-right: 24px; }.table-head { display: none; }.table-row { grid-template-columns: 1fr auto; gap: 10px; padding: 15px 15px; }.table-row > span:nth-child(2), .table-row > span:nth-child(3), .table-row > strong, .table-row > .status-pill { grid-column: 2; justify-self: end; }.table-row__primary { grid-row: span 2; }.table-row > span:nth-child(2) { grid-row: 1; }.table-row > span:nth-child(3) { grid-row: 2; }.table-row > strong { grid-row: 3; }.table-row > .status-pill { grid-row: 4; }.row-actions { grid-row: 5; grid-column: 1 / -1; }.table-row--expense > span:nth-child(2), .table-row--expense > span:nth-child(3), .table-row--expense > strong, .table-row--expense > .status-pill { grid-column: 2; }.filter-bar { flex-wrap: wrap; }.search-field { max-width: none; flex-basis: 100%; }.select-field { flex: 1; }.organization-hero { align-items: flex-start; flex-wrap: wrap; }.organization-hero__status { width: 100%; margin-left: 66px; }.member-row__joined { display: none; }.landing { width: min(100% - 36px, 620px); }.landing-hero { grid-template-columns: 1fr; padding: 45px 0 65px; }.landing-hero__copy h1 { font-size: clamp(48px, 13vw, 73px); }.landing-hero__visual { min-height: 400px; margin-top: 15px; }.landing-signal > div:first-child { align-items: flex-start; flex-direction: column; gap: 20px; }.landing-signal h2 { font-size: 35px; }.landing-signal__grid { grid-template-columns: 1fr; gap: 4px; }.landing-signal__grid article { min-height: 165px; }.public-nav, .public-footer { width: calc(100% - 36px); }.public-nav { height: 70px; }.public-nav__actions .text-link { display: none; }.auth-layout { grid-template-columns: 1fr; min-height: calc(100vh - 70px); }.auth-aside { min-height: 345px; padding: 42px 25px; }.auth-aside h1 { max-width: 500px; font-size: 49px; }.auth-aside__stamp { bottom: 20px; left: 25px; }.auth-aside::after { right: -140px; bottom: -240px; }.auth-panel { min-height: 570px; padding: 25px; }.auth-form { margin: 45px auto; }.public-footer { align-items: flex-start; flex-direction: column; gap: 12px; }.stat-strip strong { font-size: 19px; } } -.mobile-topbar .notification-panel { position: fixed; top: 61px; right: 10px; left: 10px; width: auto; } -@media (max-width: 480px) { .health-badge span { display: none; }.health-badge { padding: 6px; }.page-header h1 { font-size: 36px; }.metrics-grid { gap: 8px; }.metric-card { min-height: 136px; padding: 14px; }.metric-card strong { margin-top: 13px; font-size: 22px; }.metric-card p { font-size: 10px; }.dashboard-intro__trend { display: none; }.timeline-card { margin-right: -18px; margin-left: -18px; border-right: 0; border-left: 0; border-radius: 0; }.surface-card--table { margin-right: -1px; margin-left: -1px; }.stat-strip { overflow: hidden; }.stat-strip > div { padding: 13px 10px; }.stat-strip span { font-size: 8px; }.stat-strip strong { font-size: 15px; }.modal { padding: 19px; }.form-grid { grid-template-columns: 1fr; }.profile-card__identity { align-items: flex-start; flex-wrap: wrap; }.profile-card__identity .button { width: 100%; }.preference-row { align-items: flex-start; flex-direction: column; justify-content: center; padding: 12px 0; }.preference-row > select, .theme-pills, .preference-row > .button { align-self: flex-start; }.landing-hero__visual { min-height: 340px; }.hero-desk-card { width: 94%; }.hero-float--top { top: 25px; right: -3px; }.hero-float--bottom { bottom: 24px; left: -4px; }.hero-orbit--one { width: 290px; height: 350px; }.hero-orbit--two { width: 330px; height: 220px; }.hero-desk-card__balance { margin: 30px 0 25px; }.hero-desk-card__balance strong { font-size: 33px; } } - -[data-theme="dark"] { --ink: #edf3ff; --ink-soft: #aab8cb; --muted: #8090a5; --paper: #0e1828; --surface: #142238; --line: #263750; --line-strong: #3b4d68; --blue-soft: #1d315b; --mint-soft: #133d3b; --amber-soft: #45341e; --coral-soft: #482733; --ink-deep: #0c1626; --shadow: 0 18px 50px rgba(0, 0, 0, .25); } -[data-theme="dark"] body, [data-theme="dark"] .sidebar, [data-theme="dark"] .content-topbar, [data-theme="dark"] .mobile-topbar { background: var(--paper); } -[data-theme="dark"] .sidebar, [data-theme="dark"] .content-topbar { background: #101c2e; } -[data-theme="dark"] .nav-link:hover, [data-theme="dark"] .compact-row:hover { background: #1b2a42; } -[data-theme="dark"] .org-switcher, [data-theme="dark"] .button--secondary, [data-theme="dark"] .icon-button:hover, [data-theme="dark"] .search-field, [data-theme="dark"] .select-field, [data-theme="dark"] .modal-form input, [data-theme="dark"] .modal-form select, [data-theme="dark"] .field-label input, [data-theme="dark"] .auth-form input, [data-theme="dark"] .account-form input, [data-theme="dark"] .inline-form input, [data-theme="dark"] .preference-row select, [data-theme="dark"] .theme-pill, [data-theme="dark"] .health-badge button { background: var(--surface); color: var(--ink); } -[data-theme="dark"] .health-badge, [data-theme="dark"] .sidebar__signal { background: #142b3c; border-color: #244d55; } -[data-theme="dark"] .landing-hero__visual .hero-float { background: #172944; border-color: #2c4260; } -[data-theme="dark"] .metric-card--mint { background: linear-gradient(135deg, var(--surface) 36%, var(--mint-soft)); } -[data-theme="dark"] .metric-card--amber { background: linear-gradient(135deg, var(--surface) 36%, var(--amber-soft)); } -[data-theme="dark"] .meter { background: var(--line-strong); } -[data-theme="dark"] .status-pill--upcoming, [data-theme="dark"] .status-pill--pending { color: #9db4ff; } -[data-theme="dark"] .status-pill--due { color: #f0b45c; } -[data-theme="dark"] .status-pill--overdue, [data-theme="dark"] .status-pill--cancelled { color: #ff8f99; } -[data-theme="dark"] .status-pill--paid { color: #4fd6b8; } diff --git a/apps/frontend-v2/src/types.ts b/apps/frontend-v2/src/types.ts deleted file mode 100644 index a3f859c..0000000 --- a/apps/frontend-v2/src/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { User } from "./api/auth/auth.types"; -export type { OrganizationSummary as Organization, OrganizationDetails } from "./api/organizations/organizations.types"; -export type { Bill, BillCategory, BillFrequency, BillSeriesType, BillStatus, BillDocument } from "./api/bills/bills.types"; -export type { Expense, ExpenseCategory, ExpenseStatus } from "./api/expenses/expenses.types"; diff --git a/apps/frontend-v2/src/ui.tsx b/apps/frontend-v2/src/ui.tsx deleted file mode 100644 index b1f6af3..0000000 --- a/apps/frontend-v2/src/ui.tsx +++ /dev/null @@ -1,232 +0,0 @@ -import { isValidElement, lazy, Suspense, useEffect, useRef, useState, type ButtonHTMLAttributes, type FormEvent, type ReactNode } from "react"; -import { Link, NavLink, Outlet, useLocation, useNavigate, useSearchParams } from "react-router-dom"; -import { - ArrowUpRight, - BarChart3, - Building2, - CalendarDays, - ChevronDown, - ChevronRight, - CircleDollarSign, - CreditCard, - FileText, - Globe2, - LayoutDashboard, - LogOut, - Menu, - Moon, - MoreHorizontal, - ReceiptText, - Settings2, - SunMedium, - UsersRound, - WalletCards, - X, -} from "lucide-react"; -import { useTranslation } from "react-i18next"; - -import { formatCurrency } from "./format"; -import { useAuth } from "./auth/auth-provider"; -import { useOrganizationStore } from "./auth/auth-store"; -import { useOrganizationsQuery } from "./hooks/use-queries"; -import { useTheme } from "./hooks/use-theme"; -import { NotificationBell } from "./notification-bell"; - -type ButtonVariant = "primary" | "secondary" | "ghost" | "danger"; - -export function BrandMark({ compact = false }: { compact?: boolean }) { - const { t } = useTranslation(); - return bitfinance; -} - -export function Button({ variant = "primary", className = "", children, ...props }: ButtonHTMLAttributes & { variant?: ButtonVariant }) { - return ; -} - -export function IconButton({ label, children, className = "", ...props }: ButtonHTMLAttributes & { label: string }) { - return ; -} - -export function Avatar({ initials, src, size = "md" }: { initials: string; src?: string; size?: "sm" | "md" | "lg" }) { - return src ? : {initials}; -} - -export function StatusPill({ status }: { status: string }) { - const { t } = useTranslation(); - const label = t(`statuses.${status}`, { defaultValue: status.replaceAll("_", " ") }); - return {label}; -} - -export function PageHeader({ eyebrow, title, description, actions }: { eyebrow: string; title: string; description?: string; actions?: ReactNode }) { - const labelsPeriodControl = isValidElement<{ className?: string }>(actions) && actions.props.className?.split(/\s+/).includes("period-control") === true; - return
{!labelsPeriodControl &&

{eyebrow}

}

{title}

{description &&

{description}

}
{actions &&
{labelsPeriodControl &&

{eyebrow}

}{labelsPeriodControl ? : actions}
}
; -} - -const dateParamPattern = /^\d{4}-\d{2}-\d{2}$/; - -function currentMonthInputs() { - const now = new Date(); - const from = new Date(now.getFullYear(), now.getMonth(), 1); - const to = new Date(now.getFullYear(), now.getMonth() + 1, 0); - const input = (date: Date) => `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; - return { from: input(from), to: input(to) }; -} - -function validDateInput(value: string | null) { - if (!value || !dateParamPattern.test(value)) return null; - const date = new Date(`${value}T12:00:00`); - return Number.isNaN(date.getTime()) ? null : value; -} - -export function PeriodPicker() { - const { i18n } = useTranslation(); - const [searchParams, setSearchParams] = useSearchParams(); - const defaults = currentMonthInputs(); - const selectedFrom = validDateInput(searchParams.get("from")) ?? defaults.from; - const selectedTo = validDateInput(searchParams.get("to")) ?? defaults.to; - const [open, setOpen] = useState(false); - const [from, setFrom] = useState(selectedFrom); - const [to, setTo] = useState(selectedTo); - const root = useRef(null); - const locale = i18n.language === "pt-BR" ? "pt-BR" : "en-US"; - const display = (value: string) => new Intl.DateTimeFormat(locale, { month: "short", day: "numeric" }).format(new Date(`${value}T12:00:00`)); - - useEffect(() => { - if (!open) return; - const close = (event: PointerEvent) => { if (!root.current?.contains(event.target as Node)) setOpen(false); }; - const escape = (event: KeyboardEvent) => { if (event.key === "Escape") setOpen(false); }; - document.addEventListener("pointerdown", close); - document.addEventListener("keydown", escape); - return () => { document.removeEventListener("pointerdown", close); document.removeEventListener("keydown", escape); }; - }, [open]); - - const toggle = () => { - if (!open) { setFrom(selectedFrom); setTo(selectedTo); } - setOpen((value) => !value); - }; - const apply = (event: FormEvent) => { - event.preventDefault(); - if (from > to) return; - const next = new URLSearchParams(searchParams); - next.set("from", from); - next.set("to", to); - setSearchParams(next, { replace: true }); - setOpen(false); - }; - const reset = () => { - const next = new URLSearchParams(searchParams); - next.delete("from"); - next.delete("to"); - setSearchParams(next, { replace: true }); - setFrom(defaults.from); - setTo(defaults.to); - setOpen(false); - }; - - const { t } = useTranslation(); - return
{open &&
{t("common.choosePeriod")}{t("common.periodUpdated")}
{from > to &&

{t("common.endDateError")}

}
}
; -} - -export function SectionHeading({ title, description, action }: { title: string; description?: string; action?: ReactNode }) { - return

{title}

{description &&

{description}

}
{action}
; -} - -export function MetricCard({ label, value, detail, tone = "blue", icon: Icon, progress }: { label: string; value: string; detail: string; tone?: "blue" | "mint" | "amber" | "ink"; icon: typeof WalletCards; progress?: number }) { - return
{label}
{value}

{detail}

{progress !== undefined &&
}
; -} - -export function EmptyState({ icon: Icon = FileText, title, description, action }: { icon?: typeof FileText; title: string; description: string; action?: ReactNode }) { - return

{title}

{description}

{action}
; -} - -export function Modal({ title, description, onClose, children, wide = false }: { title: string; description?: string; onClose: () => void; children: ReactNode; wide?: boolean }) { - const { t } = useTranslation(); - const ref = useRef(null); - useEffect(() => { - const handler = (event: KeyboardEvent) => { if (event.key === "Escape") onClose(); }; - document.addEventListener("keydown", handler); - ref.current?.focus(); - return () => document.removeEventListener("keydown", handler); - }, [onClose]); - return
{ if (event.target === event.currentTarget) onClose(); }}>
{description &&

{description}

}
{children}
; -} - -export function ActionMenu({ onEdit, onPaid, onDelete, onUpload, detailHref, canPay = false }: { onEdit: () => void; onPaid?: () => void; onDelete: () => void; onUpload?: () => void; detailHref?: string; canPay?: boolean }) { - const { t } = useTranslation(); - return }>; -} - -const LazyActionMenu = lazy(async () => { - const module = await import("./base-action-menu"); - return { default: module.BaseActionMenu }; -}); - -const navItems = [ - { to: "/dashboard", labelKey: "nav.overview", icon: LayoutDashboard, end: true }, - { to: "/dashboard/bills", labelKey: "nav.bills", icon: ReceiptText }, - { to: "/dashboard/expenses", labelKey: "nav.expenses", icon: CreditCard }, -]; - -function OrganizationSwitcher() { - const { user } = useAuth(); - const organizations = useOrganizationsQuery(Boolean(user)); - const selectedId = useOrganizationStore((state) => state.selectedOrganizationId); - const setSelectedId = useOrganizationStore((state) => state.setSelectedOrganizationId); - const items = organizations.data ?? user?.organizations ?? []; - const { t } = useTranslation(); - return ; -} - -function ThemeSwitcher() { - const { t } = useTranslation(); - const { theme, setTheme } = useTheme(); - const label = t("common.theme"); - return setTheme(theme === "dark" ? "light" : "dark")}>{theme === "dark" ? : }; -} - -function UserMenu() { - const { t } = useTranslation(); - const { user, signOut } = useAuth(); - const navigate = useNavigate(); - if (!user) return null; - const initials = user.fullName.split(/\s+/).slice(0, 2).map((part) => part[0]).join("").toUpperCase(); - return
{user.fullName}{user.email} { void signOut().finally(() => navigate("/auth/sign-in")); }}>
; -} - -export function AppShell() { - const { t } = useTranslation(); - const location = useLocation(); - return
{t("common.liveWorkspace")} / {location.pathname.includes("bills") ? t("nav.bills") : location.pathname.includes("expenses") ? t("nav.expenses") : location.pathname.includes("organization") ? t("nav.organization") : t("nav.overview")}
; -} - -export function PublicLayout({ children }: { children: ReactNode }) { - const { t, i18n } = useTranslation(); - return
{t("common.signIn")}{t("common.signUp")}
{children}
{t("home.footer")}
; -} - -export function KpiSparkline({ values, color = "#2f5bea" }: { values: number[]; color?: string }) { - const points = values.map((value, index) => `${(index / (values.length - 1)) * 100},${36 - value * 30}`).join(" "); - return ; -} - -export function QuickAction({ to, icon: Icon, label, detail }: { to: string; icon: typeof ArrowUpRight; label: string; detail: string }) { - return {label}{detail}; -} - -export function Currency({ value, locale = "en-US", className = "" }: { value: number; locale?: string; className?: string }) { - return {formatCurrency(value, locale)}; -} - -export function PageContainer({ children }: { children: ReactNode }) { - return
{children}
; -} - -export function MobileMenuButton({ onClick }: { onClick: () => void }) { - const { t } = useTranslation(); - return ; -} - -export function DataIcon({ type }: { type: "bill" | "expense" | "budget" | "team" }) { - const Icon = type === "bill" ? ReceiptText : type === "expense" ? BarChart3 : type === "budget" ? WalletCards : UsersRound; - return ; -} diff --git a/apps/frontend-v2/src/vite-env.d.ts b/apps/frontend-v2/src/vite-env.d.ts deleted file mode 100644 index 39fc679..0000000 --- a/apps/frontend-v2/src/vite-env.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -/// - -declare module "*.css"; diff --git a/apps/frontend-v2/tsconfig.app.json b/apps/frontend-v2/tsconfig.app.json deleted file mode 100644 index a8d321b..0000000 --- a/apps/frontend-v2/tsconfig.app.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "module": "ESNext", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "paths": { "@/*": ["./src/*"] } - }, - "include": ["src"] -} diff --git a/apps/frontend-v2/tsconfig.json b/apps/frontend-v2/tsconfig.json deleted file mode 100644 index 1ffef60..0000000 --- a/apps/frontend-v2/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/apps/frontend-v2/tsconfig.node.json b/apps/frontend-v2/tsconfig.node.json deleted file mode 100644 index 4564ff5..0000000 --- a/apps/frontend-v2/tsconfig.node.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "types": ["node"] - }, - "include": ["vite.config.ts"] -} diff --git a/apps/frontend-v2/vite.config.ts b/apps/frontend-v2/vite.config.ts deleted file mode 100644 index 7761a36..0000000 --- a/apps/frontend-v2/vite.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { fileURLToPath, URL } from "node:url"; - -import react from "@vitejs/plugin-react"; -import tailwindcss from "@tailwindcss/vite"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [react(), tailwindcss()], - resolve: { alias: { "@": fileURLToPath(new URL("./src", import.meta.url)) } }, - server: { port: 5174 }, -}); diff --git a/apps/frontend/.env.development.example b/apps/frontend/.env.development.example index 136c099..12d2b02 100644 --- a/apps/frontend/.env.development.example +++ b/apps/frontend/.env.development.example @@ -1,5 +1,2 @@ -# Development environment configuration template -# Copy this to .env.development or .env.local for local development - -# Development backend URL (local backend server) VITE_API_URL=http://localhost:8080/api/v1 +VITE_HEALTH_URL=http://localhost:8080/health diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example index 8148dd7..b10b4ff 100644 --- a/apps/frontend/.env.example +++ b/apps/frontend/.env.example @@ -1,7 +1,2 @@ -# Base environment configuration template -# Copy this to .env, .env.development, or .env.production and fill in values - -# API Base URL -# Development: http://localhost:8080/api/v1 -# Production: /api/v1 -VITE_API_URL= +VITE_API_URL=/api/v1 +VITE_HEALTH_URL=/health diff --git a/apps/frontend/.env.production.example b/apps/frontend/.env.production.example index caf2e3d..b10b4ff 100644 --- a/apps/frontend/.env.production.example +++ b/apps/frontend/.env.production.example @@ -1,5 +1,2 @@ -# Production environment configuration template -# GitHub Actions creates .env.production from secrets during deployment - -# Production API URL (same-origin routing with /api/v1 prefix) VITE_API_URL=/api/v1 +VITE_HEALTH_URL=/health diff --git a/apps/frontend/.eslintrc.json b/apps/frontend/.eslintrc.json deleted file mode 100644 index de77012..0000000 --- a/apps/frontend/.eslintrc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": [ - "next/core-web-vitals", - "next/typescript" - ], - "rules": { - "react/no-unescaped-entities": "off", - "@typescript-eslint/no-empty-object-type": "off", - "@typescript-eslint/no-explicit-any": "off" - } -} \ No newline at end of file diff --git a/apps/frontend/.gitignore b/apps/frontend/.gitignore deleted file mode 100644 index 9f0674b..0000000 --- a/apps/frontend/.gitignore +++ /dev/null @@ -1,48 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# ide files -.vscode -.idea - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build -/dist -/dev-dist - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Environment files (security: never commit actual .env files) -.env -.env*.local -.env.development -.env.production - -# Exception: DO commit .env.example files (templates only) -!.env*.example - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/apps/frontend/.npmrc b/apps/frontend/.npmrc deleted file mode 100644 index a827580..0000000 --- a/apps/frontend/.npmrc +++ /dev/null @@ -1 +0,0 @@ -min-version-age=7d diff --git a/apps/frontend/.prettierignore b/apps/frontend/.prettierignore new file mode 100644 index 0000000..758cab9 --- /dev/null +++ b/apps/frontend/.prettierignore @@ -0,0 +1,4 @@ +coverage +dist +node_modules +pnpm-lock.yaml diff --git a/apps/frontend/.prettierrc.json b/apps/frontend/.prettierrc.json new file mode 100644 index 0000000..90abee2 --- /dev/null +++ b/apps/frontend/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "printWidth": 100, + "semi": true, + "singleQuote": false, + "trailingComma": "all" +} diff --git a/apps/frontend/AGENTS.md b/apps/frontend/AGENTS.md deleted file mode 100644 index 847072c..0000000 --- a/apps/frontend/AGENTS.md +++ /dev/null @@ -1,165 +0,0 @@ -# AGENTS.md - Coding Guidelines for BitFinance Frontend - -## Project Overview - -React + TypeScript + Vite finance dashboard app with: -- TanStack Query for server state -- Zustand for shared client auth/organization state -- Tailwind CSS + Radix UI for UI -- `react-i18next` with locale files in `src/i18n/locales` - -## Build/Development Commands - -```bash -# Development server -npm run dev - -# Type check + production build -npm run build - -# ESLint linting -npm run lint - -# Preview production build locally -npm run preview - -# Install dependencies -npm install -``` - -## Code Style Guidelines - -### TypeScript Configuration - -- **Target**: ES2020, strict mode enabled -- **Path alias**: use `@/` for imports from `src/` -- **No unused locals/parameters**: clean up unused code -- **No fallthrough in switch**: explicit breaks required - -### Import Order - -```typescript -// 1. React imports -import { useState, useEffect } from "react"; - -// 2. External libraries -import { useQuery } from "@tanstack/react-query"; -import { toast } from "sonner"; - -// 3. Internal aliases (@/) -import { authService } from "@/api/auth"; -import { Button } from "@/components/ui/button"; - -// 4. Relative imports -import { SomeComponent } from "./some-component"; -``` - -### Naming Conventions - -- **Components**: PascalCase (`UserProfile.tsx`, `Dashboard.tsx`) -- **Files/Folders**: kebab-case (`use-breadcrumbs.ts`, `auth-provider.tsx`, `auth-store.ts`) -- **Functions**: camelCase (`fetchUserData`, `handleSubmit`) -- **Interfaces/Types**: PascalCase (`SignInResponse`, `User`, `AuthClientState`) -- **Hooks**: `use*` prefix (`useLoginAction`, `useSelectedOrganization`) -- **API Methods**: `camelCase + Async` (`signInAsync`, `listAsync`) - -### Component Structure - -```typescript -export function ComponentName() { - return
...
; -} -``` - -### Styling with Tailwind - -- Use `cn()` from `@/lib/utils` for class merging -- Follow mobile-first responsive design -- Use `dark:` styles when needed -- Prefer Tailwind utilities over custom CSS - -## Architecture Guidelines - -### State Management - -- **Server state**: TanStack Query (`src/hooks/queries`, `src/hooks/mutations`) -- **Shared client state**: Zustand auth store in `src/auth/auth-store.ts` -- **Local UI state**: component-level `useState` -- Do **not** reintroduce a monolithic auth context (`useAuth()` was removed) - -### Authentication - -- `AuthProvider` in `src/auth/auth-provider.tsx` is a bootstrap/controller layer (session restore, refresh-failure handling, org consistency) -- Prefer selector/action hooks from `@/auth/auth-provider`: - - `useIsAuthenticated` - - `useAuthInitialization` - - `useCurrentUser` - - `useSelectedOrganization` - - `useSelectedOrganizationId` - - `useSetSelectedOrganizationId` - - `useLoginAction` - - `useRegisterAction` - - `useLogoutAction` - - `useGetMeAction` -- `selectedOrganizationId` is persisted (`bitfinance-auth` storage key) -- Access token for Axios interceptors is mirrored via `@/lib/auth-token` - -### API Patterns - -- API modules are feature-based: - - `@/api/auth` - - `@/api/bills` - - `@/api/expenses` -- Keep HTTP concerns in service files under `src/api/*` -- Normalize API errors via `src/api/shared/normalize-error.ts` -- Use `api` for public endpoints and `authApi`/`privateAPI()` for authenticated endpoints - -### Error Handling - -- Use `logger` from `@/lib/logger` for development diagnostics -- API error toasts are global in Axios interceptors (`src/lib/axios.ts`) -- Avoid duplicate page-level API error toasts unless intentionally overriding UX -- `Toaster` is mounted once at app level in `src/app.tsx` - -### Routing - -- Routes are defined in `src/routes.tsx` -- Protected pages use `` -- Page components live in `src/pages/{feature}/` - -### Internationalization (i18n) - -- Use `useTranslation()` from `react-i18next` -- i18n runtime config: `src/i18n/config.ts` -- Translation files: `src/i18n/locales/{lng}.json` - -### File Organization - -```text -src/ -├── api/ # API calls by feature + shared error normalization -├── auth/ # Zustand auth store + auth provider hooks/bootstrap -├── components/ # Reusable components -│ └── ui/ # Radix UI-based primitives -├── hooks/ # Query/mutation and utility hooks -├── layouts/ # Route/layout wrappers -├── lib/ # Axios, auth-token, logger, query client, utils -├── pages/ # Page components by feature -├── i18n/ # i18n setup -└── utils/ # Helper functions -``` - -## ESLint Rules - -- React Hooks rules enforced -- React Refresh restrictions enforced -- TypeScript recommended rules enabled -- `npm run build` runs type-check before build - -## Quick Reference - -- **Dev server**: `npm run dev` (Vite default: http://localhost:5173) -- **Build**: `npm run build` -- **Path alias**: `@/` maps to `src/` -- **Tailwind config**: `tailwind.config.js` -- **Environment vars**: use `import.meta.env.VITE_*` diff --git a/apps/frontend/Dockerfile b/apps/frontend/Dockerfile deleted file mode 100644 index 5b51c04..0000000 --- a/apps/frontend/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM node:22-alpine - -WORKDIR /app - -COPY package.json . -RUN npm install -RUN npm i -g serve - -COPY . . -RUN npm run build - -EXPOSE 3000 - -CMD [ "serve", "-s", "dist" ] diff --git a/apps/frontend/LICENSE b/apps/frontend/LICENSE deleted file mode 100644 index 98ae35d..0000000 --- a/apps/frontend/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2023-2026 Gustavo Miranda - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/apps/frontend/README.md b/apps/frontend/README.md index 88a58d0..340a49c 100644 --- a/apps/frontend/README.md +++ b/apps/frontend/README.md @@ -1,155 +1,68 @@ -

- BitFinance app icon -

+# BitFinance frontend -# BitFinance +The BitFinance web client is a React 19, TypeScript, and Vite application. It +uses typed services under `src/api`, TanStack Query for server state, and +Zustand for the selected organization preference. -![React Version](https://img.shields.io/badge/React-18-61DAFB?logo=react) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +Production is served from `https://bitfinance.gustavomiranda.dev`. API and +health requests use same-origin `/api/v1` and `/health` routes. -BitFinance is a finance platform for tracking bills, expenses, organizations, and financial activity. This package contains the web application. - -## Features - -- Track bills and expenses by organization -- View dashboard summaries for upcoming bills and recent expenses -- Create, join, and manage organizations -- Invite organization members -- Upload and manage bill or expense documents -- Manage account profile and avatar settings -- Support authenticated sessions with refresh-token based API integration -- Provide installable PWA assets through Vite PWA - -## Tech Stack - -- **React 18** for the user interface -- **TypeScript** for static typing -- **Vite** for local development and production builds -- **React Router** for client-side routing -- **TanStack Query** for server state -- **Zustand** for shared auth and organization state -- **Axios** for API requests -- **Tailwind CSS** and **Radix UI** for styling and primitives -- **react-i18next** for internationalization -- **vite-plugin-pwa** for PWA manifest and assets - -## Getting Started - -### Prerequisites - -- Node.js 22 or newer is recommended -- pnpm -- A running BitFinance backend API - -### Installation - -1. Install dependencies from this directory. - - ```bash - pnpm install - ``` - -2. Create a local environment file. - - ```bash - cp .env.development.example .env.local - ``` - -3. Start the development server. - - ```bash - pnpm dev - ``` - -The app runs at `http://localhost:3000` and expects the backend API at `http://localhost:8080/api/v1` by default. - -## Environment Variables - -Vite only exposes variables prefixed with `VITE_` to the browser. - -| Variable | Description | Local default | -| --- | --- | --- | -| `VITE_API_URL` | Base URL for the BitFinance API | `http://localhost:8080/api/v1` | - -Environment templates are included for common modes: - -- `.env.example` for a generic template -- `.env.development.example` for local development -- `.env.production.example` for production builds - -Use `.env.local` for personal overrides. Do not commit real `.env` files. - -## Available Scripts +## Run locally ```bash -pnpm dev # Start the Vite development server -pnpm build # Type-check and create a production build -pnpm lint # Run ESLint -pnpm preview # Preview the production build locally +cd apps/frontend +pnpm install --frozen-lockfile +cp .env.development.example .env.local +pnpm dev ``` -## API Organization +The Vite server uses port `5174`. The backend must allow that origin with +credentials. -API modules are organized by feature under `src/api`. +## Checks -```text -src/api/ - account/ - auth/ - bills/ - dashboard/ - expenses/ - organizations/ - shared/ +```bash +pnpm format:check +pnpm lint +pnpm build ``` -Conventions: - -- Import API clients from feature barrels such as `@/api/auth`, `@/api/bills`, and `@/api/expenses`. -- Use `camelCase + Async` for service methods, for example `billsService.listAsync`. -- Keep HTTP concerns inside service files. -- Keep shared API error normalization in `src/api/shared`. -- API error toasts are handled globally through Axios interceptors. +There is currently no automated frontend test suite. Pull request and release +validation both run the checks above. -## Routing +## PWA -Routes are defined in `src/routes.tsx`. +`vite-plugin-pwa` generates `manifest.webmanifest` and a root-scoped `sw.js`. +The worker automatically updates, precaches the application shell and +revisioned static assets, and removes outdated Workbox caches. API, identity, +health, and upload responses are not runtime-cached. The manifest supports both +portrait and landscape orientation. -Main routes include: - -- `/` for the public home page -- `/auth/sign-in` and `/auth/sign-up` for authentication -- `/dashboard` for the authenticated dashboard -- `/dashboard/bills` and `/dashboard/bills/:billId` -- `/dashboard/expenses` and `/dashboard/expenses/:expenseId` -- `/account/settings`, `/account/more`, and `/account/organization` -- `/account/create-organization` -- `/join-organization` - -Authenticated pages are wrapped with `ProtectedRoute`. - -## Build and Deployment - -Create a production build with: +PWA assets are generated from `public/favicon.svg`: ```bash -pnpm build +pnpm generate:pwa-assets ``` -Production builds use `VITE_API_URL=/api/v1` by default, which supports same-origin API routing behind a reverse proxy. - -The included `Dockerfile` builds the Vite app and serves the generated `dist` directory on port `3000`. +After a production build, verify the generated files and installability in +browser developer tools. Also test offline shell loading, an API-dependent +screen's connection error, a direct refresh on a nested route, desktop install, +iPhone Home Screen install, and an update from the previous deployed worker. -Deployment automation lives in `.github/workflows/frontend-deploy.yml` and runs when a -`frontend/v*` release tag is pushed, for example: +## Design notes -```bash -git tag frontend/v1.11.0 -git push origin frontend/v1.11.0 -``` +The interface is a modern finance desk. Ledger Ink, Paper, Cobalt, Mint, Amber, +and Coral create a calm finance workspace. Space Grotesk gives headings a +deliberate voice, Figtree keeps interface copy warm, and IBM Plex Mono makes +dates and amounts easy to scan. -The tag version must match the version in `apps/frontend/package.json`. +The app includes English and Brazilian Portuguese copy, responsive +desktop/mobile navigation, light and dark themes, accessible focus states, +reduced-motion handling, server-backed CRUD, uploads/downloads, and explicit +loading, empty, offline, and error states. -## License +## Deployment -Distributed under the MIT License. See [LICENSE](LICENSE) for details. +Releases use immutable versioned directories and an atomic `current` symlink. +See [`docs/deployment.md`](docs/deployment.md) for initial server migration, +release, cutover, redirect, verification, and rollback procedures. diff --git a/apps/frontend/components.json b/apps/frontend/components.json deleted file mode 100644 index 726ff34..0000000 --- a/apps/frontend/components.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/index.css", - "baseColor": "zinc", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - } -} diff --git a/apps/frontend/docs/org-management-invite-plan.md b/apps/frontend/docs/org-management-invite-plan.md deleted file mode 100644 index 2045b8c..0000000 --- a/apps/frontend/docs/org-management-invite-plan.md +++ /dev/null @@ -1,351 +0,0 @@ -# Org Management And Invite Flow Plan - -## Goal - -Prioritize frontend integration for organization management and invitation flows using the backend already implemented in `bitfinance-backend`. - -## Product Decisions - -- Organization management should include role management. -- Invitation links can use a simple token-processing page for the first pass. -- After joining a new organization, the frontend should automatically switch to it. - -## Backend Endpoints In Scope - -### Organizations - -- `GET /api/v1/organizations` -- `GET /api/v1/organizations/{organizationId}` -- `POST /api/v1/organizations` -- `PATCH /api/v1/organizations/{organizationId}` -- `POST /api/v1/organizations/{organizationId}/invite` -- `POST /api/v1/organizations/join?token=...` - -### Related Auth - -- `GET /api/v1/identity/me` -- `POST /api/v1/identity/login` -- `POST /api/v1/identity/register` -- `POST /api/v1/identity/refresh` - -## Current Frontend State - -### Already implemented - -- Auth bootstrap and session restore -- Organization selection from `me.organizations` -- Create organization page -- Protected routing and selected organization persistence -- Organization management page and invite flow -- Invitation join flow with auth resume and auto-switch -- Bills contract cleanup, details, and attachment flows -- Expenses contract cleanup, details, and attachment flows -- Account security and avatar frontend flows with placeholder avatar support - -### Missing frontend integration - -- Organization list fetch from `/organizations` -- Organization detail fetch -- Organization update flow -- Organization members view -- Invitation creation flow -- Invitation acceptance and join flow -- Auth-aware invitation entry flow -- Role management UI - -## Backend Gap For Role Management - -Full member role editing is not yet possible with the currently exposed backend API. - -- `GET /organizations/{organizationId}` returns members with `id`, `username`, and `email`, but no role. -- There is no endpoint to update an existing member's role. -- `POST /organizations/{organizationId}/invite` does accept a role, so role selection can be supported for invitations. - -Frontend work should therefore be split into two parts. - -- Phase 1 supports role-aware invitations and prepares organization role types. -- A later phase can add member role editing once the backend exposes member role data and a role update endpoint. - -## Priority Order - -1. Organization services and types -2. Organization management page -3. Invite member flow -4. Join organization flow -5. Auth redirect improvements -6. Navigation and empty states -7. Cleanup and contract verification - -## Phase 1: Service Layer - -Status: Done - -Create a dedicated `src/api/organizations/` feature module to match current API organization conventions. - -### Add - -- `organizations.service.ts` -- `organizations.types.ts` -- `index.ts` - -### Service methods - -- `listAsync()` -- `getAsync(organizationId)` -- `createAsync(request)` -- `updateAsync(request)` -- `createInviteAsync(request)` -- `joinAsync(token)` - -### Types - -- `OrganizationSummary` -- `OrganizationDetails` -- `OrganizationMember` -- `OrganizationRole` -- `CreateOrganizationRequest` -- `UpdateOrganizationRequest` -- `CreateInvitationRequest` -- `CreateInvitationResponse` - -### Phase 1 implementation notes - -- Keep role values frontend-friendly and map them to the backend shape in the service layer. -- Replace the one-off `create-organization.ts` helper with the new organizations module. -- Keep current create organization UI working with the new module before moving to later phases. - -## Phase 2: Query And Mutation Hooks - -Status: Done - -Add TanStack Query hooks for organization management. - -### Queries - -- `use-organizations-query.ts` -- `use-organization-query.ts` - -### Mutations - -- `use-organization-mutations.ts` - -### Query invalidation - -Invalidate the following when organization state changes. - -- `auth.me` -- organization lists -- organization detail -- any views dependent on current organization selection - -## Phase 3: Organization Management UI - -Status: Done - -Create a management page for the selected organization. - -### Recommended route - -- `/account/organization` - -### Page responsibilities - -- Show organization name -- Show members list -- Allow renaming organization -- Allow inviting a member -- Show invite result or copyable join token and link -- Reserve a role management section for current members once the backend exposes that capability - -### Likely components - -- `organization-settings-form.tsx` -- `organization-members-list.tsx` -- `invite-member-dialog.tsx` - -## Phase 4: Invite Flow - -Status: Done - -Use backend `POST /organizations/{organizationId}/invite`. - -### UI - -- Dialog or form from organization management page -- Inputs for email and role -- Success state with generated join link and expiration info - -### UX - -- Provide copy action for token and full join link -- Keep the first pass simple and token-driven - -## Phase 5: Join Flow - -Status: Done - -Create an invitation join route. - -### Recommended route - -- `/join-organization` - -### Behavior - -- Read `token` from the query string -- If authenticated, call `joinAsync(token)` -- Refresh `me` -- Automatically switch the selected organization to the newly joined organization -- Navigate to the dashboard after success -- If unauthenticated, redirect to sign-in with a preserved `returnUrl` -- After auth, resume the join flow automatically - -### Components and pages - -- `src/pages/organizations/join.tsx` - -## Phase 6: Auth Redirect Improvements - -Status: Done - -Current sign-in redirects directly to `/dashboard`. - -### Update behavior - -- Respect `returnUrl` after sign-in and sign-up -- Support invitation join resume after auth -- If an authenticated user has zero organizations, redirect to `account/create-organization` - -## Phase 7: Navigation Updates - -Status: Done - -Expose organization management in the app. - -### Options - -- Add `Organization` under the account section -- Keep `Create Organization` in the More page -- Optionally add a quick path from the organization switcher when there are no organizations - -## Phase 8: Existing Member Role Management - -Status: Blocked by backend - -Complete role management for existing members once the backend exposes the missing capabilities. - -### Backend requirements - -- Include member roles in `GET /organizations/{organizationId}` -- Add an endpoint to update a member role within an organization - -### Frontend work - -- Replace the current role-management placeholder in the members list -- Show each member's current role -- Add inline or dialog-based role editing -- Refresh organization detail after role changes - -## Phase 9: Account Security And Avatar Management - -Status: Frontend implemented, backend follow-up pending - -Integrate the remaining implemented identity endpoints that are still not surfaced in the frontend. - -### Endpoints - -- `POST /api/v1/identity/manage/avatar` -- `DELETE /api/v1/identity/manage/avatar` -- `POST /api/v1/identity/logout-all` - -### Frontend work - -- Add avatar upload and remove actions in account settings -- Replace placeholder avatar handling in nav and account surfaces -- Add a `log out all devices` action in account settings or More - -### Current result - -- Frontend account security and avatar UI is implemented -- Avatar upload, remove, and `logout-all` actions are wired -- Navigation surfaces use `avatarUrl` when available and fall back to a placeholder image for now -- Full avatar rendering still depends on the backend returning `avatarUrl` from `GET /identity/me` - -## Phase 10: Dashboard Summary Integration - -Status: Blocked by backend summary endpoint - -Replace the remaining mocked dashboard summary cards with backend-backed data. - -### Backend requirement - -- Add a summary endpoint for dashboard totals and budget metrics - -### Frontend work - -- Remove mocked summary values from the dashboard page -- Add summary query hooks and API module -- Keep upcoming bills and recent expenses as separate queries unless the backend consolidates them - -## Phase 11: Final Backend Parity Review - -Status: Pending - -Do one final parity pass after the phases above are complete. - -### Review checklist - -- Verify every implemented backend endpoint is either integrated or intentionally unused -- Re-check request and response type alignment -- Re-check route coverage and empty states -- Re-check auth redirects and organization switching behavior -- Re-check bundle size impact of the added flows - -## Refactors Needed - -- `src/routes.tsx` -- `src/layouts/app-navigation.ts` -- `src/pages/account/more.tsx` -- `src/auth/auth-provider.tsx` -- `src/components/organization-switcher.tsx` - -These routes and shared auth flows will need small refactors to support organization settings, invitation entry, and auto-switch behavior after join. - -Additional files will be touched in later phases for avatar management, existing-member role editing, and dashboard summary integration. - -## Acceptance Criteria - -- User can open organization settings for the selected organization -- User can rename an organization -- User can view organization members -- User can create an invite with a selected role and copy a join link -- Authenticated user can join an organization from an invite token -- Unauthenticated user can sign in and resume joining from an invite token -- After a successful join, the frontend automatically switches to the new organization -- `me` data refreshes after organization creation or join -- Selected organization remains consistent after joins and switches - -## Out Of Scope For This Pass - -- Existing-member role editing until backend support is available -- Dashboard summary metrics until the backend exposes a summary endpoint - -## Suggested Implementation Sequence - -1. Add `src/api/organizations/*` -2. Add organization query and mutation hooks -3. Add `/account/organization` route and page -4. Add invite dialog and members list -5. Add `/join-organization` route and token flow -6. Update auth redirect handling -7. Update navigation and zero-org states -8. Verify end-to-end with the local backend - -## Follow-Up Phases - -The following phases should be completed to reach fuller backend parity after the organization workflow foundation is in place. - -1. Phase 8: existing member role management -2. Phase 9: account security and avatar management -3. Phase 10: dashboard summary integration -4. Phase 11: final backend parity review diff --git a/apps/frontend/eslint.config.js b/apps/frontend/eslint.config.js index 922806f..a269c37 100644 --- a/apps/frontend/eslint.config.js +++ b/apps/frontend/eslint.config.js @@ -1,30 +1,19 @@ -import js from '@eslint/js' -import globals from 'globals' -import tanstackQuery from '@tanstack/eslint-plugin-query' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' +import js from "@eslint/js"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; export default tseslint.config( - { ignores: ['dist', 'dev-dist'] }, - ...tanstackQuery.configs['flat/recommended'], + { ignores: ["dist", "coverage"] }, + js.configs.recommended, + ...tseslint.configs.recommended, { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ['**/*.{ts,tsx}'], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - }, + files: ["**/*.{ts,tsx}"], + plugins: { "react-hooks": reactHooks, "react-refresh": reactRefresh }, rules: { ...reactHooks.configs.recommended.rules, - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], + "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], }, }, -) +); diff --git a/apps/frontend/index.html b/apps/frontend/index.html index 9c49dfa..6f3d292 100644 --- a/apps/frontend/index.html +++ b/apps/frontend/index.html @@ -1,44 +1,18 @@ - - + + - - - + + + - - - - - - - - BitFinance - - + + + + BitFinance - finance desk
diff --git a/apps/frontend/package.json b/apps/frontend/package.json index a8683f2..a81fe9d 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -1,75 +1,49 @@ { - "name": "bitfinance-app", + "name": "bitfinance-frontend", "private": true, - "version": "1.13.0", + "version": "2.0.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc -b && vite build", + "format": "prettier --write src", + "format:check": "prettier --check src", + "generate:pwa-assets": "pwa-assets-generator --preset minimal-2023 public/favicon.svg", "lint": "eslint .", "preview": "vite preview" }, "dependencies": { - "@hookform/resolvers": "^3.9.0", - "@radix-ui/react-alert-dialog": "^1.1.2", - "@radix-ui/react-avatar": "^1.1.1", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.6", - "@radix-ui/react-label": "^2.1.2", - "@radix-ui/react-popover": "^1.1.2", - "@radix-ui/react-progress": "^1.1.2", - "@radix-ui/react-select": "^2.1.2", - "@radix-ui/react-separator": "^1.1.2", - "@radix-ui/react-slot": "^1.1.2", - "@radix-ui/react-toast": "^1.2.6", - "@radix-ui/react-tooltip": "^1.1.8", - "@tanstack/react-query": "^5.59.13", - "axios": "^1.7.7", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "cmdk": "^1.0.0", - "date-fns": "^3.6.0", - "i18next": "^25.5.2", - "i18next-browser-languagedetector": "^8.0.4", - "lucide-react": "^0.452.0", - "next-themes": "^0.4.6", - "react": "^18.3.1", - "react-day-picker": "^8.10.1", - "react-dom": "^18.3.1", - "react-hook-form": "^7.53.0", - "react-i18next": "^15.4.1", - "react-router-dom": "^6.27.0", - "sonner": "^2.0.7", - "tailwind-merge": "^2.5.3", - "tailwindcss-animate": "^1.0.7", - "vaul": "^1.1.2", - "zod": "^3.23.8", - "zustand": "^5.0.7" + "@base-ui/react": "1.6.0", + "@tanstack/react-query": "^5.101.2", + "axios": "^1.18.1", + "date-fns": "4.4.0", + "i18next": "26.3.6", + "lucide-react": "1.24.0", + "react": "19.2.7", + "react-dom": "19.2.7", + "react-i18next": "17.0.9", + "react-router-dom": "7.18.1", + "sonner": "2.0.7", + "zod": "4.4.3", + "zustand": "5.0.14" }, "devDependencies": { - "@eslint/js": "^9.11.1", - "@tanstack/eslint-plugin-query": "^5.59.7", - "@types/node": "^22.7.5", - "@types/react": "^18.3.10", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.2", - "autoprefixer": "^10.4.20", - "eslint": "^9.11.1", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.12", - "globals": "^15.9.0", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.13", - "typescript": "^5.5.3", - "typescript-eslint": "^8.7.0", - "vite": "^6.3.4", - "vite-plugin-pwa": "^0.21.1", - "workbox-window": "^7.4.1" + "@eslint/js": "10.0.1", + "@tailwindcss/vite": "4.3.2", + "@types/node": "26.1.1", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", + "@vite-pwa/assets-generator": "1.0.2", + "@vitejs/plugin-react": "6.0.3", + "eslint": "10.6.0", + "eslint-plugin-react-hooks": "7.1.1", + "eslint-plugin-react-refresh": "0.5.3", + "prettier": "^3.9.6", + "tailwindcss": "4.3.2", + "typescript": "5.9.3", + "typescript-eslint": "8.63.0", + "vite": "8.1.4", + "vite-plugin-pwa": "1.3.0" }, - "packageManager": "pnpm@11.0.9", - "pnpm": { - "overrides": { - "@radix-ui/react-focus-scope": "1.0.4" - } - } + "packageManager": "pnpm@11.0.9" } diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 169f5cf..5ef8959 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -8,211 +8,135 @@ importers: .: dependencies: - '@hookform/resolvers': - specifier: ^3.9.0 - version: 3.10.0(react-hook-form@7.75.0(react@18.3.1)) - '@radix-ui/react-alert-dialog': - specifier: ^1.1.2 - version: 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-avatar': - specifier: ^1.1.1 - version: 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dialog': - specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dropdown-menu': - specifier: ^2.1.6 - version: 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-label': - specifier: ^2.1.2 - version: 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popover': - specifier: ^1.1.2 - version: 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-progress': - specifier: ^1.1.2 - version: 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-select': - specifier: ^2.1.2 - version: 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': - specifier: ^1.1.2 - version: 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': - specifier: ^1.1.2 - version: 1.2.4(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-toast': - specifier: ^1.2.6 - version: 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tooltip': - specifier: ^1.1.8 - version: 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@base-ui/react': + specifier: 1.6.0 + version: 1.6.0(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/react-query': - specifier: ^5.59.13 - version: 5.100.10(react@18.3.1) + specifier: ^5.101.2 + version: 5.101.2(react@19.2.7) axios: - specifier: ^1.7.7 - version: 1.16.0 - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - cmdk: - specifier: ^1.0.0 - version: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^1.18.1 + version: 1.18.1 date-fns: - specifier: ^3.6.0 - version: 3.6.0 + specifier: 4.4.0 + version: 4.4.0 i18next: - specifier: ^25.5.2 - version: 25.10.10(typescript@5.9.3) - i18next-browser-languagedetector: - specifier: ^8.0.4 - version: 8.2.1 + specifier: 26.3.6 + version: 26.3.6(typescript@5.9.3) lucide-react: - specifier: ^0.452.0 - version: 0.452.0(react@18.3.1) - next-themes: - specifier: ^0.4.6 - version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 1.24.0 + version: 1.24.0(react@19.2.7) react: - specifier: ^18.3.1 - version: 18.3.1 - react-day-picker: - specifier: ^8.10.1 - version: 8.10.2(date-fns@3.6.0)(react@18.3.1) + specifier: 19.2.7 + version: 19.2.7 react-dom: - specifier: ^18.3.1 - version: 18.3.1(react@18.3.1) - react-hook-form: - specifier: ^7.53.0 - version: 7.75.0(react@18.3.1) + specifier: 19.2.7 + version: 19.2.7(react@19.2.7) react-i18next: - specifier: ^15.4.1 - version: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3) + specifier: 17.0.9 + version: 17.0.9(i18next@26.3.6(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3) react-router-dom: - specifier: ^6.27.0 - version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 7.18.1 + version: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) sonner: - specifier: ^2.0.7 - version: 2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - tailwind-merge: - specifier: ^2.5.3 - version: 2.6.1 - tailwindcss-animate: - specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.19) - vaul: - specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 2.0.7 + version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) zod: - specifier: ^3.23.8 - version: 3.25.76 + specifier: 4.4.3 + version: 4.4.3 zustand: - specifier: ^5.0.7 - version: 5.0.13(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + specifier: 5.0.14 + version: 5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)) devDependencies: '@eslint/js': - specifier: ^9.11.1 - version: 9.39.4 - '@tanstack/eslint-plugin-query': - specifier: ^5.59.7 - version: 5.100.10(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + specifier: 10.0.1 + version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) + '@tailwindcss/vite': + specifier: 4.3.2 + version: 4.3.2(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0)) '@types/node': - specifier: ^22.7.5 - version: 22.19.19 + specifier: 26.1.1 + version: 26.1.1 '@types/react': - specifier: ^18.3.10 - version: 18.3.28 + specifier: 19.2.17 + version: 19.2.17 '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.17) + '@vite-pwa/assets-generator': + specifier: 1.0.2 + version: 1.0.2 '@vitejs/plugin-react': - specifier: ^4.3.2 - version: 4.7.0(vite@6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1)) - autoprefixer: - specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) + specifier: 6.0.3 + version: 6.0.3(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0)) eslint: - specifier: ^9.11.1 - version: 9.39.4(jiti@1.21.7) + specifier: 10.6.0 + version: 10.6.0(jiti@2.7.0) eslint-plugin-react-hooks: - specifier: ^5.1.0-rc.0 - version: 5.2.0(eslint@9.39.4(jiti@1.21.7)) + specifier: 7.1.1 + version: 7.1.1(eslint@10.6.0(jiti@2.7.0)) eslint-plugin-react-refresh: - specifier: ^0.4.12 - version: 0.4.26(eslint@9.39.4(jiti@1.21.7)) - globals: - specifier: ^15.9.0 - version: 15.15.0 - postcss: - specifier: ^8.4.47 - version: 8.5.14 + specifier: 0.5.3 + version: 0.5.3(eslint@10.6.0(jiti@2.7.0)) + prettier: + specifier: ^3.9.6 + version: 3.9.6 tailwindcss: - specifier: ^3.4.13 - version: 3.4.19 + specifier: 4.3.2 + version: 4.3.2 typescript: - specifier: ^5.5.3 + specifier: 5.9.3 version: 5.9.3 typescript-eslint: - specifier: ^8.7.0 - version: 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + specifier: 8.63.0 + version: 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) vite: - specifier: ^6.3.4 - version: 6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1) + specifier: 8.1.4 + version: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0) vite-plugin-pwa: - specifier: ^0.21.1 - version: 0.21.2(vite@6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1))(workbox-build@7.4.1(@types/babel__core@7.20.5))(workbox-window@7.4.1) - workbox-window: - specifier: ^7.4.1 - version: 7.4.1 + specifier: 1.3.0 + version: 1.3.0(@vite-pwa/assets-generator@1.0.2)(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0))(workbox-build@7.4.1)(workbox-window@7.4.1) packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - '@apideck/better-ajv-errors@0.3.7': resolution: {integrity: sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==} engines: {node: '>=10'} peerDependencies: ajv: '>=8' - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.29.3': - resolution: {integrity: sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==} + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.28.5': - resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + '@babel/helper-create-regexp-features-plugin@7.29.7': + resolution: {integrity: sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -222,105 +146,105 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + '@babel/helper-remap-async-to-generator@7.29.7': + resolution: {integrity: sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.28.6': - resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.28.6': - resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} + '@babel/helper-wrap-function@7.29.7': + resolution: {integrity: sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': - resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7': + resolution: {integrity: sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': - resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7': + resolution: {integrity: sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': - resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7': + resolution: {integrity: sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.3': - resolution: {integrity: sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==} + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7': + resolution: {integrity: sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': - resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7': + resolution: {integrity: sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': - resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7': + resolution: {integrity: sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -331,14 +255,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.28.6': - resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} + '@babel/plugin-syntax-import-assertions@7.29.7': + resolution: {integrity: sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.28.6': - resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -349,326 +273,314 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + '@babel/plugin-transform-arrow-functions@7.29.7': + resolution: {integrity: sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.29.0': - resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} + '@babel/plugin-transform-async-generator-functions@7.29.7': + resolution: {integrity: sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.28.6': - resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} + '@babel/plugin-transform-async-to-generator@7.29.7': + resolution: {integrity: sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.27.1': - resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + '@babel/plugin-transform-block-scoped-functions@7.29.7': + resolution: {integrity: sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.6': - resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} + '@babel/plugin-transform-block-scoping@7.29.7': + resolution: {integrity: sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.28.6': - resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} + '@babel/plugin-transform-class-properties@7.29.7': + resolution: {integrity: sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.28.6': - resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} + '@babel/plugin-transform-class-static-block@7.29.7': + resolution: {integrity: sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.28.6': - resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} + '@babel/plugin-transform-classes@7.29.7': + resolution: {integrity: sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.28.6': - resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} + '@babel/plugin-transform-computed-properties@7.29.7': + resolution: {integrity: sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.5': - resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + '@babel/plugin-transform-destructuring@7.29.7': + resolution: {integrity: sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.28.6': - resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} + '@babel/plugin-transform-dotall-regex@7.29.7': + resolution: {integrity: sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.27.1': - resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + '@babel/plugin-transform-duplicate-keys@7.29.7': + resolution: {integrity: sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': - resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-dynamic-import@7.27.1': - resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + '@babel/plugin-transform-dynamic-import@7.29.7': + resolution: {integrity: sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-explicit-resource-management@7.28.6': - resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} + '@babel/plugin-transform-explicit-resource-management@7.29.7': + resolution: {integrity: sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.28.6': - resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} + '@babel/plugin-transform-exponentiation-operator@7.29.7': + resolution: {integrity: sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + '@babel/plugin-transform-export-namespace-from@7.29.7': + resolution: {integrity: sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + '@babel/plugin-transform-for-of@7.29.7': + resolution: {integrity: sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + '@babel/plugin-transform-function-name@7.29.7': + resolution: {integrity: sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.28.6': - resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} + '@babel/plugin-transform-json-strings@7.29.7': + resolution: {integrity: sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + '@babel/plugin-transform-literals@7.29.7': + resolution: {integrity: sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.28.6': - resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} + '@babel/plugin-transform-logical-assignment-operators@7.29.7': + resolution: {integrity: sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-member-expression-literals@7.27.1': - resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + '@babel/plugin-transform-member-expression-literals@7.29.7': + resolution: {integrity: sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-amd@7.27.1': - resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + '@babel/plugin-transform-modules-amd@7.29.7': + resolution: {integrity: sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.28.6': - resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + '@babel/plugin-transform-modules-commonjs@7.29.7': + resolution: {integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.29.4': - resolution: {integrity: sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==} + '@babel/plugin-transform-modules-systemjs@7.29.7': + resolution: {integrity: sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-umd@7.27.1': - resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + '@babel/plugin-transform-modules-umd@7.29.7': + resolution: {integrity: sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': - resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.27.1': - resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': - resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-numeric-separator@7.28.6': - resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} + '@babel/plugin-transform-new-target@7.29.7': + resolution: {integrity: sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.28.6': - resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7': + resolution: {integrity: sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.27.1': - resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + '@babel/plugin-transform-numeric-separator@7.29.7': + resolution: {integrity: sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.28.6': - resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} + '@babel/plugin-transform-object-rest-spread@7.29.7': + resolution: {integrity: sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.28.6': - resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} + '@babel/plugin-transform-object-super@7.29.7': + resolution: {integrity: sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + '@babel/plugin-transform-optional-catch-binding@7.29.7': + resolution: {integrity: sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.28.6': - resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} + '@babel/plugin-transform-optional-chaining@7.29.7': + resolution: {integrity: sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.28.6': - resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} + '@babel/plugin-transform-parameters@7.29.7': + resolution: {integrity: sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.27.1': - resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + '@babel/plugin-transform-private-methods@7.29.7': + resolution: {integrity: sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + '@babel/plugin-transform-private-property-in-object@7.29.7': + resolution: {integrity: sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==} 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==} + '@babel/plugin-transform-property-literals@7.29.7': + resolution: {integrity: sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.29.0': - resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} + '@babel/plugin-transform-regenerator@7.29.7': + resolution: {integrity: sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regexp-modifiers@7.28.6': - resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} + '@babel/plugin-transform-regexp-modifiers@7.29.7': + resolution: {integrity: sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-reserved-words@7.27.1': - resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} + '@babel/plugin-transform-reserved-words@7.29.7': + resolution: {integrity: sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + '@babel/plugin-transform-shorthand-properties@7.29.7': + resolution: {integrity: sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.28.6': - resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} + '@babel/plugin-transform-spread@7.29.7': + resolution: {integrity: sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + '@babel/plugin-transform-sticky-regex@7.29.7': + resolution: {integrity: sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + '@babel/plugin-transform-template-literals@7.29.7': + resolution: {integrity: sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.27.1': - resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + '@babel/plugin-transform-typeof-symbol@7.29.7': + resolution: {integrity: sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.27.1': - resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + '@babel/plugin-transform-unicode-escapes@7.29.7': + resolution: {integrity: sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.28.6': - resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} + '@babel/plugin-transform-unicode-property-regex@7.29.7': + resolution: {integrity: sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + '@babel/plugin-transform-unicode-regex@7.29.7': + resolution: {integrity: sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.28.6': - resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} + '@babel/plugin-transform-unicode-sets-regex@7.29.7': + resolution: {integrity: sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.29.5': - resolution: {integrity: sha512-/69t2aEzGKHD76DyLbHysF/QH2LJOB8iFnYO37unDTKBTubzcMRv0f3H5EiN1Q6ajOd/eB7dAInF0qdFVS06kA==} + '@babel/preset-env@7.29.7': + resolution: {integrity: sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -678,177 +590,60 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] + '@base-ui/react@1.6.0': + resolution: {integrity: sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] + '@base-ui/utils@0.3.1': + resolution: {integrity: sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] + '@canvas/image-data@1.1.0': + resolution: {integrity: sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==} - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} @@ -860,33 +655,34 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -903,11 +699,6 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@hookform/resolvers@3.10.0': - resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} - peerDependencies: - react-hook-form: ^7.0.0 - '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -928,6 +719,123 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@isaacs/cliui@9.0.0': resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} engines: {node: '>=18'} @@ -951,485 +859,115 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@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'} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + '@quansync/fs@1.0.0': + resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + '@rolldown/binding-android-arm64@1.1.5': + resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@radix-ui/react-alert-dialog@1.1.15': - resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-darwin-x64@1.1.5': + resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@radix-ui/react-avatar@1.1.11': - resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-linux-arm64-gnu@1.1.5': + resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-linux-arm64-musl@1.1.5': + resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@radix-ui/react-context@1.1.3': - resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.8': - resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popover@1.1.15': - resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.4': - resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-progress@1.1.8': - resolution: {integrity: sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-separator@1.1.8': - resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-toast@1.2.15': - resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tooltip@1.2.8': - resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-linux-s390x-gnu@1.1.5': + resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-linux-x64-gnu@1.1.5': + resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-linux-x64-musl@1.1.5': + resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-openharmony-arm64@1.1.5': + resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-wasm32-wasi@1.1.5': + resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/binding-win32-arm64-msvc@1.1.5': + resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@remix-run/router@1.23.2': - resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-win32-x64-msvc@1.1.5': + resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@rollup/plugin-babel@6.1.0': resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} @@ -1471,8 +1009,8 @@ packages: rollup: optional: true - '@rollup/pluginutils@5.3.0': - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -1480,158 +1018,243 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.60.3': - resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + '@rollup/rollup-android-arm-eabi@4.62.2': + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.3': - resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} + '@rollup/rollup-android-arm64@4.62.2': + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.3': - resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} + '@rollup/rollup-darwin-arm64@4.62.2': + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.3': - resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} + '@rollup/rollup-darwin-x64@4.62.2': + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.3': - resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + '@rollup/rollup-freebsd-arm64@4.62.2': + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.3': - resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} + '@rollup/rollup-freebsd-x64@4.62.2': + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': - resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.3': - resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.3': - resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} + '@rollup/rollup-linux-arm64-gnu@4.62.2': + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.3': - resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} + '@rollup/rollup-linux-arm64-musl@4.62.2': + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.3': - resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + '@rollup/rollup-linux-loong64-gnu@4.62.2': + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.3': - resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + '@rollup/rollup-linux-loong64-musl@4.62.2': + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.3': - resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.3': - resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + '@rollup/rollup-linux-ppc64-musl@4.62.2': + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.3': - resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.3': - resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + '@rollup/rollup-linux-riscv64-musl@4.62.2': + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.3': - resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} + '@rollup/rollup-linux-s390x-gnu@4.62.2': + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.3': - resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} + '@rollup/rollup-linux-x64-gnu@4.62.2': + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.3': - resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} + '@rollup/rollup-linux-x64-musl@4.62.2': + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.3': - resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + '@rollup/rollup-openbsd-x64@4.62.2': + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.3': - resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} + '@rollup/rollup-openharmony-arm64@4.62.2': + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.3': - resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} + '@rollup/rollup-win32-arm64-msvc@4.62.2': + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.3': - resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + '@rollup/rollup-win32-ia32-msvc@4.62.2': + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.3': - resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} + '@rollup/rollup-win32-x64-gnu@4.62.2': + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.3': - resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + '@rollup/rollup-win32-x64-msvc@4.62.2': + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} cpu: [x64] os: [win32] - '@tanstack/eslint-plugin-query@5.100.10': - resolution: {integrity: sha512-Ddou3agTWv5rvHSBby4yHlugUFHVh0nyo2fyoZ81qSxaTBIwNCoPgpiJhjo5QkThrH1wGC7k548BcMTszZCkBw==} + '@tailwindcss/node@4.3.2': + resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} + + '@tailwindcss/oxide-android-arm64@4.3.2': + resolution: {integrity: sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.2': + resolution: {integrity: sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.2': + resolution: {integrity: sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.2': + resolution: {integrity: sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + resolution: {integrity: sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + resolution: {integrity: sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + resolution: {integrity: sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + resolution: {integrity: sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + resolution: {integrity: sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + resolution: {integrity: sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + resolution: {integrity: sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + resolution: {integrity: sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.2': + resolution: {integrity: sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.2': + resolution: {integrity: sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ^5.4.0 || ^6.0.0 - peerDependenciesMeta: - typescript: - optional: true + vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/query-core@5.100.10': - resolution: {integrity: sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==} + '@tanstack/query-core@5.101.2': + resolution: {integrity: sha512-hH5MLoJhF7KaIGd7q3xTXGXvslI+GYlM1Z/35aSHHWaCJWB7XvTSHYuV3eM7tw+aE0mT/xMro4M4Q9rCGHT0lw==} - '@tanstack/react-query@5.100.10': - resolution: {integrity: sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==} + '@tanstack/react-query@5.101.2': + resolution: {integrity: sha512-seDkr6kzGzX1okaaTtZPtgA688CDPlXUz1C6xSg0ESqn04Vuc8tlrYms1s3de+znBqhPVxFRfpAfUf+6XvfPWg==} peerDependencies: react: ^18 || ^19 @@ -1639,20 +1262,11 @@ packages: resolution: {integrity: sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==} engines: {node: '>=12'} - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -1660,19 +1274,16 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@22.19.19': - resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} - - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@types/node@26.1.1': + resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: - '@types/react': ^18.0.0 + '@types/react': ^19.2.0 - '@types/react@18.3.28': - resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -1680,108 +1291,103 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.59.3': - resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} + '@typescript-eslint/eslint-plugin@8.63.0': + resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.59.3 + '@typescript-eslint/parser': ^8.63.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.59.3': - resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} + '@typescript-eslint/parser@8.63.0': + resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.59.3': - resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} + '@typescript-eslint/project-service@8.63.0': + resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.59.3': - resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} + '@typescript-eslint/scope-manager@8.63.0': + resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.59.3': - resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} + '@typescript-eslint/tsconfig-utils@8.63.0': + resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.59.3': - resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} + '@typescript-eslint/type-utils@8.63.0': + resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.59.3': - resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} + '@typescript-eslint/types@8.63.0': + resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.59.3': - resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} + '@typescript-eslint/typescript-estree@8.63.0': + resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.59.3': - resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} + '@typescript-eslint/utils@8.63.0': + resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.59.3': - resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} + '@typescript-eslint/visitor-keys@8.63.0': + resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} + '@vite-pwa/assets-generator@1.0.2': + resolution: {integrity: sha512-MCbrb508JZHqe7bUibmZj/lyojdhLRnfkmyXnkrCM2zVrjTgL89U8UEfInpKTvPeTnxsw2hmyZxnhsdNR6yhwg==} + engines: {node: '>=16.14.0'} + hasBin: true + + '@vitejs/plugin-react@6.0.3': + resolution: {integrity: sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==} + engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -1804,19 +1410,12 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - autoprefixer@10.5.0: - resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} - 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'} - axios@1.16.0: - resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} + axios@1.18.1: + resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==} babel-plugin-polyfill-corejs2@0.4.17: resolution: {integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==} @@ -1840,37 +1439,30 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.29: - resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} + baseline-browser-mapping@2.10.42: + resolution: {integrity: sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==} engines: {node: '>=6.0.0'} hasBin: true - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + brace-expansion@2.1.2: + resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + browserslist@4.28.5: + resolution: {integrity: sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1883,37 +1475,8 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - callsites@3.1.0: - 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'} - - caniuse-lite@1.0.30001792: - resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - - cmdk@1.1.1: - resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} - peerDependencies: - react: ^18 || ^19 || ^19.0.0-rc - react-dom: ^18 || ^19 || ^19.0.0-rc + caniuse-lite@1.0.30001803: + resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==} color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -1922,6 +1485,16 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -1929,20 +1502,21 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + core-js-compat@3.49.0: resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} @@ -1954,11 +1528,6 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} 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==} @@ -1974,8 +1543,8 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + date-fns@4.4.0: + resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -1986,6 +1555,14 @@ packages: supports-color: optional: true + decode-bmp@0.2.1: + resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==} + engines: {node: '>=8.6.0'} + + decode-ico@0.4.1: + resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==} + engines: {node: '>=8.6'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -2001,18 +1578,16 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} @@ -2023,8 +1598,16 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.353: - resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} + electron-to-chromium@1.5.389: + resolution: {integrity: sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==} + + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} es-abstract@1.24.2: resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} @@ -2038,23 +1621,18 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2063,36 +1641,32 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-plugin-react-hooks@5.2.0: - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - eslint-plugin-react-refresh@0.4.26: - resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} + eslint-plugin-react-refresh@0.5.3: + resolution: {integrity: sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==} peerDependencies: - eslint: '>=8.40' + eslint: ^9 || ^10 - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-visitor-keys@5.0.1: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@10.6.0: + resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: jiti: '*' @@ -2100,9 +1674,9 @@ packages: jiti: optional: true - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} @@ -2130,21 +1704,14 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - 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==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -2162,10 +1729,6 @@ packages: filelist@1.0.6: resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -2194,13 +1757,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} - fraction.js@5.3.4: - resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -2213,8 +1773,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: @@ -2232,10 +1792,6 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - get-own-enumerable-property-symbols@3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} @@ -2247,10 +1803,6 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - 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'} @@ -2261,14 +1813,6 @@ packages: deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -2284,10 +1828,6 @@ packages: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -2303,24 +1843,34 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + html-parse-stringify@3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} - i18next-browser-languagedetector@8.2.1: - resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} - i18next@25.10.10: - resolution: {integrity: sha512-cqUW2Z3EkRx7NqSyywjkgCLK7KLCL6IFVFcONG7nVYIJ3ekZ1/N5jUsihHV6Bq37NfhgtczxJcxduELtjTwkuQ==} + i18next@26.3.6: + resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==} peerDependencies: - typescript: ^5 || ^6 + typescript: ^5 || ^6 || ^7 peerDependenciesMeta: typescript: optional: true + ico-endec@0.1.6: + resolution: {integrity: sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==} + idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} @@ -2328,14 +1878,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} engines: {node: '>= 4'} - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -2348,6 +1894,9 @@ packages: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -2356,10 +1905,6 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - is-boolean-object@1.2.2: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} @@ -2380,6 +1925,10 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2411,10 +1960,6 @@ packages: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - is-obj@1.0.1: resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} engines: {node: '>=0.10.0'} @@ -2478,17 +2023,13 @@ packages: engines: {node: '>=10'} hasBin: true - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -2529,12 +2070,79 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -2543,27 +2151,17 @@ packages: lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lru-cache@11.3.6: - resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.452.0: - resolution: {integrity: sha512-kNefjOUOGm+Mu3KDiryONyPba9r+nhcrz5oJs3N6JDzGboQNEXw5GB3yB8rnV9/FA4bPyggNU6CRSihZm9MvSw==} + lucide-react@1.24.0: + resolution: {integrity: sha512-YT6mBD8lGKkg4nM39enlm94/sfJIiW0YKUT60fBy4YK8tai31ylg1VhGNWxkpSKHo9UagfnZqwIff3HTDQwXeA==} peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2572,14 +2170,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -2592,9 +2182,6 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@5.1.9: resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} @@ -2606,37 +2193,17 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next-themes@0.4.6: - resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} - peerDependencies: - react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - - node-releases@2.0.38: - resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} + node-releases@2.0.51: + resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} + engines: {node: '>=18'} object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} @@ -2654,8 +2221,8 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + own-keys@1.0.2: + resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} engines: {node: '>= 0.4'} p-limit@3.1.0: @@ -2669,10 +2236,6 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2691,77 +2254,27 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - possible-typed-array-names@1.1.0: 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'} - peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - 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.14: - resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + postcss@8.5.16: + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} + engines: {node: '>=14'} + hasBin: true + pretty-bytes@5.6.0: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} engines: {node: '>=6'} @@ -2778,34 +2291,22 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - react-day-picker@8.10.2: - resolution: {integrity: sha512-LK68OTbHB3oJNhl9cA0qVizzp3o26w61YSjAFkYi67N86iro32wx86kSNeFU/hq+gI8m1yzWhnomMLfZ041RzQ==} - peerDependencies: - date-fns: ^2.28.0 || ^3.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 + quansync@1.0.0: + resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - react-hook-form@7.75.0: - resolution: {integrity: sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw==} - engines: {node: '>=18.0.0'} + react-dom@19.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: - react: ^16.8.0 || ^17 || ^18 || ^19 + react: ^19.2.7 - react-i18next@15.7.4: - resolution: {integrity: sha512-nyU8iKNrI5uDJch0z9+Y5XEr34b0wkyYj3Rp+tfbahxtlswxSCjcUL9H0nqXo9IR3/t5Y5PKIA3fx3MfUyR9Xw==} + react-i18next@17.0.9: + resolution: {integrity: sha512-buLzOSqHtXxjf+qgSrLWNTXVZ1jSwO6kUv3uJqSP1roGBPgNnbhFm7OmdVwWcgf2gIbUyP0J333uPyx+Btsi3w==} peerDependencies: - i18next: '>= 23.4.0' + i18next: '>= 26.2.0' react: '>= 16.8.0' react-dom: '*' react-native: '*' - typescript: ^5 + typescript: ^5 || ^6 || ^7 peerDependenciesMeta: react-dom: optional: true @@ -2814,64 +2315,27 @@ packages: typescript: optional: true - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - 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'} + react-router-dom@7.18.1: + resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==} + engines: {node: '>=20.0.0'} peerDependencies: - react: '>=16.8' + react: '>=18' + react-dom: '>=18' - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} + react-router@7.18.1: + resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} + engines: {node: '>=20.0.0'} peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react: '>=18' + react-dom: '>=18' peerDependenciesMeta: - '@types/react': + react-dom: optional: true - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} engines: {node: '>=0.10.0'} - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -2894,35 +2358,32 @@ packages: regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.13.1: - resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} + regjsparser@0.13.2: + resolution: {integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==} hasBin: true require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} resolve@1.22.12: resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rolldown@1.1.5: + resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true - rollup@4.60.3: - resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} + rollup@4.62.2: + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - safe-array-concat@1.1.4: resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} @@ -2935,22 +2396,25 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - 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==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true - serialize-javascript@7.0.5: - resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} + serialize-javascript@7.0.7: + resolution: {integrity: sha512-YAy8Od6KV+uuwUuU50np8fGB/Aues6Y0nAhA9y/hId74PlKUcme4pXcBD46NWKr1Q4osN/iseZ17YqO1XfmI8g==} engines: {node: '>=20.0.0'} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2963,6 +2427,13 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + sharp-ico@0.1.5: + resolution: {integrity: sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==} + + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2983,16 +2454,19 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - smob@1.6.1: - resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + smob@1.6.2: + resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} engines: {node: '>=20.0.0'} sonner@2.0.7: @@ -3012,10 +2486,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions + source-map@0.8.0: + resolution: {integrity: sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==} + engines: {node: '>= 12'} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} @@ -3025,12 +2498,12 @@ packages: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} engines: {node: '>= 0.4'} - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} engines: {node: '>= 0.4'} string.prototype.trimstart@1.0.8: @@ -3045,35 +2518,16 @@ packages: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - sucrase@3.35.1: - resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tailwind-merge@2.6.1: - resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} - - tailwindcss-animate@1.0.7: - resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders' + tailwindcss@4.3.2: + resolution: {integrity: sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==} - tailwindcss@3.4.19: - resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} - engines: {node: '>=14.0.0'} - hasBin: true + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} @@ -3083,28 +2537,17 @@ packages: resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} engines: {node: '>=10'} - terser@5.47.1: - resolution: {integrity: sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==} + terser@5.49.0: + resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} engines: {node: '>=10'} hasBin: true - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + to-data-view@1.1.0: + resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==} ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} @@ -3112,9 +2555,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -3138,12 +2578,12 @@ packages: resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} - typescript-eslint@8.59.3: - resolution: {integrity: sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==} + typescript-eslint@8.63.0: + resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3158,8 +2598,14 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + unconfig-core@7.5.0: + resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} + + unconfig@7.5.0: + resolution: {integrity: sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==} + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} @@ -3198,77 +2644,51 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - 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==} - - vaul@1.1.2: - resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - - vite-plugin-pwa@0.21.2: - resolution: {integrity: sha512-vFhH6Waw8itNu37hWUJxL50q+CBbNcMVzsKaYHQVrfxTt3ihk3PeLO22SbiP1UNWzcEPaTQv+YVxe4G0KOjAkg==} + vite-plugin-pwa@1.3.0: + resolution: {integrity: sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==} engines: {node: '>=16.0.0'} peerDependencies: - '@vite-pwa/assets-generator': ^0.2.6 - vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 - workbox-build: ^7.3.0 - workbox-window: ^7.3.0 + '@vite-pwa/assets-generator': ^1.0.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + workbox-build: ^7.4.1 + workbox-window: ^7.4.1 peerDependenciesMeta: '@vite-pwa/assets-generator': optional: true - vite@6.4.2: - resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@8.1.4: + resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -3288,12 +2708,6 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -3306,8 +2720,8 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + which-typed-array@1.1.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} engines: {node: '>= 0.4'} which@2.0.2: @@ -3375,11 +2789,17 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 - zustand@5.0.13: - resolution: {integrity: sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zustand@5.0.14: + resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=18.0.0' @@ -3398,33 +2818,31 @@ packages: snapshots: - '@alloc/quick-lru@5.2.0': {} - '@apideck/better-ajv-errors@0.3.7(ajv@8.20.0)': dependencies: ajv: 8.20.0 jsonpointer: 5.0.1 leven: 3.1.0 - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.3': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': + '@babel/core@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3434,773 +2852,715 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': + '@babel/generator@7.29.7': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.27.3': + '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/helper-compilation-targets@7.28.6': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.5 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.3(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.0)': + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 debug: 4.4.3 lodash.debounce: 4.0.8 resolve: 1.22.12 transitivePeerDependencies: - supports-color - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-optimise-call-expression@7.27.1': + '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-wrap-function': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-option@7.29.7': {} - '@babel/helper-wrap-function@7.28.6': + '@babel/helper-wrap-function@7.29.7': dependencies: - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helpers@7.29.2': + '@babel/helpers@7.29.7': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 - '@babel/parser@7.29.3': + '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.3(@babel/core@7.29.0)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/template': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/template': 7.29.7 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.29.4(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@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-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)': + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/preset-env@7.29.5(@babel/core@7.29.0)': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.3(@babel/core@7.29.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) - '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-modules-systemjs': 7.29.4(@babel/core@7.29.0) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) - '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.0) - babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.0) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/preset-env@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7) core-js-compat: 3.49.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/types': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/types': 7.29.7 esutils: 2.0.3 - '@babel/runtime@7.29.2': {} + '@babel/runtime@7.29.7': {} - '@babel/template@7.28.6': + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.29.0': + '@babel/types@7.29.7': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@esbuild/aix-ppc64@0.25.12': - optional: true - - '@esbuild/android-arm64@0.25.12': - optional: true - - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 - '@esbuild/linux-mips64el@0.25.12': - optional: true - - '@esbuild/linux-ppc64@0.25.12': - optional: true - - '@esbuild/linux-riscv64@0.25.12': - optional: true - - '@esbuild/linux-s390x@0.25.12': - optional: true - - '@esbuild/linux-x64@0.25.12': - optional: true - - '@esbuild/netbsd-arm64@0.25.12': - optional: true - - '@esbuild/netbsd-x64@0.25.12': - optional: true - - '@esbuild/openbsd-arm64@0.25.12': - optional: true - - '@esbuild/openbsd-x64@0.25.12': - optional: true + '@base-ui/react@1.6.0(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@base-ui/utils': 0.3.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + date-fns: 4.4.0 - '@esbuild/openharmony-arm64@0.25.12': - optional: true + '@base-ui/utils@0.3.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 - '@esbuild/sunos-x64@0.25.12': - optional: true + '@canvas/image-data@1.1.0': {} - '@esbuild/win32-arm64@0.25.12': + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 optional: true - '@esbuild/win32-ia32@0.25.12': + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/win32-x64@0.25.12': + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))': dependencies: - eslint: 9.39.4(jiti@1.21.7) + eslint: 10.6.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.2': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 2.1.7 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 3.1.5 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.2': + '@eslint/config-helpers@0.6.0': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 - '@eslint/core@0.17.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} + '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0))': + optionalDependencies: + eslint: 10.6.0(jiti@2.7.0) - '@eslint/object-schema@2.1.7': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.4.1': + '@eslint/plugin-kit@0.7.2': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 levn: 0.4.1 '@floating-ui/core@1.7.5': @@ -4212,18 +3572,14 @@ snapshots: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@floating-ui/dom': 1.7.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) '@floating-ui/utils@0.2.11': {} - '@hookform/resolvers@3.10.0(react-hook-form@7.75.0(react@18.3.1))': - dependencies: - react-hook-form: 7.75.0(react@18.3.1) - '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -4240,637 +3596,363 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@isaacs/cliui@9.0.0': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true - '@jridgewell/resolve-uri@3.1.2': {} + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true - '@jridgewell/sourcemap-codec@1.5.5': {} + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true - '@nodelib/fs.stat@2.0.5': {} + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true - '@radix-ui/number@1.1.1': {} + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true - '@radix-ui/primitive@1.1.3': {} + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@img/sharp-linux-arm64@0.33.5': optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true - '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@img/sharp-linux-arm@0.33.5': optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-avatar@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true - '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@img/sharp-linux-s390x@0.33.5': optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 + '@img/sharp-linux-x64@0.33.5': optionalDependencies: - '@types/react': 18.3.28 + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true - '@radix-ui/react-context@1.1.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 + '@img/sharp-linuxmusl-arm64@0.33.5': optionalDependencies: - '@types/react': 18.3.28 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true - '@radix-ui/react-context@1.1.3(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + '@img/sharp-linuxmusl-x64@0.33.5': optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true - '@radix-ui/react-direction@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@img/sharp-wasm32@0.33.5': dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@emnapi/runtime': 1.11.1 + optional: true - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@img/sharp-win32-ia32@0.33.5': + optional: true - '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@img/sharp-win32-x64@0.33.5': + optional: true - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@isaacs/cliui@9.0.0': {} - '@radix-ui/react-id@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@jridgewell/gen-mapping@0.3.13': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@jridgewell/remapping@2.3.5': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-popover@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@jridgewell/resolve-uri@3.1.2': {} - '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@jridgewell/source-map@0.3.11': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@jridgewell/sourcemap-codec@1.5.5': {} - '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@jridgewell/trace-mapping@0.3.31': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true - '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@oxc-project/types@0.139.0': {} - '@radix-ui/react-slot@1.2.3(@types/react@18.3.28)(react@18.3.1)': + '@quansync/fs@1.0.0': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + quansync: 1.0.0 - '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-toast@1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@rolldown/binding-android-arm64@1.1.5': + optional: true - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-darwin-arm64@1.1.5': + optional: true - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-darwin-x64@1.1.5': + optional: true - '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-freebsd-x64@1.1.5': + optional: true - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + optional: true - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-linux-arm64-gnu@1.1.5': + optional: true - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-linux-arm64-musl@1.1.5': + optional: true - '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + optional: true - '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-linux-s390x-gnu@1.1.5': + optional: true - '@radix-ui/react-use-size@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 + '@rolldown/binding-linux-x64-gnu@1.1.5': + optional: true + + '@rolldown/binding-linux-x64-musl@1.1.5': + optional: true + + '@rolldown/binding-openharmony-arm64@1.1.5': + optional: true - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@rolldown/binding-wasm32-wasi@1.1.5': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true - '@radix-ui/rect@1.1.1': {} + '@rolldown/binding-win32-arm64-msvc@1.1.5': + optional: true - '@remix-run/router@1.23.2': {} + '@rolldown/binding-win32-x64-msvc@1.1.5': + optional: true - '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-babel@6.1.0(@babel/core@7.29.0)(@types/babel__core@7.20.5)(rollup@4.60.3)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7)(rollup@4.62.2)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@rollup/pluginutils': 5.3.0(rollup@4.60.3) + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) optionalDependencies: - '@types/babel__core': 7.20.5 - rollup: 4.60.3 + rollup: 4.62.2 transitivePeerDependencies: - supports-color - '@rollup/plugin-node-resolve@16.0.3(rollup@4.60.3)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.3) + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.12 optionalDependencies: - rollup: 4.60.3 + rollup: 4.62.2 - '@rollup/plugin-replace@6.0.3(rollup@4.60.3)': + '@rollup/plugin-replace@6.0.3(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.3) + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) magic-string: 0.30.21 optionalDependencies: - rollup: 4.60.3 + rollup: 4.62.2 - '@rollup/plugin-terser@1.0.0(rollup@4.60.3)': + '@rollup/plugin-terser@1.0.0(rollup@4.62.2)': dependencies: - serialize-javascript: 7.0.5 - smob: 1.6.1 - terser: 5.47.1 + serialize-javascript: 7.0.7 + smob: 1.6.2 + terser: 5.49.0 optionalDependencies: - rollup: 4.60.3 + rollup: 4.62.2 - '@rollup/pluginutils@5.3.0(rollup@4.60.3)': + '@rollup/pluginutils@5.4.0(rollup@4.62.2)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 - picomatch: 4.0.4 + picomatch: 4.0.5 optionalDependencies: - rollup: 4.60.3 + rollup: 4.62.2 - '@rollup/rollup-android-arm-eabi@4.60.3': + '@rollup/rollup-android-arm-eabi@4.62.2': optional: true - '@rollup/rollup-android-arm64@4.60.3': + '@rollup/rollup-android-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-arm64@4.60.3': + '@rollup/rollup-darwin-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-x64@4.60.3': + '@rollup/rollup-darwin-x64@4.62.2': optional: true - '@rollup/rollup-freebsd-arm64@4.60.3': + '@rollup/rollup-freebsd-arm64@4.62.2': optional: true - '@rollup/rollup-freebsd-x64@4.60.3': + '@rollup/rollup-freebsd-x64@4.62.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.3': + '@rollup/rollup-linux-arm-musleabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.3': + '@rollup/rollup-linux-arm64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.3': + '@rollup/rollup-linux-arm64-musl@4.62.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.3': + '@rollup/rollup-linux-loong64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.3': + '@rollup/rollup-linux-loong64-musl@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.3': + '@rollup/rollup-linux-ppc64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.3': + '@rollup/rollup-linux-ppc64-musl@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.3': + '@rollup/rollup-linux-riscv64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.3': + '@rollup/rollup-linux-riscv64-musl@4.62.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.3': + '@rollup/rollup-linux-s390x-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.3': + '@rollup/rollup-linux-x64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-musl@4.60.3': + '@rollup/rollup-linux-x64-musl@4.62.2': optional: true - '@rollup/rollup-openbsd-x64@4.60.3': + '@rollup/rollup-openbsd-x64@4.62.2': optional: true - '@rollup/rollup-openharmony-arm64@4.60.3': + '@rollup/rollup-openharmony-arm64@4.62.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.3': + '@rollup/rollup-win32-arm64-msvc@4.62.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.3': + '@rollup/rollup-win32-ia32-msvc@4.62.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.3': + '@rollup/rollup-win32-x64-gnu@4.62.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.3': + '@rollup/rollup-win32-x64-msvc@4.62.2': optional: true - '@tanstack/eslint-plugin-query@5.100.10(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@tailwindcss/node@4.3.2': dependencies: - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.4(jiti@1.21.7) + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.2 + + '@tailwindcss/oxide-android-arm64@4.3.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + optional: true + + '@tailwindcss/oxide@4.3.2': optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@tailwindcss/oxide-android-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-x64': 4.3.2 + '@tailwindcss/oxide-freebsd-x64': 4.3.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-x64-musl': 4.3.2 + '@tailwindcss/oxide-wasm32-wasi': 4.3.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 + + '@tailwindcss/vite@4.3.2(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0))': + dependencies: + '@tailwindcss/node': 4.3.2 + '@tailwindcss/oxide': 4.3.2 + tailwindcss: 4.3.2 + vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0) - '@tanstack/query-core@5.100.10': {} + '@tanstack/query-core@5.101.2': {} - '@tanstack/react-query@5.100.10(react@18.3.1)': + '@tanstack/react-query@5.101.2(react@19.2.7)': dependencies: - '@tanstack/query-core': 5.100.10 - react: 18.3.1 + '@tanstack/query-core': 5.101.2 + react: 19.2.7 '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': dependencies: @@ -4879,161 +3961,150 @@ snapshots: magic-string: 0.30.21 string.prototype.matchall: 4.0.12 - '@types/babel__core@7.20.5': + '@tybys/wasm-util@0.10.3': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 + tslib: 2.8.1 + optional: true - '@types/estree@1.0.8': {} + '@types/esrecurse@4.3.1': {} '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} - '@types/node@22.19.19': + '@types/node@26.1.1': dependencies: - undici-types: 6.21.0 + undici-types: 8.3.0 - '@types/prop-types@15.7.15': {} - - '@types/react-dom@18.3.7(@types/react@18.3.28)': + '@types/react-dom@19.2.3(@types/react@19.2.17)': dependencies: - '@types/react': 18.3.28 + '@types/react': 19.2.17 - '@types/react@18.3.28': + '@types/react@19.2.17': dependencies: - '@types/prop-types': 15.7.15 csstype: 3.2.3 '@types/resolve@1.20.2': {} '@types/trusted-types@2.0.7': {} - '@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/type-utils': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.3 - eslint: 9.39.4(jiti@1.21.7) - ignore: 7.0.5 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/type-utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.63.0 + eslint: 10.6.0(jiti@2.7.0) + ignore: 7.0.6 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.63.0 debug: 4.4.3 - eslint: 9.39.4(jiti@1.21.7) + eslint: 10.6.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.3(typescript@5.9.3)': + '@typescript-eslint/project-service@8.63.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) + '@typescript-eslint/types': 8.63.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.59.3': + '@typescript-eslint/scope-manager@8.63.0': dependencies: - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 - '@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.63.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.4(jiti@1.21.7) + eslint: 10.6.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.3': {} + '@typescript-eslint/types@8.63.0': {} - '@typescript-eslint/typescript-estree@8.59.3(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.63.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.59.3(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/project-service': 8.63.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.8.0 - tinyglobby: 0.2.16 + semver: 7.8.5 + tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - eslint: 9.39.4(jiti@1.21.7) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + eslint: 10.6.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.59.3': + '@typescript-eslint/visitor-keys@8.63.0': dependencies: - '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/types': 8.63.0 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@4.7.0(vite@6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1))': + '@vite-pwa/assets-generator@1.0.2': + dependencies: + cac: 6.7.14 + colorette: 2.0.20 + consola: 3.4.2 + sharp: 0.33.5 + sharp-ico: 0.1.5 + unconfig: 7.5.0 + + '@vitejs/plugin-react@6.0.3(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0) + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + agent-base@6.0.2: 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: 6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1) + debug: 4.4.3 transitivePeerDependencies: - supports-color - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -5044,29 +4115,10 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - any-promise@1.3.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.2 - - arg@5.0.2: {} - - argparse@2.0.1: {} - - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 @@ -5090,48 +4142,41 @@ snapshots: at-least-node@1.0.0: {} - autoprefixer@10.5.0(postcss@8.5.14): - dependencies: - browserslist: 4.28.2 - caniuse-lite: 1.0.30001792 - fraction.js: 5.3.4 - picocolors: 1.1.1 - postcss: 8.5.14 - postcss-value-parser: 4.2.0 - available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 - axios@1.16.0: + axios@1.18.1: dependencies: follow-redirects: 1.16.0 - form-data: 4.0.5 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color - babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.0): + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7): dependencies: - '@babel/compat-data': 7.29.3 - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.0): + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7): dependencies: - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.0): + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7): dependencies: - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) transitivePeerDependencies: - supports-color @@ -5139,37 +4184,28 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.29: {} - - binary-extensions@2.3.0: {} + baseline-browser-mapping@2.10.42: {} - brace-expansion@1.1.14: + brace-expansion@2.1.2: dependencies: balanced-match: 1.0.2 - concat-map: 0.0.1 - brace-expansion@2.1.0: - dependencies: - balanced-match: 1.0.2 - - brace-expansion@5.0.6: + brace-expansion@5.0.7: dependencies: balanced-match: 4.0.4 - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.2: + browserslist@4.28.5: dependencies: - baseline-browser-mapping: 2.10.29 - caniuse-lite: 1.0.30001792 - electron-to-chromium: 1.5.353 - node-releases: 2.0.38 - update-browserslist-db: 1.2.3(browserslist@4.28.2) + baseline-browser-mapping: 2.10.42 + caniuse-lite: 1.0.30001803 + electron-to-chromium: 1.5.389 + node-releases: 2.0.51 + update-browserslist-db: 1.2.3(browserslist@4.28.5) buffer-from@1.1.2: {} + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -5187,52 +4223,25 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - callsites@3.1.0: {} - - camelcase-css@2.0.1: {} - - caniuse-lite@1.0.30001792: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 + caniuse-lite@1.0.30001803: {} - class-variance-authority@0.7.1: + color-convert@2.0.1: dependencies: - clsx: 2.1.1 + color-name: 1.1.4 - clsx@2.1.1: {} + color-name@1.1.4: {} - cmdk@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + color-string@1.9.1: dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' + color-name: 1.1.4 + simple-swizzle: 0.2.4 - color-convert@2.0.1: + color@4.2.3: dependencies: - color-name: 1.1.4 + color-convert: 2.0.1 + color-string: 1.9.1 - color-name@1.1.4: {} + colorette@2.0.20: {} combined-stream@1.0.8: dependencies: @@ -5240,17 +4249,17 @@ snapshots: commander@2.20.3: {} - commander@4.1.1: {} - common-tags@1.8.2: {} - concat-map@0.0.1: {} + consola@3.4.2: {} convert-source-map@2.0.0: {} + cookie@1.1.1: {} + core-js-compat@3.49.0: dependencies: - browserslist: 4.28.2 + browserslist: 4.28.5 cross-spawn@7.0.6: dependencies: @@ -5260,8 +4269,6 @@ snapshots: crypto-random-string@2.0.0: {} - cssesc@3.0.0: {} - csstype@3.2.3: {} data-view-buffer@1.0.2: @@ -5282,12 +4289,23 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - date-fns@3.6.0: {} + date-fns@4.4.0: {} debug@4.4.3: dependencies: ms: 2.1.3 + decode-bmp@0.2.1: + dependencies: + '@canvas/image-data': 1.1.0 + to-data-view: 1.1.0 + + decode-ico@0.4.1: + dependencies: + '@canvas/image-data': 1.1.0 + decode-bmp: 0.2.1 + to-data-view: 1.1.0 + deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -5304,13 +4322,11 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - delayed-stream@1.0.0: {} - - detect-node-es@1.1.0: {} + defu@6.1.7: {} - didyoumean@1.2.2: {} + delayed-stream@1.0.0: {} - dlv@1.1.3: {} + detect-libc@2.1.2: {} dunder-proto@1.0.1: dependencies: @@ -5322,7 +4338,19 @@ snapshots: dependencies: jake: 10.9.4 - electron-to-chromium@1.5.353: {} + electron-to-chromium@1.5.389: {} + + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 es-abstract@1.24.2: dependencies: @@ -5336,10 +4364,10 @@ snapshots: data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 + es-to-primitive: 1.3.4 + function.prototype.name: 1.2.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 get-symbol-description: 1.1.0 @@ -5348,7 +4376,7 @@ snapshots: has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.3 + hasown: 2.0.4 internal-slot: 1.1.0 is-array-buffer: 3.0.5 is-callable: 1.2.7 @@ -5364,28 +4392,28 @@ snapshots: object-inspect: 1.13.4 object-keys: 1.1.1 object.assign: 4.1.7 - own-keys: 1.0.1 + own-keys: 1.0.2 regexp.prototype.flags: 1.5.4 safe-array-concat: 1.1.4 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.3 typed-array-byte-length: 1.0.3 typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 + typed-array-length: 1.0.8 unbox-primitive: 1.1.0 - which-typed-array: 1.1.20 + which-typed-array: 1.1.22 es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-object-atoms@1.1.1: + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -5394,88 +4422,66 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.3 + hasown: 2.0.4 - es-to-primitive@1.3.0: + es-to-primitive@1.3.4: dependencies: + es-abstract-get: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@1.21.7)): + eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@1.21.7) + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + eslint: 10.6.0(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color - eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@1.21.7)): + eslint-plugin-react-refresh@0.5.3(eslint@10.6.0(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@1.21.7) + eslint: 10.6.0(jiti@2.7.0) - eslint-scope@8.4.0: + eslint-scope@9.1.2: dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.2.1: {} - eslint-visitor-keys@5.0.1: {} - eslint@9.39.4(jiti@1.21.7): + eslint@10.6.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.6.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.9 ajv: 6.15.0 - chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -5486,20 +4492,19 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 1.21.7 + jiti: 2.7.0 transitivePeerDependencies: - supports-color - espree@10.4.0: + espree@11.2.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 5.0.1 esquery@1.7.0: dependencies: @@ -5519,27 +4524,15 @@ snapshots: fast-deep-equal@3.1.3: {} - 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: {} - fast-uri@3.1.2: {} - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 + fast-uri@3.1.4: {} - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: @@ -5549,10 +4542,6 @@ snapshots: dependencies: minimatch: 5.1.9 - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -5576,16 +4565,14 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.5: + form-data@4.0.6: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.3 + hasown: 2.0.4 mime-types: 2.1.35 - fraction.js@5.3.4: {} - fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 @@ -5598,14 +4585,17 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.8: + function.prototype.name@1.2.0: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 - define-properties: 1.2.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 functions-have-names: 1.2.3 - hasown: 2.0.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 is-callable: 1.2.7 + is-document.all: 1.0.0 functions-have-names@1.2.3: {} @@ -5618,22 +4608,20 @@ snapshots: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.3 + hasown: 2.0.4 math-intrinsics: 1.1.0 - get-nonce@1.0.1: {} - get-own-enumerable-property-symbols@3.0.2: {} get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-symbol-description@1.1.0: dependencies: @@ -5641,10 +4629,6 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -5658,10 +4642,6 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 2.0.2 - globals@14.0.0: {} - - globals@15.15.0: {} - globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -5673,8 +4653,6 @@ snapshots: has-bigints@1.1.0: {} - has-flag@4.0.0: {} - has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -5689,42 +4667,46 @@ snapshots: dependencies: has-symbols: 1.1.0 - hasown@2.0.3: + hasown@2.0.4: dependencies: function-bind: 1.1.2 + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + html-parse-stringify@3.0.1: dependencies: void-elements: 3.1.0 - i18next-browser-languagedetector@8.2.1: + https-proxy-agent@5.0.1: dependencies: - '@babel/runtime': 7.29.2 + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color - i18next@25.10.10(typescript@5.9.3): - dependencies: - '@babel/runtime': 7.29.2 + i18next@26.3.6(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 + ico-endec@0.1.6: {} + idb@7.1.1: {} ignore@5.3.2: {} - ignore@7.0.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 + ignore@7.0.6: {} imurmurhash@0.1.4: {} internal-slot@1.1.0: dependencies: es-errors: 1.3.0 - hasown: 2.0.3 - side-channel: 1.1.0 + hasown: 2.0.4 + side-channel: 1.1.1 is-array-buffer@3.0.5: dependencies: @@ -5732,6 +4714,8 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-arrayish@0.3.4: {} + is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -5744,10 +4728,6 @@ snapshots: dependencies: has-bigints: 1.1.0 - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-boolean-object@1.2.2: dependencies: call-bound: 1.0.4 @@ -5757,7 +4737,7 @@ snapshots: is-core-module@2.16.2: dependencies: - hasown: 2.0.3 + hasown: 2.0.4 is-data-view@1.0.2: dependencies: @@ -5770,6 +4750,10 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -5799,8 +4783,6 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-number@7.0.0: {} - is-obj@1.0.1: {} is-regex@1.2.1: @@ -5808,7 +4790,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.3 + hasown: 2.0.4 is-regexp@1.0.0: {} @@ -5833,7 +4815,7 @@ snapshots: is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.20 + which-typed-array: 1.1.22 is-weakmap@2.0.2: {} @@ -5860,14 +4842,10 @@ snapshots: filelist: 1.0.6 picocolors: 1.1.1 - jiti@1.21.7: {} + jiti@2.7.0: {} js-tokens@4.0.0: {} - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -5899,33 +4877,70 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lilconfig@3.1.3: {} + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true - lines-and-columns@1.2.4: {} + lightningcss-darwin-x64@1.32.0: + optional: true - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 + lightningcss-freebsd-x64@1.32.0: + optional: true - lodash.debounce@4.0.8: {} + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true - lodash.merge@4.6.2: {} + lightningcss-win32-arm64-msvc@1.32.0: + optional: true - lodash.sortby@4.7.0: {} + lightningcss-win32-x64-msvc@1.32.0: + optional: true - loose-envify@1.4.0: + lightningcss@1.32.0: dependencies: - js-tokens: 4.0.0 + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 - lru-cache@11.3.6: {} + lodash.debounce@4.0.8: {} + + lru-cache@11.5.2: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lucide-react@0.452.0(react@18.3.1): + lucide-react@1.24.0(react@19.2.7): dependencies: - react: 18.3.1 + react: 19.2.7 magic-string@0.30.21: dependencies: @@ -5933,13 +4948,6 @@ snapshots: math-intrinsics@1.1.0: {} - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - mime-db@1.52.0: {} mime-types@2.1.35: @@ -5948,42 +4956,21 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.6 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 + brace-expansion: 5.0.7 minimatch@5.1.9: dependencies: - brace-expansion: 2.1.0 + brace-expansion: 2.1.2 minipass@7.1.3: {} ms@2.1.3: {} - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - - nanoid@3.3.12: {} + nanoid@3.3.15: {} natural-compare@1.4.0: {} - next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - node-releases@2.0.38: {} - - normalize-path@3.0.0: {} - - object-assign@4.1.1: {} - - object-hash@3.0.0: {} + node-releases@2.0.51: {} object-inspect@1.13.4: {} @@ -5994,7 +4981,7 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 has-symbols: 1.1.0 object-keys: 1.1.1 @@ -6007,8 +4994,9 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - own-keys@1.0.1: + own-keys@1.0.2: dependencies: + call-bound: 1.0.4 get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 @@ -6023,10 +5011,6 @@ snapshots: package-json-from-dist@1.0.1: {} - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - path-exists@4.0.0: {} path-key@3.1.1: {} @@ -6035,60 +5019,25 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.3.6 + lru-cache: 11.5.2 minipass: 7.1.3 picocolors@1.1.1: {} - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - pify@2.3.0: {} - - pirates@4.0.7: {} + picomatch@4.0.5: {} possible-typed-array-names@1.1.0: {} - postcss-import@15.1.0(postcss@8.5.14): - dependencies: - postcss: 8.5.14 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.12 - - postcss-js@4.1.0(postcss@8.5.14): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.14 - - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.14): - dependencies: - lilconfig: 3.1.3 - optionalDependencies: - jiti: 1.21.7 - postcss: 8.5.14 - - postcss-nested@6.2.0(postcss@8.5.14): - dependencies: - postcss: 8.5.14 - 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.14: + postcss@8.5.16: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.15 picocolors: 1.1.1 source-map-js: 1.2.1 prelude-ls@1.2.1: {} + prettier@3.9.6: {} + pretty-bytes@5.6.0: {} pretty-bytes@6.1.1: {} @@ -6097,85 +5046,39 @@ snapshots: punycode@2.3.1: {} - queue-microtask@1.2.3: {} - - react-day-picker@8.10.2(date-fns@3.6.0)(react@18.3.1): - dependencies: - date-fns: 3.6.0 - react: 18.3.1 - - react-dom@18.3.1(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + quansync@1.0.0: {} - react-hook-form@7.75.0(react@18.3.1): + react-dom@19.2.7(react@19.2.7): dependencies: - react: 18.3.1 + react: 19.2.7 + scheduler: 0.27.0 - react-i18next@15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3): + react-i18next@17.0.9(i18next@26.3.6(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@5.9.3): dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 html-parse-stringify: 3.0.1 - i18next: 25.10.10(typescript@5.9.3) - react: 18.3.1 + i18next: 26.3.6(typescript@5.9.3) + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) optionalDependencies: - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.2.7(react@19.2.7) typescript: 5.9.3 - react-refresh@0.17.0: {} - - react-remove-scroll-bar@2.3.8(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - - react-remove-scroll@2.7.2(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - react-remove-scroll-bar: 2.3.8(@types/react@18.3.28)(react@18.3.1) - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@18.3.28)(react@18.3.1) - use-sidecar: 1.1.3(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - - 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): + react-router-dom@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - '@remix-run/router': 1.23.2 - react: 18.3.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-router: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react-style-singleton@2.2.3(@types/react@18.3.28)(react@18.3.1): + react-router@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - get-nonce: 1.0.1 - react: 18.3.1 - tslib: 2.8.1 + cookie: 1.1.1 + react: 19.2.7 + set-cookie-parser: 2.7.2 optionalDependencies: - '@types/react': 18.3.28 - - react@18.3.1: - dependencies: - loose-envify: 1.4.0 + react-dom: 19.2.7(react@19.2.7) - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.2 + react@19.2.7: {} reflect.getprototypeof@1.0.10: dependencies: @@ -6183,7 +5086,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 get-proto: 1.0.1 which-builtin-type: 1.2.1 @@ -6208,19 +5111,19 @@ snapshots: regenerate: 1.4.2 regenerate-unicode-properties: 10.2.2 regjsgen: 0.8.0 - regjsparser: 0.13.1 + regjsparser: 0.13.2 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 regjsgen@0.8.0: {} - regjsparser@0.13.1: + regjsparser@0.13.2: dependencies: jsesc: 3.1.0 require-from-string@2.0.2: {} - resolve-from@4.0.0: {} + reselect@5.2.0: {} resolve@1.22.12: dependencies: @@ -6229,42 +5132,57 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - reusify@1.1.0: {} - - rollup@4.60.3: + rolldown@1.1.5: dependencies: - '@types/estree': 1.0.8 + '@oxc-project/types': 0.139.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.3 - '@rollup/rollup-android-arm64': 4.60.3 - '@rollup/rollup-darwin-arm64': 4.60.3 - '@rollup/rollup-darwin-x64': 4.60.3 - '@rollup/rollup-freebsd-arm64': 4.60.3 - '@rollup/rollup-freebsd-x64': 4.60.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 - '@rollup/rollup-linux-arm-musleabihf': 4.60.3 - '@rollup/rollup-linux-arm64-gnu': 4.60.3 - '@rollup/rollup-linux-arm64-musl': 4.60.3 - '@rollup/rollup-linux-loong64-gnu': 4.60.3 - '@rollup/rollup-linux-loong64-musl': 4.60.3 - '@rollup/rollup-linux-ppc64-gnu': 4.60.3 - '@rollup/rollup-linux-ppc64-musl': 4.60.3 - '@rollup/rollup-linux-riscv64-gnu': 4.60.3 - '@rollup/rollup-linux-riscv64-musl': 4.60.3 - '@rollup/rollup-linux-s390x-gnu': 4.60.3 - '@rollup/rollup-linux-x64-gnu': 4.60.3 - '@rollup/rollup-linux-x64-musl': 4.60.3 - '@rollup/rollup-openbsd-x64': 4.60.3 - '@rollup/rollup-openharmony-arm64': 4.60.3 - '@rollup/rollup-win32-arm64-msvc': 4.60.3 - '@rollup/rollup-win32-ia32-msvc': 4.60.3 - '@rollup/rollup-win32-x64-gnu': 4.60.3 - '@rollup/rollup-win32-x64-msvc': 4.60.3 - fsevents: 2.3.3 - - run-parallel@1.2.0: + '@rolldown/binding-android-arm64': 1.1.5 + '@rolldown/binding-darwin-arm64': 1.1.5 + '@rolldown/binding-darwin-x64': 1.1.5 + '@rolldown/binding-freebsd-x64': 1.1.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 + '@rolldown/binding-linux-arm64-gnu': 1.1.5 + '@rolldown/binding-linux-arm64-musl': 1.1.5 + '@rolldown/binding-linux-ppc64-gnu': 1.1.5 + '@rolldown/binding-linux-s390x-gnu': 1.1.5 + '@rolldown/binding-linux-x64-gnu': 1.1.5 + '@rolldown/binding-linux-x64-musl': 1.1.5 + '@rolldown/binding-openharmony-arm64': 1.1.5 + '@rolldown/binding-wasm32-wasi': 1.1.5 + '@rolldown/binding-win32-arm64-msvc': 1.1.5 + '@rolldown/binding-win32-x64-msvc': 1.1.5 + + rollup@4.62.2: dependencies: - queue-microtask: 1.2.3 + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.2 + '@rollup/rollup-android-arm64': 4.62.2 + '@rollup/rollup-darwin-arm64': 4.62.2 + '@rollup/rollup-darwin-x64': 4.62.2 + '@rollup/rollup-freebsd-arm64': 4.62.2 + '@rollup/rollup-freebsd-x64': 4.62.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 + '@rollup/rollup-linux-arm64-musl': 4.62.2 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 + '@rollup/rollup-linux-loong64-musl': 4.62.2 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 + '@rollup/rollup-linux-x64-gnu': 4.62.2 + '@rollup/rollup-linux-x64-musl': 4.62.2 + '@rollup/rollup-openbsd-x64': 4.62.2 + '@rollup/rollup-openharmony-arm64': 4.62.2 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 + '@rollup/rollup-win32-x64-gnu': 4.62.2 + '@rollup/rollup-win32-x64-msvc': 4.62.2 + fsevents: 2.3.3 safe-array-concat@1.1.4: dependencies: @@ -6285,15 +5203,15 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 + scheduler@0.27.0: {} semver@6.3.1: {} - semver@7.8.0: {} + semver@7.8.5: {} - serialize-javascript@7.0.5: {} + serialize-javascript@7.0.7: {} + + set-cookie-parser@2.7.2: {} set-function-length@1.2.2: dependencies: @@ -6315,7 +5233,39 @@ snapshots: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 + + sharp-ico@0.1.5: + dependencies: + decode-ico: 0.4.1 + ico-endec: 0.1.6 + sharp: 0.33.5 + + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 shebang-command@2.0.0: dependencies: @@ -6343,7 +5293,7 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -6353,12 +5303,16 @@ snapshots: signal-exit@4.1.0: {} - smob@1.6.1: {} + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + smob@1.6.2: {} - sonner@2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + sonner@2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) source-map-js@1.2.1: {} @@ -6369,9 +5323,7 @@ snapshots: source-map@0.6.1: {} - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 + source-map@0.8.0: {} stop-iteration-iterator@1.1.0: dependencies: @@ -6385,37 +5337,38 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 gopd: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.1.0 + side-channel: 1.1.1 - string.prototype.trim@1.2.10: + string.prototype.trim@1.2.11: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 - string.prototype.trimend@1.0.9: + string.prototype.trimend@1.0.10: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.9 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 stringify-object@3.3.0: dependencies: @@ -6425,57 +5378,11 @@ snapshots: strip-comments@2.0.1: {} - strip-json-comments@3.1.1: {} - - sucrase@3.35.1: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.7 - tinyglobby: 0.2.16 - ts-interface-checker: 0.1.13 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - supports-preserve-symlinks-flag@1.0.0: {} - tailwind-merge@2.6.1: {} - - tailwindcss-animate@1.0.7(tailwindcss@3.4.19): - dependencies: - tailwindcss: 3.4.19 + tailwindcss@4.3.2: {} - tailwindcss@3.4.19: - 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.14 - postcss-import: 15.1.0(postcss@8.5.14) - postcss-js: 4.1.0(postcss@8.5.14) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.14) - postcss-nested: 6.2.0(postcss@8.5.14) - postcss-selector-parser: 6.1.2 - resolve: 1.22.12 - sucrase: 3.35.1 - transitivePeerDependencies: - - tsx - - yaml + tapable@2.3.3: {} temp-dir@2.0.0: {} @@ -6486,41 +5393,26 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 - terser@5.47.1: + terser@5.49.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.16.0 + acorn: 8.17.0 commander: 2.20.3 source-map-support: 0.5.21 - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: + tinyglobby@0.2.17: dependencies: - any-promise: 1.3.0 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 - tinyglobby@0.2.16: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tr46@1.0.1: - dependencies: - punycode: 2.3.1 + to-data-view@1.1.0: {} ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - ts-interface-checker@0.1.13: {} - - tslib@2.8.1: {} + tslib@2.8.1: + optional: true type-check@0.4.0: dependencies: @@ -6552,7 +5444,7 @@ snapshots: is-typed-array: 1.1.15 reflect.getprototypeof: 1.0.10 - typed-array-length@1.0.7: + typed-array-length@1.0.8: dependencies: call-bind: 1.0.9 for-each: 0.3.5 @@ -6561,13 +5453,13 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3): + typescript-eslint@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.4(jiti@1.21.7) + '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) + eslint: 10.6.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -6581,7 +5473,20 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@6.21.0: {} + unconfig-core@7.5.0: + dependencies: + '@quansync/fs': 1.0.0 + quansync: 1.0.0 + + unconfig@7.5.0: + dependencies: + '@quansync/fs': 1.0.0 + defu: 6.1.7 + jiti: 2.7.0 + quansync: 1.0.0 + unconfig-core: 7.5.0 + + undici-types@8.3.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -6602,9 +5507,9 @@ snapshots: upath@1.2.0: {} - update-browserslist-db@1.2.3(browserslist@4.28.2): + update-browserslist-db@1.2.3(browserslist@4.28.5): dependencies: - browserslist: 4.28.2 + browserslist: 4.28.5 escalade: 3.2.0 picocolors: 1.1.1 @@ -6612,71 +5517,38 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - - use-sidecar@1.1.3(@types/react@18.3.28)(react@18.3.1): - dependencies: - detect-node-es: 1.1.0 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - - use-sync-external-store@1.6.0(react@18.3.1): - dependencies: - react: 18.3.1 - - util-deprecate@1.0.2: {} - - vaul@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + use-sync-external-store@1.6.0(react@19.2.7): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' + react: 19.2.7 - vite-plugin-pwa@0.21.2(vite@6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1))(workbox-build@7.4.1(@types/babel__core@7.20.5))(workbox-window@7.4.1): + vite-plugin-pwa@1.3.0(@vite-pwa/assets-generator@1.0.2)(vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0))(workbox-build@7.4.1)(workbox-window@7.4.1): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 - tinyglobby: 0.2.16 - vite: 6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1) - workbox-build: 7.4.1(@types/babel__core@7.20.5) + tinyglobby: 0.2.17 + vite: 8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0) + workbox-build: 7.4.1 workbox-window: 7.4.1 + optionalDependencies: + '@vite-pwa/assets-generator': 1.0.2 transitivePeerDependencies: - supports-color - vite@6.4.2(@types/node@22.19.19)(jiti@1.21.7)(terser@5.47.1): + vite@8.1.4(@types/node@26.1.1)(jiti@2.7.0)(terser@5.49.0): dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - postcss: 8.5.14 - rollup: 4.60.3 - tinyglobby: 0.2.16 + lightningcss: 1.32.0 + picomatch: 4.0.5 + postcss: 8.5.16 + rolldown: 1.1.5 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 22.19.19 + '@types/node': 26.1.1 fsevents: 2.3.3 - jiti: 1.21.7 - terser: 5.47.1 + jiti: 2.7.0 + terser: 5.49.0 void-elements@3.1.0: {} - webidl-conversions@4.0.2: {} - - whatwg-url@7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -6688,7 +5560,7 @@ snapshots: which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 - function.prototype.name: 1.1.8 + function.prototype.name: 1.2.0 has-tostringtag: 1.0.2 is-async-function: 2.1.1 is-date-object: 1.1.0 @@ -6699,7 +5571,7 @@ snapshots: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.20 + which-typed-array: 1.1.22 which-collection@1.0.2: dependencies: @@ -6708,7 +5580,7 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 - which-typed-array@1.1.20: + which-typed-array@1.1.22: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.9 @@ -6733,16 +5605,16 @@ snapshots: dependencies: workbox-core: 7.4.1 - workbox-build@7.4.1(@types/babel__core@7.20.5): + workbox-build@7.4.1: dependencies: '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) - '@babel/core': 7.29.0 - '@babel/preset-env': 7.29.5(@babel/core@7.29.0) - '@babel/runtime': 7.29.2 - '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.0)(@types/babel__core@7.20.5)(rollup@4.60.3) - '@rollup/plugin-node-resolve': 16.0.3(rollup@4.60.3) - '@rollup/plugin-replace': 6.0.3(rollup@4.60.3) - '@rollup/plugin-terser': 1.0.0(rollup@4.60.3) + '@babel/core': 7.29.7 + '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + '@babel/runtime': 7.29.7 + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7)(rollup@4.62.2) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.62.2) + '@rollup/plugin-replace': 6.0.3(rollup@4.62.2) + '@rollup/plugin-terser': 1.0.0(rollup@4.62.2) '@trickfilm400/rollup-plugin-off-main-thread': 3.0.0-pre1 ajv: 8.20.0 common-tags: 1.8.2 @@ -6751,8 +5623,8 @@ snapshots: fs-extra: 9.1.0 glob: 11.1.0 pretty-bytes: 5.6.0 - rollup: 4.60.3 - source-map: 0.8.0-beta.0 + rollup: 4.62.2 + source-map: 0.8.0 stringify-object: 3.3.0 strip-comments: 2.0.1 tempy: 0.6.0 @@ -6841,10 +5713,14 @@ snapshots: yocto-queue@0.1.0: {} - zod@3.25.76: {} + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} - zustand@5.0.13(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + zustand@5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)): optionalDependencies: - '@types/react': 18.3.28 - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) + '@types/react': 19.2.17 + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) diff --git a/apps/frontend/pnpm-workspace.yaml b/apps/frontend/pnpm-workspace.yaml index 5ed0b5a..dbb26c8 100644 --- a/apps/frontend/pnpm-workspace.yaml +++ b/apps/frontend/pnpm-workspace.yaml @@ -1,2 +1,3 @@ allowBuilds: esbuild: true + sharp: true diff --git a/apps/frontend/postcss.config.js b/apps/frontend/postcss.config.js deleted file mode 100644 index 2e7af2b..0000000 --- a/apps/frontend/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/apps/frontend/public/apple-touch-icon-180x180.png b/apps/frontend/public/apple-touch-icon-180x180.png new file mode 100644 index 0000000..93a74cb Binary files /dev/null and b/apps/frontend/public/apple-touch-icon-180x180.png differ diff --git a/apps/frontend/public/assets/app-icon.png b/apps/frontend/public/assets/app-icon.png deleted file mode 100644 index f10cd2f..0000000 Binary files a/apps/frontend/public/assets/app-icon.png and /dev/null differ diff --git a/apps/frontend/public/assets/avatars/04.png b/apps/frontend/public/assets/avatars/04.png deleted file mode 100644 index 1129539..0000000 Binary files a/apps/frontend/public/assets/avatars/04.png and /dev/null differ diff --git a/apps/frontend/public/assets/logo.png b/apps/frontend/public/assets/logo.png deleted file mode 100644 index 641ba7c..0000000 Binary files a/apps/frontend/public/assets/logo.png and /dev/null differ diff --git a/apps/frontend/public/assets/pwa/app-icon-16.png b/apps/frontend/public/assets/pwa/app-icon-16.png deleted file mode 100644 index 2ad0ee4..0000000 Binary files a/apps/frontend/public/assets/pwa/app-icon-16.png and /dev/null differ diff --git a/apps/frontend/public/assets/pwa/app-icon-180.png b/apps/frontend/public/assets/pwa/app-icon-180.png deleted file mode 100644 index 11156ec..0000000 Binary files a/apps/frontend/public/assets/pwa/app-icon-180.png and /dev/null differ diff --git a/apps/frontend/public/assets/pwa/app-icon-192.png b/apps/frontend/public/assets/pwa/app-icon-192.png deleted file mode 100644 index 971521e..0000000 Binary files a/apps/frontend/public/assets/pwa/app-icon-192.png and /dev/null differ diff --git a/apps/frontend/public/assets/pwa/app-icon-32.png b/apps/frontend/public/assets/pwa/app-icon-32.png deleted file mode 100644 index 53037e0..0000000 Binary files a/apps/frontend/public/assets/pwa/app-icon-32.png and /dev/null differ diff --git a/apps/frontend/public/assets/pwa/app-icon-512.png b/apps/frontend/public/assets/pwa/app-icon-512.png deleted file mode 100644 index 4cc393b..0000000 Binary files a/apps/frontend/public/assets/pwa/app-icon-512.png and /dev/null differ diff --git a/apps/frontend/public/assets/pwa/app-icon-maskable-512.png b/apps/frontend/public/assets/pwa/app-icon-maskable-512.png deleted file mode 100644 index 6993485..0000000 Binary files a/apps/frontend/public/assets/pwa/app-icon-maskable-512.png and /dev/null differ diff --git a/apps/frontend/public/assets/undraw_dashboard_re_3b76.svg b/apps/frontend/public/assets/undraw_dashboard_re_3b76.svg deleted file mode 100644 index 78d1443..0000000 --- a/apps/frontend/public/assets/undraw_dashboard_re_3b76.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/frontend/public/assets/undraw_online_payments_re_y8f2.svg b/apps/frontend/public/assets/undraw_online_payments_re_y8f2.svg deleted file mode 100644 index 629592c..0000000 --- a/apps/frontend/public/assets/undraw_online_payments_re_y8f2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/frontend/public/assets/undraw_security_on_re_e491.svg b/apps/frontend/public/assets/undraw_security_on_re_e491.svg deleted file mode 100644 index 860e90c..0000000 --- a/apps/frontend/public/assets/undraw_security_on_re_e491.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/frontend/public/favicon.ico b/apps/frontend/public/favicon.ico index f8fc309..a2b4e3f 100644 Binary files a/apps/frontend/public/favicon.ico and b/apps/frontend/public/favicon.ico differ diff --git a/apps/frontend/public/favicon.svg b/apps/frontend/public/favicon.svg index 2f237a7..677309b 100644 --- a/apps/frontend/public/favicon.svg +++ b/apps/frontend/public/favicon.svg @@ -1,10 +1,5 @@ - - - - - - - - - $ + + + + diff --git a/apps/frontend/public/maskable-icon-512x512.png b/apps/frontend/public/maskable-icon-512x512.png new file mode 100644 index 0000000..bb958e5 Binary files /dev/null and b/apps/frontend/public/maskable-icon-512x512.png differ diff --git a/apps/frontend/public/pwa-192x192.png b/apps/frontend/public/pwa-192x192.png new file mode 100644 index 0000000..6512c87 Binary files /dev/null and b/apps/frontend/public/pwa-192x192.png differ diff --git a/apps/frontend/public/pwa-512x512.png b/apps/frontend/public/pwa-512x512.png new file mode 100644 index 0000000..d9bcab5 Binary files /dev/null and b/apps/frontend/public/pwa-512x512.png differ diff --git a/apps/frontend/public/pwa-64x64.png b/apps/frontend/public/pwa-64x64.png new file mode 100644 index 0000000..eaeacb4 Binary files /dev/null and b/apps/frontend/public/pwa-64x64.png differ diff --git a/apps/frontend/public/vite.svg b/apps/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/apps/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/frontend/robots.txt b/apps/frontend/robots.txt deleted file mode 100644 index 67285c6..0000000 --- a/apps/frontend/robots.txt +++ /dev/null @@ -1,12 +0,0 @@ -User-agent: * -# Block private/authenticated sections -Disallow: /bitfinance/dashboard/ -Disallow: /bitfinance/account/ -Disallow: /bitfinance/auth/sign-in -Disallow: /bitfinance/auth/sign-up -Disallow: /bitfinance/api/ - -# Allow public content -Allow: /bitfinance/ - -Sitemap: https://gustavomiranda.dev/bitfinance/sitemap.xml diff --git a/apps/frontend/sitemap.xml b/apps/frontend/sitemap.xml deleted file mode 100644 index 1cefd7a..0000000 --- a/apps/frontend/sitemap.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - https://gustavomiranda.dev/bitfinance/ - 2026-02-18 - monthly - 1.0 - - diff --git a/apps/frontend/src/api/account/account.service.ts b/apps/frontend/src/api/account/account.service.ts index 336c45b..228bb09 100644 --- a/apps/frontend/src/api/account/account.service.ts +++ b/apps/frontend/src/api/account/account.service.ts @@ -1,59 +1,34 @@ -import { privateAPI } from "@/lib/axios"; - -import { normalizeError } from "@/api/shared/normalize-error"; - -import type { AvatarResponse, UpdateProfileRequest } from "./account.types"; - -const authApi = privateAPI(); +import { authApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { User } from "../auth/auth.types"; export const accountService = { - async updateProfileAsync(request: UpdateProfileRequest) { + async updateProfileAsync(firstName: string, lastName: string): Promise { try { - const response = await authApi.post("/identity/manage/profile", { - firstName: request.firstName, - lastName: request.lastName, - }); - - return response.data; + return (await authApi.post("/identity/manage/profile", { firstName, lastName })).data; } catch (error) { - throw normalizeError(error, "Failed to update profile."); + throw normalizeApiError(error, "api.account.updateProfile"); } }, - - async uploadAvatarAsync(file: File): Promise { + async uploadAvatarAsync(file: File) { try { - const formData = new FormData(); - formData.append("file", file); - - const response = await authApi.post( - "/identity/manage/avatar", - formData, - { - headers: { - "Content-Type": "multipart/form-data", - }, - } - ); - - return response.data; + const form = new FormData(); + form.append("file", file); + return ( + await authApi.post<{ id: string; fileName: string; contentType: string }>( + "/identity/manage/avatar", + form, + ) + ).data; } catch (error) { - throw normalizeError(error, "Failed to upload avatar."); + throw normalizeApiError(error, "api.account.uploadAvatar"); } }, - - async deleteAvatarAsync(): Promise { + async deleteAvatarAsync() { try { await authApi.delete("/identity/manage/avatar"); } catch (error) { - throw normalizeError(error, "Failed to delete avatar."); - } - }, - - async logoutAllDevicesAsync(): Promise { - try { - await authApi.post("/identity/logout-all"); - } catch (error) { - throw normalizeError(error, "Failed to log out all devices."); + throw normalizeApiError(error, "api.account.removeAvatar"); } }, }; diff --git a/apps/frontend/src/api/account/account.types.ts b/apps/frontend/src/api/account/account.types.ts deleted file mode 100644 index 61a2ac9..0000000 --- a/apps/frontend/src/api/account/account.types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface UpdateProfileRequest { - firstName: string; - lastName: string; -} - -export interface AvatarResponse { - id: string; - fileName: string; - contentType: string; -} diff --git a/apps/frontend/src/api/account/index.ts b/apps/frontend/src/api/account/index.ts deleted file mode 100644 index 5fbfd82..0000000 --- a/apps/frontend/src/api/account/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { accountService } from "./account.service"; -export type { AvatarResponse, UpdateProfileRequest } from "./account.types"; diff --git a/apps/frontend/src/api/auth/auth.service.ts b/apps/frontend/src/api/auth/auth.service.ts index afddf20..3c43979 100644 --- a/apps/frontend/src/api/auth/auth.service.ts +++ b/apps/frontend/src/api/auth/auth.service.ts @@ -1,76 +1,49 @@ -import { api, authApi } from "@/lib/axios"; - -import { normalizeError } from "@/api/shared/normalize-error"; -import type { User } from "@/auth/types"; - -import type { - AuthSessionResponse, - MeApiResponse, - SignInRequest, - SignUpRequest, -} from "./auth.types"; - -function mapMeApiResponse(response: MeApiResponse): User { - return { - id: response.id, - username: response.username, - fullName: response.fullName, - email: response.email, - avatarUrl: response.avatarUrl ?? null, - organizations: response.organizations ?? [], - }; -} +import { authApi, publicApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { AuthCredentials, AuthSessionResponse, RegisterCredentials, User } from "./auth.types"; +import { mapMeResponse } from "./auth.types"; export const authService = { - async signInAsync(request: SignInRequest): Promise { + async registerAsync(credentials: RegisterCredentials): Promise { try { - const response = await api.post( - "/identity/login", - request - ); - - return response.data; + return (await publicApi.post("/identity/register", credentials)).data; } catch (error) { - throw normalizeError(error, "Failed to sign in."); + throw normalizeApiError(error, "api.auth.createAccount"); } }, - - async signUpAsync(request: SignUpRequest): Promise { + async loginAsync(credentials: AuthCredentials): Promise { try { - const response = await api.post( - "/identity/register", - request - ); - - return response.data; + return (await publicApi.post("/identity/login", credentials)).data; } catch (error) { - throw normalizeError(error, "Failed to sign up."); + throw normalizeApiError(error, "api.auth.signIn"); } }, - async refreshAsync(): Promise { try { - const response = await api.post("/identity/refresh"); - return response.data; + return (await publicApi.post("/identity/refresh")).data; } catch (error) { - throw normalizeError(error, "Failed to restore session."); + throw normalizeApiError(error, "api.auth.restoreSession"); } }, - - async getMeAsync(): Promise { + async logoutAsync() { try { - const response = await authApi.get("/identity/me"); - return mapMeApiResponse(response.data); + await authApi.post("/identity/logout"); } catch (error) { - throw normalizeError(error, "Failed to load current user."); + throw normalizeApiError(error, "api.auth.signOut"); } }, - - async logoutAsync(): Promise { + async logoutAllAsync() { try { - await authApi.post("/identity/logout"); + await authApi.post("/identity/logout-all"); + } catch (error) { + throw normalizeApiError(error, "api.auth.signOutAll"); + } + }, + async getMeAsync(): Promise { + try { + return mapMeResponse((await authApi.get("/identity/me")).data); } catch (error) { - throw normalizeError(error, "Failed to sign out."); + throw normalizeApiError(error, "api.auth.loadAccount"); } }, }; diff --git a/apps/frontend/src/api/auth/auth.types.ts b/apps/frontend/src/api/auth/auth.types.ts index a1b82b2..9e32cdf 100644 --- a/apps/frontend/src/api/auth/auth.types.ts +++ b/apps/frontend/src/api/auth/auth.types.ts @@ -1,36 +1,47 @@ -import type { User } from "@/auth/types"; +export interface OrganizationSummary { + id: string; + name: string; +} -export interface AuthSessionUser { +export interface User { id: string; + username: string; + fullName: string; email: string; - userName: string; - firstName: string; - lastName: string; + organizations: OrganizationSummary[]; + avatarUrl?: string | null; } export interface AuthSessionResponse { accessToken: string; accessTokenExpiresAt: string; - user: AuthSessionUser; + user: { id: string; email: string; userName: string; firstName: string; lastName: string }; } -export interface SignInRequest { +export interface AuthCredentials { email: string; password: string; } -export interface SignUpRequest { +export interface RegisterCredentials extends AuthCredentials { firstName: string; lastName: string; - email: string; - password: string; } -export interface MeApiResponse { +interface MeResponse { id: string; - username: string; fullName: string; email: string; - avatarUrl?: string | null; - organizations?: User["organizations"]; + userName: string; + organizations?: OrganizationSummary[]; +} + +export function mapMeResponse(response: MeResponse): User { + return { + id: response.id, + username: response.userName, + fullName: response.fullName, + email: response.email, + organizations: response.organizations ?? [], + }; } diff --git a/apps/frontend/src/api/auth/index.ts b/apps/frontend/src/api/auth/index.ts deleted file mode 100644 index c5d5be2..0000000 --- a/apps/frontend/src/api/auth/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { authService } from "./auth.service"; -export type { - AuthSessionResponse, - AuthSessionUser, - MeApiResponse, - SignInRequest, - SignUpRequest, -} from "./auth.types"; diff --git a/apps/frontend/src/api/bills/bills.service.ts b/apps/frontend/src/api/bills/bills.service.ts index 6ce8e2d..54e0bf1 100644 --- a/apps/frontend/src/api/bills/bills.service.ts +++ b/apps/frontend/src/api/bills/bills.service.ts @@ -1,321 +1,159 @@ -import { privateAPI } from "@/lib/axios"; +import { authApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { Bill, BillDocument, BillInput, BillListFilters, Paged } from "./bills.types"; -import { normalizeError } from "@/api/shared/normalize-error"; - -import type { +type BillWire = Omit< Bill, - BillSeriesType, - BillsListQuery, - BillsListResponse, - BillDocument, - CreateBillRequest, - CreateBillResponse, - DeleteBillDocumentRequest, - DownloadBillDocumentRequest, - StopBillSeriesRequest, - UpdateBillRequest, - UpdateBillResponse, - UploadBillDocumentResponse, - UploadBillDocumentsRequest, -} from "./bills.types"; - -const authApi = privateAPI(); - -interface BillAttachmentApiResponse { - id: string; - fileName: string; - contentType: string; - fileCategory: UploadBillDocumentResponse["fileCategory"]; - attachmentType: UploadBillDocumentResponse["attachmentType"]; -} - -interface BillApiResponse extends Omit { - category: string; - status: string; - attachments?: BillAttachmentApiResponse[]; - billSeriesType?: string | null; -} - -interface BillsListApiResponse extends Omit { - data: BillApiResponse[]; -} - -interface CreateBillApiResponse { - id: string; - description: string; + "category" | "status" | "billSeriesType" | "billSeriesFrequency" | "documents" | "paymentDate" +> & { category: string; status: string; - amountDue: number; - amountPaid?: number | null; - createdDate: string; - dueDate: string; - paidDate?: string | null; - billSeriesId?: string | null; - occurrenceNumber?: number | null; - totalOccurrences?: number | null; billSeriesType?: string | null; -} - -interface UpdateBillApiResponse { - id: string; - description: string; - category: string; - status: string; - amountDue: number; - amountPaid?: number | null; - dueDate: string; + billSeriesFrequency?: string | null; + paymentDate?: string | null; paidDate?: string | null; - billSeriesId?: string | null; - occurrenceNumber?: number | null; - totalOccurrences?: number | null; - billSeriesType?: string | null; - billSeriesIsActive?: boolean; -} - -function mapStatus(status: string): Bill["status"] { - return status.toLowerCase() as Bill["status"]; -} - -function mapCategory(category: string): Bill["category"] { - return category.toLowerCase() as Bill["category"]; -} - -function mapSeriesType(type?: string | null): BillSeriesType | null | undefined { - if (type === null) return null; - if (type === undefined) return undefined; - return type.toLowerCase() as BillSeriesType; -} - -function mapAttachment(attachment: BillAttachmentApiResponse): BillDocument { - return { - id: attachment.id, - fileName: attachment.fileName, - contentType: attachment.contentType, - fileCategory: attachment.fileCategory, - attachmentType: attachment.attachmentType, - }; -} - -function mapBill(bill: BillApiResponse): Bill { - return { - ...bill, - category: mapCategory(bill.category), - status: mapStatus(bill.status), - billSeriesType: mapSeriesType(bill.billSeriesType), - paymentDate: bill.paymentDate ?? bill.paidDate ?? null, - documents: bill.attachments?.map(mapAttachment) ?? [], - }; -} - -function mapCreateBillResponse(bill: CreateBillApiResponse): CreateBillResponse { - return { - id: bill.id, - description: bill.description, - category: mapCategory(bill.category), - status: mapStatus(bill.status), - amountDue: bill.amountDue, - amountPaid: bill.amountPaid ?? null, - createdDate: bill.createdDate, - dueDate: bill.dueDate, - paymentDate: bill.paidDate ?? null, - billSeriesId: bill.billSeriesId ?? null, - occurrenceNumber: bill.occurrenceNumber ?? null, - totalOccurrences: bill.totalOccurrences ?? null, - billSeriesType: mapSeriesType(bill.billSeriesType), - }; -} - -function mapUpdateBillResponse(bill: UpdateBillApiResponse): UpdateBillResponse { - return { - id: bill.id, - description: bill.description, - category: mapCategory(bill.category), - status: mapStatus(bill.status), - dueDate: bill.dueDate, - paymentDate: bill.paidDate ?? null, - amountDue: bill.amountDue, - amountPaid: bill.amountPaid ?? null, - billSeriesId: bill.billSeriesId ?? null, - occurrenceNumber: bill.occurrenceNumber ?? null, - totalOccurrences: bill.totalOccurrences ?? null, - billSeriesType: mapSeriesType(bill.billSeriesType), - billSeriesIsActive: bill.billSeriesIsActive ?? false, - }; -} - -async function uploadDocumentAsync( - organizationId: string, - billId: string, - file: File, - documentType: UploadBillDocumentsRequest["documentType"] -): Promise { - const formData = new FormData(); - formData.append("file", file); - formData.append("fileCategory", documentType); - - const response = await authApi.post( - `/organizations/${organizationId}/bills/${billId}/documents`, - formData, - { - headers: { - "Content-Type": "multipart/form-data", - }, - } - ); - - return response.data; -} + attachments?: BillDocument[]; +}; +const normalize = (value: string) => value.toLowerCase(); +const map = (wire: BillWire): Bill => ({ + ...wire, + category: normalize(wire.category) as Bill["category"], + status: normalize(wire.status) as Bill["status"], + billSeriesType: wire.billSeriesType + ? (normalize(wire.billSeriesType) as Bill["billSeriesType"]) + : null, + billSeriesFrequency: wire.billSeriesFrequency + ? (normalize(wire.billSeriesFrequency) as Bill["billSeriesFrequency"]) + : null, + paymentDate: wire.paymentDate ?? wire.paidDate ?? null, + documents: wire.attachments ?? [], + billSeriesId: wire.billSeriesId ?? null, + occurrenceNumber: wire.occurrenceNumber ?? null, + totalOccurrences: wire.totalOccurrences ?? null, + billSeriesIsActive: wire.billSeriesIsActive ?? false, + amountPaid: wire.amountPaid ?? null, +}); export const billsService = { - async getAsync(organizationId: string, billId: string): Promise { + async listAsync(filters: BillListFilters): Promise> { try { - const response = await authApi.get( - `/organizations/${organizationId}/bills/${billId}` + const response = await authApi.get>( + `/organizations/${filters.organizationId}/bills`, + { + params: { + page: filters.page, + pageSize: filters.pageSize, + from: filters.from?.toISOString(), + to: filters.to?.toISOString(), + status: filters.status, + description: filters.description || undefined, + }, + }, ); - - return mapBill(response.data); + return { ...response.data, data: response.data.data.map(map) }; } catch (error) { - throw normalizeError(error, "Failed to fetch bill."); + throw normalizeApiError(error, "api.bills.load"); } }, - - async listAsync(query: BillsListQuery): Promise { + async getAsync(organizationId: string, billId: string) { try { - const response = await authApi.get( - `/organizations/${query.organizationId}/bills`, - { - params: { - from: query.from, - to: query.to, - status: query.status?.join(",") || undefined, - description: query.description || undefined, - }, - } + return map( + (await authApi.get(`/organizations/${organizationId}/bills/${billId}`)).data, ); - - return { - ...response.data, - data: response.data.data.map(mapBill), - }; } catch (error) { - throw normalizeError(error, "Failed to fetch bills."); + throw normalizeApiError(error, "api.bills.loadOne"); } }, - - async createAsync(request: CreateBillRequest): Promise { + async createAsync(organizationId: string, input: BillInput) { try { - const response = await authApi.post( - `/organizations/${request.organizationId}/bills`, - { - description: request.description, - category: request.category, - status: request.status, - dueDate: request.dueDate, - amountDue: request.amountDue, - paymentDate: request.paymentDate, - amountPaid: request.amountPaid, - frequency: request.frequency ?? undefined, - installments: request.installments ?? undefined, - } + return map( + (await authApi.post(`/organizations/${organizationId}/bills`, input)).data, ); - - return mapCreateBillResponse(response.data); } catch (error) { - throw normalizeError(error, "Failed to create bill."); + throw normalizeApiError(error, "api.bills.create"); } }, - - async updateAsync(request: UpdateBillRequest): Promise { + async updateAsync( + organizationId: string, + billId: string, + input: Omit, + ) { try { - const response = await authApi.patch( - `/organizations/${request.organizationId}/bills/${request.id}`, - { - description: request.description, - category: request.category, - status: request.status, - dueDate: request.dueDate, - amountDue: request.amountDue, - paymentDate: request.paymentDate, - amountPaid: request.amountPaid, - } + return map( + (await authApi.patch(`/organizations/${organizationId}/bills/${billId}`, input)) + .data, ); - - return mapUpdateBillResponse(response.data); } catch (error) { - throw normalizeError(error, "Failed to update bill."); + throw normalizeApiError(error, "api.bills.update"); } }, - - async deleteAsync(id: string, organizationId: string): Promise { + async deleteAsync(organizationId: string, billId: string) { try { - await authApi.delete(`/organizations/${organizationId}/bills/${id}`); + await authApi.delete(`/organizations/${organizationId}/bills/${billId}`); } catch (error) { - throw normalizeError(error, "Failed to delete bill."); + throw normalizeApiError(error, "api.bills.delete"); } }, - - async stopSeriesAsync(request: StopBillSeriesRequest): Promise { + async uploadDocumentAsync( + organizationId: string, + billId: string, + file: File, + fileCategory: string, + ) { try { - await authApi.post( - `/organizations/${request.organizationId}/bills/series/${request.seriesId}/stop` - ); + const form = new FormData(); + form.append("file", file); + form.append("fileCategory", fileCategory); + return ( + await authApi.post( + `/organizations/${organizationId}/bills/${billId}/documents`, + form, + ) + ).data; } catch (error) { - throw normalizeError(error, "Failed to stop future bills."); + throw normalizeApiError(error, "api.bills.uploadDocument"); } }, - - async uploadDocumentsAsync( - payload: UploadBillDocumentsRequest - ): Promise { + async getDocumentAsync(organizationId: string, billId: string, documentId: string) { try { - const uploadResults = await Promise.all( - payload.files.map((file) => - uploadDocumentAsync( - payload.organizationId, - payload.billId, - file, - payload.documentType - ) + return ( + await authApi.get( + `/organizations/${organizationId}/bills/${billId}/documents/${documentId}`, + { responseType: "blob" }, ) - ); - return uploadResults; + ).data; } catch (error) { - throw normalizeError(error, "Failed to upload bill documents."); + throw normalizeApiError(error, "api.bills.openDocument"); } }, - - async downloadDocumentAsync( - payload: DownloadBillDocumentRequest - ): Promise { + async getDocumentDownloadUrlAsync(organizationId: string, billId: string, documentId: string) { try { - const response = await authApi.get( - `/organizations/${payload.organizationId}/bills/${payload.billId}/documents/${payload.documentId}`, - { - responseType: "blob", - } - ); - - const blob = new Blob([response.data]); - const url = window.URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - link.download = payload.fileName; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - window.URL.revokeObjectURL(url); + return ( + await authApi.get<{ + url: string; + fileName: string; + contentType: string; + expiresAt: string; + }>(`/organizations/${organizationId}/bills/${billId}/documents/${documentId}/download-url`) + ).data; } catch (error) { - throw normalizeError(error, "Failed to download bill document."); + throw normalizeApiError(error, "api.bills.prepareDownload"); } }, - - async deleteDocumentAsync(payload: DeleteBillDocumentRequest): Promise { + async deleteDocumentAsync(organizationId: string, billId: string, documentId: string) { try { await authApi.delete( - `/organizations/${payload.organizationId}/bills/${payload.billId}/documents/${payload.documentId}` + `/organizations/${organizationId}/bills/${billId}/documents/${documentId}`, ); } catch (error) { - throw normalizeError(error, "Failed to delete bill document."); + throw normalizeApiError(error, "api.bills.removeDocument"); + } + }, + async stopSeriesAsync(organizationId: string, seriesId: string) { + try { + await authApi.post(`/organizations/${organizationId}/bills/series/${seriesId}/stop`); + } catch (error) { + throw normalizeApiError(error, "api.bills.stopFuture"); } }, }; diff --git a/apps/frontend/src/api/bills/bills.types.ts b/apps/frontend/src/api/bills/bills.types.ts index e4b7b53..2b78a66 100644 --- a/apps/frontend/src/api/bills/bills.types.ts +++ b/apps/frontend/src/api/bills/bills.types.ts @@ -1,173 +1,71 @@ export type BillCategory = | "housing" - | "transportation" - | "food" | "utilities" - | "clothing" + | "food" + | "transportation" | "healthcare" + | "subscriptions" + | "education" | "insurance" | "personal" - | "debt" - | "savings" - | "education" - | "entertainment" - | "miscellaneous" - | "subscriptions" | "taxes" - | "pets"; - -export type BillStatus = - | "created" - | "due" - | "paid" - | "overdue" - | "cancelled" - | "upcoming"; - -export type Frequency = "daily" | "weekly" | "monthly" | "annually"; - + | "miscellaneous" + | "travel" + | "gifts" + | "pets" + | "services"; +export type BillStatus = "created" | "upcoming" | "due" | "overdue" | "paid" | "cancelled"; export type BillSeriesType = "recurring" | "installment"; - -export type BillType = "one-time" | "recurring" | "installment"; - -export type BillDocumentType = "Invoice" | "Receipt" | "Contract" | "Other"; - -export type BillFileCategory = "Boleto" | "Receipt" | "Other"; - -export type BillAttachmentType = "BillDocument" | "ExpenseDocument" | "UserAvatar"; - +export type BillFrequency = "daily" | "weekly" | "monthly" | "annually"; +export type FileCategory = "Invoice" | "Receipt" | "Boleto" | "Other"; export interface BillDocument { id: string; fileName: string; contentType: string; - fileCategory: BillFileCategory; - attachmentType: BillAttachmentType; + fileCategory: string; + attachmentType: string; } - export interface Bill { id: string; description: string; category: BillCategory; status: BillStatus; amountDue: number; - amountPaid?: number | null; - createdDate?: string; - createdAt?: string; + amountPaid: number | null; dueDate: string; - paymentDate?: string | null; - paidDate?: string | null; - deletedDate?: string | null; - notes?: string; - documents?: BillDocument[]; - billSeriesId?: string | null; - occurrenceNumber?: number | null; - totalOccurrences?: number | null; - billSeriesType?: BillSeriesType | null; - billSeriesIsActive?: boolean; -} - -export interface BillsListQuery { - organizationId: string; - from?: Date; - to?: Date; - status?: BillStatus[]; - description?: string; + paymentDate: string | null; + billSeriesId: string | null; + occurrenceNumber: number | null; + totalOccurrences: number | null; + billSeriesType: BillSeriesType | null; + billSeriesFrequency: BillFrequency | null; + billSeriesIsActive: boolean; + documents: BillDocument[]; } - -export interface BillsListResponse { - data: Bill[]; +export interface Paged { + data: T[]; page: number; pageSize: number; totalRecords: number; totalPages: number; } - -export interface CreateBillRequest { - description: string; - category: BillCategory; - status: BillStatus; - dueDate: string; - paymentDate?: string | null; - amountDue: number; - amountPaid?: number | null; - organizationId: string; - frequency?: Frequency | null; - installments?: number | null; -} - -export interface CreateBillResponse { - id: string; - description: string; - category: BillCategory; - status: BillStatus; - amountDue: number; - amountPaid?: number | null; - createdDate: string; - dueDate: string; - paymentDate?: string | null; - billSeriesId?: string | null; - occurrenceNumber?: number | null; - totalOccurrences?: number | null; - billSeriesType?: BillSeriesType | null; -} - -export interface UpdateBillRequest { - id: string; - description: string; - category: BillCategory; - status: BillStatus; - dueDate: string; - paymentDate?: string | null; - amountDue: number; - amountPaid?: number | null; +export interface BillListFilters { organizationId: string; + page: number; + pageSize: number; + from?: Date; + to?: Date; + status?: BillStatus; + description?: string; } - -export interface UpdateBillResponse { - id: string; +export interface BillInput { description: string; category: BillCategory; status: BillStatus; dueDate: string; - paymentDate?: string | null; + paymentDate: string | null; amountDue: number; - amountPaid?: number | null; - billSeriesId?: string | null; - occurrenceNumber?: number | null; - totalOccurrences?: number | null; - billSeriesType?: BillSeriesType | null; - billSeriesIsActive?: boolean; -} - -export interface StopBillSeriesRequest { - organizationId: string; - seriesId: string; -} - -export interface UploadBillDocumentsRequest { - organizationId: string; - billId: string; - files: File[]; - documentType: BillFileCategory; -} - -export interface UploadBillDocumentResponse { - id: string; - fileName: string; - contentType: string; - fileCategory: BillFileCategory; - attachmentType: BillAttachmentType; -} - -export interface DownloadBillDocumentRequest { - organizationId: string; - billId: string; - documentId: string; - fileName: string; -} - -export interface DeleteBillDocumentRequest { - organizationId: string; - billId: string; - documentId: string; + amountPaid: number | null; + frequency?: BillFrequency | null; + installments?: number | null; } diff --git a/apps/frontend/src/api/bills/index.ts b/apps/frontend/src/api/bills/index.ts deleted file mode 100644 index dff18d6..0000000 --- a/apps/frontend/src/api/bills/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -export { billsService } from "./bills.service"; -export type { - BillAttachmentType, - Bill, - BillCategory, - BillDocument, - BillDocumentType, - BillFileCategory, - BillSeriesType, - BillStatus, - BillType, - BillsListQuery, - BillsListResponse, - CreateBillRequest, - CreateBillResponse, - DeleteBillDocumentRequest, - DownloadBillDocumentRequest, - Frequency, - StopBillSeriesRequest, - UpdateBillRequest, - UpdateBillResponse, - UploadBillDocumentResponse, - UploadBillDocumentsRequest, -} from "./bills.types"; diff --git a/apps/frontend/src/api/dashboard/dashboard.service.ts b/apps/frontend/src/api/dashboard/dashboard.service.ts new file mode 100644 index 0000000..8b7fbbf --- /dev/null +++ b/apps/frontend/src/api/dashboard/dashboard.service.ts @@ -0,0 +1,60 @@ +import { authApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { DashboardBill, DashboardExpense, DashboardSummary } from "./dashboard.types"; + +type DateFilters = { from?: Date; to?: Date }; +const params = (filters?: DateFilters) => ({ + from: filters?.from?.toISOString(), + to: filters?.to?.toISOString(), +}); +const lower = (value: string) => value.toLowerCase(); + +export const dashboardService = { + async getSummaryAsync(organizationId: string, filters?: DateFilters) { + try { + return ( + await authApi.get(`/organizations/${organizationId}/dashboard/summary`, { + params: params(filters), + }) + ).data; + } catch (error) { + throw normalizeApiError(error, "api.dashboard.summary"); + } + }, + async getUpcomingBillsAsync( + organizationId: string, + filters?: DateFilters, + ): Promise { + try { + const data = ( + await authApi.get<{ data: DashboardBill[] }>( + `/organizations/${organizationId}/dashboard/upcoming-bills`, + { params: params(filters) }, + ) + ).data.data; + return data.map((item) => ({ + ...item, + category: lower(item.category), + status: lower(item.status), + })); + } catch (error) { + throw normalizeApiError(error, "api.dashboard.upcoming"); + } + }, + async getRecentExpensesAsync( + organizationId: string, + filters?: DateFilters, + ): Promise { + try { + const data = ( + await authApi.get<{ data: DashboardExpense[] }>( + `/organizations/${organizationId}/dashboard/recent-expenses`, + { params: params(filters) }, + ) + ).data.data; + return data.map((item) => ({ ...item, category: lower(item.category) })); + } catch (error) { + throw normalizeApiError(error, "api.dashboard.recent"); + } + }, +}; diff --git a/apps/frontend/src/api/dashboard/dashboard.types.ts b/apps/frontend/src/api/dashboard/dashboard.types.ts new file mode 100644 index 0000000..a81408f --- /dev/null +++ b/apps/frontend/src/api/dashboard/dashboard.types.ts @@ -0,0 +1,24 @@ +export interface DashboardSummary { + monthlyBudget: number | null; + spentThisMonth: number; + remainingBudget: number | null; + spentPercentage: number | null; + upcomingBillsAmount: number; + upcomingBillsCount: number; +} +export interface DashboardBill { + id: string; + description: string; + category: string; + status: string; + amountDue: number; + createdAt: string; + dueDate: string; +} +export interface DashboardExpense { + id: string; + description: string; + amount: number; + date: string; + category: string; +} diff --git a/apps/frontend/src/api/dashboard/get-recent-expenses.ts b/apps/frontend/src/api/dashboard/get-recent-expenses.ts deleted file mode 100644 index d410664..0000000 --- a/apps/frontend/src/api/dashboard/get-recent-expenses.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { privateAPI } from "@/lib/axios"; - -const api = privateAPI(); - -export interface GetRecentExpensesResponse { - data: ExpenseResponseModel[]; -} - -export type ExpenseResponseModel = { - id: string; - description: string; - category: - | "housing" - | "transportation" - | "food" - | "utilities" - | "clothing" - | "healthcare" - | "insurance" - | "personal" - | "debt" - | "savings" - | "education" - | "entertainment" - | "miscellaneous" - | "travel" - | "pets" - | "gifts" - | "subscriptions" - | "taxes"; - amount: number; - date: string; -}; - -export async function getRecentExpenses( - organizationId: string, - filters?: { from?: Date; to?: Date }, -): Promise { - const params: Record = {}; - if (filters?.from) params.from = filters.from.toISOString(); - if (filters?.to) params.to = filters.to.toISOString(); - - const response = await api.get( - `/organizations/${organizationId}/dashboard/recent-expenses`, - { params }, - ); - - return response.data; -} diff --git a/apps/frontend/src/api/dashboard/get-summary.ts b/apps/frontend/src/api/dashboard/get-summary.ts deleted file mode 100644 index 0fd9eab..0000000 --- a/apps/frontend/src/api/dashboard/get-summary.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { privateAPI } from "@/lib/axios"; - -const api = privateAPI(); - -export interface DashboardSummaryResponse { - monthlyBudget: number | null; - spentThisMonth: number; - remainingBudget: number | null; - spentPercentage: number | null; - upcomingBillsAmount: number; - upcomingBillsCount: number; -} - -export async function getDashboardSummary( - organizationId: string, - filters?: { from?: Date; to?: Date }, -): Promise { - const params: Record = {}; - if (filters?.from) params.from = filters.from.toISOString(); - if (filters?.to) params.to = filters.to.toISOString(); - - const response = await api.get( - `/organizations/${organizationId}/dashboard/summary`, - { params }, - ); - - return response.data; -} diff --git a/apps/frontend/src/api/dashboard/get-upcoming-bills.ts b/apps/frontend/src/api/dashboard/get-upcoming-bills.ts deleted file mode 100644 index 91ab820..0000000 --- a/apps/frontend/src/api/dashboard/get-upcoming-bills.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { privateAPI } from "@/lib/axios"; - -const api = privateAPI(); - -export interface GetUpcomingBillsResponse { - data: UpcomingBillResponseModel[]; -} - -export type UpcomingBillResponseModel = { - id: string; - description: string; - category: - | "housing" - | "transportation" - | "food" - | "utilities" - | "clothing" - | "healthcare" - | "insurance" - | "personal" - | "debt" - | "savings" - | "education" - | "entertainment" - | "miscellaneous" - | "subscriptions" - | "taxes" - | "pets"; - status: "created" | "due" | "paid" | "overdue" | "cancelled" | "upcoming"; - amountDue: number; - createdDate?: string; - createdAt?: string; - dueDate: string; -}; - -export async function getUpcomingBills( - organizationId: string, - filters?: { from?: Date; to?: Date }, -): Promise { - const params: Record = {}; - if (filters?.from) params.from = filters.from.toISOString(); - if (filters?.to) params.to = filters.to.toISOString(); - - const response = await api.get( - `/organizations/${organizationId}/dashboard/upcoming-bills`, - { params }, - ); - - return response.data; -} diff --git a/apps/frontend/src/api/expenses/expenses.service.ts b/apps/frontend/src/api/expenses/expenses.service.ts index d226b69..2bfb83c 100644 --- a/apps/frontend/src/api/expenses/expenses.service.ts +++ b/apps/frontend/src/api/expenses/expenses.service.ts @@ -1,277 +1,121 @@ -import { privateAPI } from "@/lib/axios"; +import { authApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { Expense, ExpenseInput, ExpenseListFilters, ExpensePage } from "./expenses.types"; +import type { BillDocument } from "../bills/bills.types"; -import { normalizeError } from "@/api/shared/normalize-error"; - -import type { - CreateExpenseRequest, - CreateExpenseResponse, - DeleteExpenseDocumentRequest, - DownloadExpenseDocumentRequest, - Expense, - ExpenseDocument, - ExpensesListQuery, - ExpensesListResponse, - UpdateExpenseRequest, - UpdateExpenseResponse, - UploadExpenseDocumentResponse, - UploadExpenseDocumentsRequest, -} from "./expenses.types"; - -const authApi = privateAPI(); - -interface ExpenseAttachmentApiResponse { - id: string; - fileName: string; - contentType: string; - fileCategory: UploadExpenseDocumentResponse["fileCategory"]; - attachmentType: UploadExpenseDocumentResponse["attachmentType"]; -} - -interface ExpenseApiResponse extends Omit { - category: string; - status: string; - attachments?: ExpenseAttachmentApiResponse[]; -} - -interface ExpensesListApiResponse extends Omit { - data: ExpenseApiResponse[]; -} - -interface CreateExpenseApiResponse { - id: string; - description: string; - category: string; - amount: number; - status: string; - occurredAt: string; - createdBy: string; -} - -interface UpdateExpenseApiResponse { - id: string; - description: string; +type ExpenseWire = Omit & { category: string; - amount: number; status: string; - occurredAt: string; - createdBy: string; -} - -function mapStatus(status: string): Expense["status"] { - return status.toLowerCase() as Expense["status"]; -} - -function mapCategory(category: string): Expense["category"] { - return category.toLowerCase() as Expense["category"]; -} - -function mapAttachment(attachment: ExpenseAttachmentApiResponse): ExpenseDocument { - return { - id: attachment.id, - fileName: attachment.fileName, - contentType: attachment.contentType, - fileCategory: attachment.fileCategory, - attachmentType: attachment.attachmentType, - }; -} - -function mapExpense(expense: ExpenseApiResponse): Expense { - return { - ...expense, - category: mapCategory(expense.category), - documents: expense.attachments?.map(mapAttachment) ?? [], - status: mapStatus(expense.status), - }; -} - -function mapCreateExpenseResponse( - expense: CreateExpenseApiResponse -): CreateExpenseResponse { - return { - id: expense.id, - description: expense.description, - category: mapCategory(expense.category), - amount: expense.amount, - status: mapStatus(expense.status), - occurredAt: expense.occurredAt, - createdBy: expense.createdBy, - }; -} - -function mapUpdateExpenseResponse( - expense: UpdateExpenseApiResponse -): UpdateExpenseResponse { - return { - id: expense.id, - description: expense.description, - category: mapCategory(expense.category), - amount: expense.amount, - status: mapStatus(expense.status), - occurredAt: expense.occurredAt, - createdBy: expense.createdBy, - }; -} - -async function uploadDocumentAsync( - organizationId: string, - expenseId: string, - file: File, - fileCategory: UploadExpenseDocumentsRequest["fileCategory"] -): Promise { - const formData = new FormData(); - formData.append("file", file); - formData.append("fileCategory", fileCategory); - - const response = await authApi.post( - `/organizations/${organizationId}/expenses/${expenseId}/documents`, - formData, - { - headers: { - "Content-Type": "multipart/form-data", - }, - } - ); - - return response.data; -} + attachments?: BillDocument[]; +}; +const map = (wire: ExpenseWire): Expense => ({ + ...wire, + category: wire.category.toLowerCase() as Expense["category"], + status: wire.status.toLowerCase() as Expense["status"], + documents: wire.attachments ?? [], +}); export const expensesService = { - async listAsync(query: ExpensesListQuery): Promise { + async listAsync(filters: ExpenseListFilters): Promise { try { - const response = await authApi.get( - `/organizations/${query.organizationId}/expenses`, - { - params: { - from: query.from, - to: query.to, - }, - } - ); - - return { - ...response.data, - data: response.data.data.map(mapExpense), - }; + const response = await authApi.get<{ + data: ExpenseWire[]; + page: number; + pageSize: number; + totalRecords: number; + totalPages: number; + }>(`/organizations/${filters.organizationId}/expenses`, { + params: { + page: filters.page, + pageSize: filters.pageSize, + from: filters.from?.toISOString(), + to: filters.to?.toISOString(), + }, + }); + return { ...response.data, data: response.data.data.map(map) }; } catch (error) { - throw normalizeError(error, "Failed to fetch expenses."); + throw normalizeApiError(error, "api.expenses.load"); } }, - - async getAsync(organizationId: string, expenseId: string): Promise { + async getAsync(organizationId: string, expenseId: string) { try { - const response = await authApi.get( - `/organizations/${organizationId}/expenses/${expenseId}` + return map( + (await authApi.get(`/organizations/${organizationId}/expenses/${expenseId}`)) + .data, ); - - return mapExpense(response.data); } catch (error) { - throw normalizeError(error, "Failed to fetch expense."); + throw normalizeApiError(error, "api.expenses.loadOne"); } }, - - async createAsync( - request: CreateExpenseRequest - ): Promise { + async createAsync(organizationId: string, input: ExpenseInput & { createdBy: string }) { try { - const response = await authApi.post( - `/organizations/${request.organizationId}/expenses`, - { - description: request.description, - category: request.category, - status: request.status, - amount: request.amount, - occurredAt: request.occurredAt, - createdBy: request.createdBy, - } + return map( + (await authApi.post(`/organizations/${organizationId}/expenses`, input)).data, ); - - return mapCreateExpenseResponse(response.data); } catch (error) { - throw normalizeError(error, "Failed to create expense."); + throw normalizeApiError(error, "api.expenses.create"); } }, - - async updateAsync( - request: UpdateExpenseRequest - ): Promise { + async updateAsync(organizationId: string, expenseId: string, input: ExpenseInput) { try { - const response = await authApi.patch( - `/organizations/${request.organizationId}/expenses/${request.id}`, - { - description: request.description, - category: request.category, - status: request.status, - amount: request.amount, - occurredAt: request.occurredAt, - createdBy: request.createdBy, - } + return map( + ( + await authApi.patch( + `/organizations/${organizationId}/expenses/${expenseId}`, + input, + ) + ).data, ); - - return mapUpdateExpenseResponse(response.data); } catch (error) { - throw normalizeError(error, "Failed to update expense."); + throw normalizeApiError(error, "api.expenses.update"); } }, - - async deleteAsync(id: string, organizationId: string): Promise { + async deleteAsync(organizationId: string, expenseId: string) { try { - await authApi.delete(`/organizations/${organizationId}/expenses/${id}`); + await authApi.delete(`/organizations/${organizationId}/expenses/${expenseId}`); } catch (error) { - throw normalizeError(error, "Failed to delete expense."); + throw normalizeApiError(error, "api.expenses.delete"); } }, - - async uploadDocumentsAsync( - payload: UploadExpenseDocumentsRequest - ): Promise { + async uploadDocumentAsync( + organizationId: string, + expenseId: string, + file: File, + fileCategory: string, + ) { try { - return await Promise.all( - payload.files.map((file) => - uploadDocumentAsync( - payload.organizationId, - payload.expenseId, - file, - payload.fileCategory - ) + const form = new FormData(); + form.append("file", file); + form.append("fileCategory", fileCategory); + return ( + await authApi.post( + `/organizations/${organizationId}/expenses/${expenseId}/documents`, + form, ) - ); + ).data; } catch (error) { - throw normalizeError(error, "Failed to upload expense documents."); + throw normalizeApiError(error, "api.expenses.uploadDocument"); } }, - - async downloadDocumentAsync( - payload: DownloadExpenseDocumentRequest - ): Promise { + async getDocumentAsync(organizationId: string, expenseId: string, attachmentId: string) { try { - const response = await authApi.get( - `/organizations/${payload.organizationId}/expenses/${payload.expenseId}/documents/${payload.documentId}`, - { - responseType: "blob", - } - ); - - const blob = new Blob([response.data]); - const url = window.URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - link.download = payload.fileName; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - window.URL.revokeObjectURL(url); + return ( + await authApi.get( + `/organizations/${organizationId}/expenses/${expenseId}/documents/${attachmentId}`, + { responseType: "blob" }, + ) + ).data; } catch (error) { - throw normalizeError(error, "Failed to download expense document."); + throw normalizeApiError(error, "api.expenses.openDocument"); } }, - - async deleteDocumentAsync(payload: DeleteExpenseDocumentRequest): Promise { + async deleteDocumentAsync(organizationId: string, expenseId: string, attachmentId: string) { try { await authApi.delete( - `/organizations/${payload.organizationId}/expenses/${payload.expenseId}/documents/${payload.documentId}` + `/organizations/${organizationId}/expenses/${expenseId}/documents/${attachmentId}`, ); } catch (error) { - throw normalizeError(error, "Failed to delete expense document."); + throw normalizeApiError(error, "api.expenses.removeDocument"); } }, }; diff --git a/apps/frontend/src/api/expenses/expenses.types.ts b/apps/frontend/src/api/expenses/expenses.types.ts index e9dcc80..ff7c971 100644 --- a/apps/frontend/src/api/expenses/expenses.types.ts +++ b/apps/frontend/src/api/expenses/expenses.types.ts @@ -1,133 +1,29 @@ -export type ExpenseCategory = - | "housing" - | "transportation" - | "food" - | "utilities" - | "clothing" - | "healthcare" - | "insurance" - | "personal" - | "debt" - | "savings" - | "education" - | "entertainment" - | "miscellaneous" - | "travel" - | "pets" - | "gifts" - | "subscriptions" - | "taxes"; - +import type { BillCategory, BillDocument, Paged } from "../bills/bills.types"; +export type ExpenseCategory = BillCategory; export type ExpenseStatus = "pending" | "paid" | "cancelled"; - -export type ExpenseFileCategory = "Boleto" | "Receipt" | "Other"; - -export type ExpenseAttachmentType = - | "BillDocument" - | "ExpenseDocument" - | "UserAvatar"; - -export interface ExpenseDocument { - id: string; - fileName: string; - contentType: string; - fileCategory: ExpenseFileCategory; - attachmentType: ExpenseAttachmentType; -} - export interface Expense { id: string; description: string; category: ExpenseCategory; - amount: number; status: ExpenseStatus; + amount: number; occurredAt: string; createdBy: string; - createdAt: string; - updatedAt?: string | null; - deletedAt?: string | null; - documents?: ExpenseDocument[]; + documents: BillDocument[]; } - -export interface ExpensesListQuery { +export interface ExpenseListFilters { organizationId: string; - from?: Date; - to?: Date; -} - -export interface ExpensesListResponse { - data: Expense[]; page: number; pageSize: number; - totalRecords: number; - totalPages: number; -} - -export interface CreateExpenseRequest { - description: string; - category: ExpenseCategory; - amount: number; - status: ExpenseStatus; - occurredAt: string; - createdBy: string; - organizationId: string; -} - -export interface CreateExpenseResponse { - id: string; - description: string; - category: ExpenseCategory; - amount: number; - status: ExpenseStatus; - occurredAt: string; - createdBy: string; -} - -export interface UpdateExpenseRequest { - id: string; - description: string; - category: ExpenseCategory; - amount: number; - status: ExpenseStatus; - occurredAt: string; - createdBy: string; - organizationId: string; + from?: Date; + to?: Date; } - -export interface UpdateExpenseResponse { - id: string; +export type ExpensePage = Paged; +export interface ExpenseInput { description: string; category: ExpenseCategory; amount: number; status: ExpenseStatus; occurredAt: string; - createdBy: string; -} - -export interface UploadExpenseDocumentsRequest { - organizationId: string; - expenseId: string; - files: File[]; - fileCategory: ExpenseFileCategory; -} - -export interface UploadExpenseDocumentResponse { - id: string; - fileName: string; - contentType: string; - fileCategory: ExpenseFileCategory; - attachmentType: ExpenseAttachmentType; -} - -export interface DownloadExpenseDocumentRequest { - organizationId: string; - expenseId: string; - documentId: string; - fileName: string; -} - -export interface DeleteExpenseDocumentRequest { - organizationId: string; - expenseId: string; - documentId: string; + createdBy?: string; } diff --git a/apps/frontend/src/api/expenses/index.ts b/apps/frontend/src/api/expenses/index.ts deleted file mode 100644 index f07d73a..0000000 --- a/apps/frontend/src/api/expenses/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -export { expensesService } from "./expenses.service"; -export type { - CreateExpenseRequest, - CreateExpenseResponse, - DeleteExpenseDocumentRequest, - DownloadExpenseDocumentRequest, - Expense, - ExpenseAttachmentType, - ExpenseCategory, - ExpenseDocument, - ExpenseFileCategory, - ExpensesListQuery, - ExpensesListResponse, - ExpenseStatus, - UploadExpenseDocumentResponse, - UploadExpenseDocumentsRequest, - UpdateExpenseRequest, - UpdateExpenseResponse, -} from "./expenses.types"; diff --git a/apps/frontend-v2/src/api/health/health.service.ts b/apps/frontend/src/api/health/health.service.ts similarity index 65% rename from apps/frontend-v2/src/api/health/health.service.ts rename to apps/frontend/src/api/health/health.service.ts index 4c9ec1d..9ca25b1 100644 --- a/apps/frontend-v2/src/api/health/health.service.ts +++ b/apps/frontend/src/api/health/health.service.ts @@ -5,7 +5,12 @@ export type HealthStatus = { status: "healthy" | "degraded"; message?: string }; export const healthService = { async getAsync(): Promise { - const response = await fetch(env.VITE_HEALTH_URL, { credentials: "include" }); + let response: Response; + try { + response = await fetch(env.VITE_HEALTH_URL, { credentials: "include" }); + } catch { + throw new Error(i18n.t("errors.offline")); + } if (!response.ok) throw new Error(i18n.t("api.healthFailed", { status: response.status })); return { status: "healthy" }; }, diff --git a/apps/frontend/src/api/notifications/notifications.service.ts b/apps/frontend/src/api/notifications/notifications.service.ts new file mode 100644 index 0000000..ca3a467 --- /dev/null +++ b/apps/frontend/src/api/notifications/notifications.service.ts @@ -0,0 +1,68 @@ +import { authApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { NotificationPage, NotificationPreferences } from "./notifications.types"; + +export const notificationsService = { + async listAsync(organizationId: string): Promise { + try { + return ( + await authApi.get(`/organizations/${organizationId}/notifications`, { + params: { page: 1, pageSize: 25, unreadOnly: true }, + }) + ).data; + } catch (error) { + throw normalizeApiError(error, "api.notifications.load"); + } + }, + async unreadCountAsync(organizationId: string): Promise { + try { + return ( + await authApi.get<{ count: number }>( + `/organizations/${organizationId}/notifications/unread-count`, + ) + ).data.count; + } catch (error) { + throw normalizeApiError(error, "api.notifications.load"); + } + }, + async markReadAsync(organizationId: string, notificationId: string): Promise { + try { + await authApi.patch(`/organizations/${organizationId}/notifications/${notificationId}/read`); + } catch (error) { + throw normalizeApiError(error, "api.notifications.markRead"); + } + }, + async markAllReadAsync(organizationId: string): Promise { + try { + await authApi.post(`/organizations/${organizationId}/notifications/read-all`); + } catch (error) { + throw normalizeApiError(error, "api.notifications.markRead"); + } + }, + async getPreferencesAsync(organizationId: string): Promise { + try { + return ( + await authApi.get( + `/organizations/${organizationId}/notification-preferences`, + ) + ).data; + } catch (error) { + throw normalizeApiError(error, "api.notifications.loadPreferences"); + } + }, + async updatePreferencesAsync( + organizationId: string, + enabled: boolean, + ): Promise { + try { + return ( + await authApi.put( + `/organizations/${organizationId}/notification-preferences`, + { emailBillRemindersEnabled: enabled }, + ) + ).data; + } catch (error) { + throw normalizeApiError(error, "api.notifications.savePreferences"); + } + }, +}; diff --git a/apps/frontend-v2/src/api/notifications/notifications.types.ts b/apps/frontend/src/api/notifications/notifications.types.ts similarity index 67% rename from apps/frontend-v2/src/api/notifications/notifications.types.ts rename to apps/frontend/src/api/notifications/notifications.types.ts index f3beedb..c25ed1a 100644 --- a/apps/frontend-v2/src/api/notifications/notifications.types.ts +++ b/apps/frontend/src/api/notifications/notifications.types.ts @@ -1,6 +1,12 @@ import type { Paged } from "../bills/bills.types"; -export type NotificationType = "BillDueSoon" | "BillDueToday" | "BillOverdue" | "MemberJoined" | "MemberRoleChanged" | "MemberRemoved"; +export type NotificationType = + | "BillDueSoon" + | "BillDueToday" + | "BillOverdue" + | "MemberJoined" + | "MemberRoleChanged" + | "MemberRemoved"; export interface NotificationParameters { billId?: string; @@ -24,4 +30,7 @@ export interface AppNotification { } export type NotificationPage = Paged; -export interface NotificationPreferences { emailBillRemindersEnabled: boolean; emailAvailable: boolean } +export interface NotificationPreferences { + emailBillRemindersEnabled: boolean; + emailAvailable: boolean; +} diff --git a/apps/frontend/src/api/organizations/index.ts b/apps/frontend/src/api/organizations/index.ts deleted file mode 100644 index 3616cb1..0000000 --- a/apps/frontend/src/api/organizations/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -export { organizationsService } from "./organizations.service"; -export { inviteOrganizationRoles } from "./organizations.types"; -export type { - CreateInvitationRequest, - CreateInvitationResponse, - InviteOrganizationRole, - CreateOrganizationRequest, - OrganizationBudget, - OrganizationBudgetDetails, - OrganizationDetails, - OrganizationMember, - OrganizationRole, - OrganizationSummary, - RemoveOrganizationMemberRequest, - UpdateMemberRoleRequest, - UpdateOrganizationRequest, - UpsertOrganizationBudgetRequest, -} from "./organizations.types"; diff --git a/apps/frontend/src/api/organizations/organizations.service.ts b/apps/frontend/src/api/organizations/organizations.service.ts index 8dd97bf..2ed9846 100644 --- a/apps/frontend/src/api/organizations/organizations.service.ts +++ b/apps/frontend/src/api/organizations/organizations.service.ts @@ -1,173 +1,99 @@ -import { privateAPI } from "@/lib/axios"; +import { authApi } from "../shared/client"; +import { normalizeApiError } from "../shared/errors"; +import type { OrganizationSummary } from "../auth/auth.types"; +import type { Budget, InvitationResult, OrganizationDetails } from "./organizations.types"; -import { normalizeError } from "@/api/shared/normalize-error"; - -import type { - CreateInvitationRequest, - CreateInvitationResponse, - InviteOrganizationRole, - CreateOrganizationRequest, - OrganizationBudget, - OrganizationDetails, - OrganizationMember, - OrganizationRole, - OrganizationSummary, - RemoveOrganizationMemberRequest, - UpdateMemberRoleRequest, - UpdateOrganizationRequest, - UpsertOrganizationBudgetRequest, -} from "./organizations.types"; - -const authApi = privateAPI(); - -const organizationRoleToApiValue: Record = { - Owner: 1, - Admin: 2, - Member: 3, -}; - -function mapInviteRole(role?: InviteOrganizationRole | null) { - if (!role) { - return undefined; - } - - return organizationRoleToApiValue[role]; -} +export type OrganizationMemberRole = "Owner" | "Admin" | "Member"; +export type EditableOrganizationMemberRole = "Admin" | "Member"; export const organizationsService = { async listAsync(): Promise { try { - const response = await authApi.get("/organizations"); - return response.data; + return (await authApi.get("/organizations")).data; } catch (error) { - throw normalizeError(error, "Failed to fetch organizations."); + throw normalizeApiError(error, "api.organizations.load"); } }, - async getAsync(organizationId: string): Promise { try { - const response = await authApi.get( - `/organizations/${organizationId}` - ); - - return response.data; + return (await authApi.get(`/organizations/${organizationId}`)).data; } catch (error) { - throw normalizeError(error, "Failed to fetch organization details."); + throw normalizeApiError(error, "api.organizations.loadOne"); } }, - - async createAsync( - request: CreateOrganizationRequest - ): Promise { + async createAsync(name: string): Promise { try { - const response = await authApi.post("/organizations", { - name: request.name, - }); - - return response.data; + return (await authApi.post("/organizations", { name })).data; } catch (error) { - throw normalizeError(error, "Failed to create organization."); + throw normalizeApiError(error, "api.organizations.create"); } }, - - async updateAsync( - request: UpdateOrganizationRequest - ): Promise { + async updateAsync(organizationId: string, name: string): Promise { try { - const response = await authApi.patch( - `/organizations/${request.organizationId}`, - { - name: request.name, - } - ); - - return response.data; + return ( + await authApi.patch(`/organizations/${organizationId}`, { name }) + ).data; } catch (error) { - throw normalizeError(error, "Failed to update organization."); + throw normalizeApiError(error, "api.organizations.update"); } }, - - async getBudgetAsync(organizationId: string): Promise { + async getBudgetAsync(organizationId: string): Promise { try { - const response = await authApi.get( - `/organizations/${organizationId}/budget` - ); - - return response.data; + return (await authApi.get(`/organizations/${organizationId}/budget`)).data; } catch (error) { - throw normalizeError(error, "Failed to fetch organization budget."); + const normalized = normalizeApiError(error, "api.organizations.loadBudget"); + if (normalized.status === 404) return null; + throw normalized; } }, - - async upsertBudgetAsync( - request: UpsertOrganizationBudgetRequest - ): Promise { + async upsertBudgetAsync(organizationId: string, amount: number): Promise { try { - const response = await authApi.put( - `/organizations/${request.organizationId}/budget`, - { - amount: request.amount, - } - ); - - return response.data; + return (await authApi.put(`/organizations/${organizationId}/budget`, { amount })) + .data; } catch (error) { - throw normalizeError(error, "Failed to update organization budget."); + throw normalizeApiError(error, "api.organizations.saveBudget"); } }, - async createInviteAsync( - request: CreateInvitationRequest - ): Promise { + organizationId: string, + email: string, + role: EditableOrganizationMemberRole, + ): Promise { try { - const response = await authApi.post( - `/organizations/${request.organizationId}/invite`, - { - email: request.email, - role: mapInviteRole(request.role), - } - ); - - return response.data; + const roleValue = { Admin: 2, Member: 3 }[role]; + return ( + await authApi.post(`/organizations/${organizationId}/invite`, { + email, + role: roleValue, + }) + ).data; } catch (error) { - throw normalizeError(error, "Failed to create organization invite."); + throw normalizeApiError(error, "api.organizations.createInvitation"); } }, - async updateMemberRoleAsync( - request: UpdateMemberRoleRequest - ): Promise { + organizationId: string, + userId: string, + role: EditableOrganizationMemberRole, + ): Promise { try { - const response = await authApi.patch( - `/organizations/${request.organizationId}/members/${request.userId}/role`, - { - role: request.role, - } - ); - - return response.data; + await authApi.patch(`/organizations/${organizationId}/members/${userId}/role`, { role }); } catch (error) { - throw normalizeError(error, "Failed to update organization member role."); + throw normalizeApiError(error, "api.organizations.updateRole"); } }, - - async removeMemberAsync(request: RemoveOrganizationMemberRequest): Promise { + async removeMemberAsync(organizationId: string, userId: string): Promise { try { - await authApi.delete( - `/organizations/${request.organizationId}/members/${request.userId}` - ); + await authApi.delete(`/organizations/${organizationId}/members/${userId}`); } catch (error) { - throw normalizeError(error, "Failed to remove organization member."); + throw normalizeApiError(error, "api.organizations.removeMember"); } }, - async joinAsync(token: string): Promise { try { - await authApi.post("/organizations/join", undefined, { - params: { token }, - }); + await authApi.post(`/organizations/join?token=${encodeURIComponent(token)}`); } catch (error) { - throw normalizeError(error, "Failed to join organization."); + throw normalizeApiError(error, "api.organizations.join"); } }, }; diff --git a/apps/frontend/src/api/organizations/organizations.types.ts b/apps/frontend/src/api/organizations/organizations.types.ts index e1f17de..49a2921 100644 --- a/apps/frontend/src/api/organizations/organizations.types.ts +++ b/apps/frontend/src/api/organizations/organizations.types.ts @@ -1,73 +1,28 @@ -export type OrganizationRole = "Owner" | "Admin" | "Member"; -export const inviteOrganizationRoles = ["Admin", "Member"] as const; -export type InviteOrganizationRole = (typeof inviteOrganizationRoles)[number]; +import type { OrganizationSummary } from "../auth/auth.types"; +export type { OrganizationSummary } from "../auth/auth.types"; -export interface OrganizationSummary { - id: string; - name: string; -} - -export interface OrganizationMember { - id: string; - username: string; - email: string; - role: OrganizationRole; - joinedAt: string; -} - -export interface OrganizationBudgetDetails { - id: string; - amount: number; +export interface OrganizationDetails extends OrganizationSummary { createdAt: string; updatedAt?: string | null; + budget: { id: string; amount: number; createdAt: string; updatedAt?: string | null } | null; + members: Array<{ + id: string; + username: string; + email: string; + role: "Owner" | "Admin" | "Member"; + joinedAt: string; + }>; } -export interface OrganizationBudget extends OrganizationBudgetDetails { - organizationId: string; -} - -export interface OrganizationDetails { - id: string; - name: string; - createdAt: string; - updatedAt?: string | null; - budget: OrganizationBudgetDetails | null; - members: OrganizationMember[]; -} - -export interface CreateOrganizationRequest { - name: string; -} - -export interface UpdateOrganizationRequest { - organizationId: string; - name: string; -} - -export interface UpsertOrganizationBudgetRequest { - organizationId: string; - amount: number; -} - -export interface CreateInvitationRequest { - organizationId: string; - email: string; - role?: InviteOrganizationRole | null; -} - -export interface CreateInvitationResponse { +export interface InvitationResult { id: string; token: string; expiresAt: string; } - -export interface UpdateMemberRoleRequest { - organizationId: string; - userId: string; - role: InviteOrganizationRole; -} - -export interface RemoveOrganizationMemberRequest { - organizationId: string; - userId: string; +export interface Budget { + id: string; + organizationId?: string; + amount: number; + createdAt: string; + updatedAt?: string | null; } diff --git a/apps/frontend-v2/src/api/shared/client.ts b/apps/frontend/src/api/shared/client.ts similarity index 91% rename from apps/frontend-v2/src/api/shared/client.ts rename to apps/frontend/src/api/shared/client.ts index b7c3476..3b8bafc 100644 --- a/apps/frontend-v2/src/api/shared/client.ts +++ b/apps/frontend/src/api/shared/client.ts @@ -12,7 +12,9 @@ export const authApi = axios.create({ baseURL: env.VITE_API_URL, withCredentials let refreshPromise: Promise | null = null; async function refreshAccessToken() { - const response = await publicApi.post<{ accessToken: string; accessTokenExpiresAt: string }>("/identity/refresh"); + const response = await publicApi.post<{ accessToken: string; accessTokenExpiresAt: string }>( + "/identity/refresh", + ); setAccessToken(response.data.accessToken, response.data.accessTokenExpiresAt); return response.data.accessToken; } @@ -32,7 +34,9 @@ authApi.interceptors.response.use( } request._authRetry = true; - refreshPromise ??= refreshAccessToken().finally(() => { refreshPromise = null; }); + refreshPromise ??= refreshAccessToken().finally(() => { + refreshPromise = null; + }); try { const token = await refreshPromise; diff --git a/apps/frontend-v2/src/api/shared/errors.ts b/apps/frontend/src/api/shared/errors.ts similarity index 61% rename from apps/frontend-v2/src/api/shared/errors.ts rename to apps/frontend/src/api/shared/errors.ts index 8dd5beb..49e2497 100644 --- a/apps/frontend-v2/src/api/shared/errors.ts +++ b/apps/frontend/src/api/shared/errors.ts @@ -20,19 +20,29 @@ export function normalizeApiError(error: unknown, fallbackKey: string): ApiError if (error instanceof ApiError) return error; if (isAxiosError(error)) { + if (!error.response && (!navigator.onLine || error.code === "ERR_NETWORK")) { + return new ApiError(i18n.t("errors.offline")); + } + const data = error.response?.data as Record | undefined; const errors = data?.errors; - const message = typeof data?.message === "string" - ? data.message - : typeof data?.error === "string" - ? data.error - : typeof data?.description === "string" - ? data.description - : errors - ? i18n.t("errors.validation") - : i18n.t(fallbackKey); - - return new ApiError(message, error.response?.status, typeof data?.code === "string" ? data.code : undefined, errors); + const message = + typeof data?.message === "string" + ? data.message + : typeof data?.error === "string" + ? data.error + : typeof data?.description === "string" + ? data.description + : errors + ? i18n.t("errors.validation") + : i18n.t(fallbackKey); + + return new ApiError( + message, + error.response?.status, + typeof data?.code === "string" ? data.code : undefined, + errors, + ); } if (axios.isCancel(error)) return new ApiError(i18n.t("errors.requestCanceled")); diff --git a/apps/frontend/src/api/shared/http-error.ts b/apps/frontend/src/api/shared/http-error.ts deleted file mode 100644 index adb440f..0000000 --- a/apps/frontend/src/api/shared/http-error.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface ApiError { - name: "ApiError"; - message: string; - statusCode?: number; - code?: string; - details?: unknown; - cause?: unknown; -} diff --git a/apps/frontend/src/api/shared/normalize-error.ts b/apps/frontend/src/api/shared/normalize-error.ts deleted file mode 100644 index d637b7a..0000000 --- a/apps/frontend/src/api/shared/normalize-error.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { isAxiosError } from "axios"; - -import type { ApiError } from "./http-error"; - -function isObject(value: unknown): value is Record { - return typeof value === "object" && value !== null; -} - -function toNonEmptyString(value: unknown): string | null { - if (typeof value !== "string") { - return null; - } - - const normalized = value.trim(); - return normalized.length > 0 ? normalized : null; -} - -function extractValidationErrorMessage(errors: unknown): string | null { - if (Array.isArray(errors)) { - for (const item of errors) { - const message = toNonEmptyString(item); - if (message) { - return message; - } - } - - return null; - } - - if (!isObject(errors)) { - return null; - } - - for (const value of Object.values(errors)) { - const directMessage = toNonEmptyString(value); - if (directMessage) { - return directMessage; - } - - if (Array.isArray(value)) { - for (const item of value) { - const arrayMessage = toNonEmptyString(item); - if (arrayMessage) { - return arrayMessage; - } - } - } - } - - return null; -} - -function extractResponseMessage(responseData: unknown): string | null { - if (!isObject(responseData)) { - return null; - } - - const validationMessage = extractValidationErrorMessage(responseData.errors); - if (validationMessage) { - return validationMessage; - } - - const message = toNonEmptyString(responseData.message); - if (message) { - return message; - } - - const detail = toNonEmptyString(responseData.detail); - if (detail) { - return detail; - } - - const title = toNonEmptyString(responseData.title); - if (title) { - return title; - } - - return null; -} - -export function extractApiErrorMessage( - error: unknown, - fallbackMessage: string -): string { - if (isAxiosError(error)) { - const responseMessage = extractResponseMessage(error.response?.data); - if (responseMessage) { - return responseMessage; - } - - const axiosMessage = toNonEmptyString(error.message); - if (axiosMessage) { - return axiosMessage; - } - - return fallbackMessage; - } - - if (error instanceof Error) { - const nativeMessage = toNonEmptyString(error.message); - if (nativeMessage) { - return nativeMessage; - } - - return fallbackMessage; - } - - const stringMessage = toNonEmptyString(error); - if (stringMessage) { - return stringMessage; - } - - return fallbackMessage; -} - -export function normalizeError( - error: unknown, - fallbackMessage: string -): ApiError { - if (isAxiosError(error)) { - const statusCode = error.response?.status; - const responseData = isObject(error.response?.data) - ? error.response.data - : undefined; - const responseCode = toNonEmptyString(responseData?.code); - - return { - name: "ApiError", - message: extractApiErrorMessage(error, fallbackMessage), - statusCode, - code: responseCode ?? error.code, - details: responseData?.details ?? error.response?.data, - cause: error, - }; - } - - if (error instanceof Error) { - return { - name: "ApiError", - message: error.message || fallbackMessage, - cause: error, - }; - } - - return { - name: "ApiError", - message: fallbackMessage, - cause: error, - }; -} diff --git a/apps/frontend-v2/src/api/shared/session-events.ts b/apps/frontend/src/api/shared/session-events.ts similarity index 100% rename from apps/frontend-v2/src/api/shared/session-events.ts rename to apps/frontend/src/api/shared/session-events.ts diff --git a/apps/frontend/src/app.tsx b/apps/frontend/src/app.tsx index 6207daf..8179e53 100644 --- a/apps/frontend/src/app.tsx +++ b/apps/frontend/src/app.tsx @@ -1,19 +1,48 @@ -import { QueryClientProvider } from "@tanstack/react-query"; -import { RouterProvider } from "react-router-dom"; +import { Route, Routes } from "react-router-dom"; -import { Toaster } from "@/components/ui/sonner"; -import { AuthProvider } from "@/auth/auth-provider"; -import { queryClient } from "@/lib/react-query"; - -import { router } from "./routes"; +import { AppShell } from "@/components/layout/app-shell"; +import { ProtectedRoute } from "@/components/routing/protected-route"; +import { AccountPage } from "@/pages/account/account-page"; +import { MorePage } from "@/pages/account/more-page"; +import { AuthPage } from "@/pages/auth/auth-page"; +import { BillDetailsPage } from "@/pages/bills/bill-details-page"; +import { BillsPage } from "@/pages/bills/bills-page"; +import { DashboardPage } from "@/pages/dashboard/dashboard-page"; +import { ExpenseDetailsPage } from "@/pages/expenses/expense-details-page"; +import { ExpensesPage } from "@/pages/expenses/expenses-page"; +import { HomePage } from "@/pages/home/home-page"; +import { NotFoundPage } from "@/pages/not-found/not-found-page"; +import { CreateOrganizationPage } from "@/pages/organizations/create-organization-page"; +import { JoinPage } from "@/pages/organizations/join-organization-page"; +import { MembersPage } from "@/pages/organizations/members-page"; +import { OrganizationPage } from "@/pages/organizations/organization-page"; export function App() { return ( - - - - - - + + } /> + } /> + } /> + } /> + } /> + + +
+ } + > + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + ); } diff --git a/apps/frontend/src/assets/react.svg b/apps/frontend/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/apps/frontend/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/frontend/src/auth/auth-provider.tsx b/apps/frontend/src/auth/auth-provider.tsx index 87b64c8..fefb77d 100644 --- a/apps/frontend/src/auth/auth-provider.tsx +++ b/apps/frontend/src/auth/auth-provider.tsx @@ -1,297 +1,135 @@ -import { useCallback, useEffect, useMemo, useRef } from "react"; +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, + type ReactNode, +} from "react"; import { useQueryClient } from "@tanstack/react-query"; -import { authService } from "@/api/auth"; -import { useAuthStore } from "@/auth/auth-store"; -import type { Organization } from "@/auth/types"; -import { fetchMeAsync, useMeQuery } from "@/hooks/queries/use-me-query"; -import { setOnRefreshFailure } from "@/lib/axios"; -import { clearAccessToken, setAccessToken } from "@/lib/auth-token"; -import { logger } from "@/lib/logger"; -import { queryKeys } from "@/lib/query-keys"; - -export type { Organization, User } from "@/auth/types"; - -interface AuthProviderProps { - children: React.ReactNode; -} - -export interface RegisterBody { - firstName: string; - lastName: string; - email: string; - password: string; -} - -interface LoginCredentialsBody { - email: string; - password: string; -} - -interface ClearAuthStateOptions { - resetInitialization?: boolean; -} - -function syncAccessToken( - token: string | null, - tokenExpiresAt?: string | null -): void { - if (token) { - setAccessToken(token, tokenExpiresAt); - return; - } - - clearAccessToken(); -} - -export function useAuthInitialization(): boolean { - return useAuthStore((state) => state.isInitialized); -} - -export function useAuthToken(): string | null { - return useAuthStore((state) => state.token); -} - -export function useIsAuthenticated(): boolean { - return useAuthStore((state) => Boolean(state.token)); -} - -export function useSelectedOrganizationId(): string | null { - return useAuthStore((state) => state.selectedOrganizationId); -} - -export function useSetSelectedOrganizationId(): ( - selectedOrganizationId: string | null -) => void { - return useAuthStore((state) => state.setSelectedOrganizationId); -} - -export function useCurrentUser() { - const isInitialized = useAuthInitialization(); - const isAuthenticated = useIsAuthenticated(); - - return useMeQuery(isInitialized && isAuthenticated); -} - -export function useSelectedOrganization(): Organization | null { - const selectedOrganizationId = useSelectedOrganizationId(); - const currentUserQuery = useCurrentUser(); - const organizations = currentUserQuery.data?.organizations ?? []; - - return useMemo(() => { - if (organizations.length === 0) { - return null; - } - - if (!selectedOrganizationId) { - return organizations[0]; - } - - return ( - organizations.find((organization) => organization.id === selectedOrganizationId) ?? - organizations[0] - ); - }, [organizations, selectedOrganizationId]); -} - -export function useGetMeAction(): () => Promise { +import { authService } from "../api/auth/auth.service"; +import type { AuthCredentials, RegisterCredentials, User } from "../api/auth/auth.types"; +import { setSessionExpiredListener } from "../api/shared/session-events"; +import { clearAccessToken, setAccessToken } from "../lib/auth-token"; +import { queryKeys } from "../lib/query-keys"; +import { useOrganizationStore } from "./auth-store"; + +type AuthStatus = "initializing" | "authenticated" | "unauthenticated"; +interface AuthContextValue { + status: AuthStatus; + user: User | null; + signIn: (credentials: AuthCredentials | RegisterCredentials) => Promise; + refreshUser: () => Promise; + setAvatarPreview: (file: File) => void; + clearAvatarPreview: () => void; + signOut: (allDevices?: boolean) => Promise; +} +const AuthContext = createContext(null); + +function selectInitialOrganization(user: User) { + const current = useOrganizationStore.getState().selectedOrganizationId; + const valid = user.organizations.some((organization) => organization.id === current); + useOrganizationStore + .getState() + .setSelectedOrganizationId(valid ? current : (user.organizations[0]?.id ?? null)); +} + +export function AuthProvider({ children }: { children: ReactNode }) { const queryClient = useQueryClient(); - const token = useAuthToken(); - - return useCallback(async (): Promise => { - if (!token) { - return; - } - - await queryClient.fetchQuery({ - queryKey: queryKeys.auth.me(), - queryFn: fetchMeAsync, - }); - }, [queryClient, token]); -} + const [status, setStatus] = useState("initializing"); + const [user, setUser] = useState(null); + const avatarPreviewRef = useRef(null); + + const clearAvatarPreview = useCallback(() => { + if (avatarPreviewRef.current) URL.revokeObjectURL(avatarPreviewRef.current); + avatarPreviewRef.current = null; + setUser((current) => (current ? { ...current, avatarUrl: null } : current)); + }, []); + + const setAvatarPreview = useCallback((file: File) => { + if (avatarPreviewRef.current) URL.revokeObjectURL(avatarPreviewRef.current); + const nextPreview = URL.createObjectURL(file); + avatarPreviewRef.current = nextPreview; + setUser((current) => (current ? { ...current, avatarUrl: nextPreview } : current)); + }, []); + + const refreshUser = useCallback(async () => { + const next = await authService.getMeAsync(); + const withPreview = { ...next, avatarUrl: avatarPreviewRef.current }; + setUser(withPreview); + selectInitialOrganization(withPreview); + setStatus("authenticated"); + queryClient.setQueryData(queryKeys.auth.me(), withPreview); + return withPreview; + }, [queryClient]); -export function useRegisterAction(): ( - body: RegisterBody -) => Promise { - const queryClient = useQueryClient(); - const setSession = useAuthStore((state) => state.setSession); - - return useCallback( - async ({ - firstName, - lastName, - email, - password, - }: RegisterBody): Promise => { - try { - const response = await authService.signUpAsync({ - firstName, - lastName, - email, - password, - }); - - const { accessToken, accessTokenExpiresAt } = response; - setSession(accessToken, accessTokenExpiresAt); - syncAccessToken(accessToken, accessTokenExpiresAt); - await queryClient.fetchQuery({ - queryKey: queryKeys.auth.me(), - queryFn: fetchMeAsync, - }); - return true; - } catch (error) { - logger.error("Registration failed", error); - return false; - } - }, - [queryClient, setSession] + useEffect(() => { + const expire = () => { + clearAccessToken(); + clearAvatarPreview(); + setUser(null); + setStatus("unauthenticated"); + void queryClient.clear(); + }; + setSessionExpiredListener(expire); + void authService + .refreshAsync() + .then((session) => { + setAccessToken(session.accessToken, session.accessTokenExpiresAt); + return refreshUser(); + }) + .catch(expire); + return () => setSessionExpiredListener(null); + }, [clearAvatarPreview, queryClient, refreshUser]); + + const value = useMemo( + () => ({ + status, + user, + signIn: async (credentials) => { + const session = + "firstName" in credentials + ? await authService.registerAsync(credentials) + : await authService.loginAsync(credentials); + setAccessToken(session.accessToken, session.accessTokenExpiresAt); + return refreshUser(); + }, + refreshUser, + setAvatarPreview, + clearAvatarPreview, + signOut: async (allDevices = false) => { + try { + await authService[allDevices ? "logoutAllAsync" : "logoutAsync"](); + } finally { + clearAccessToken(); + clearAvatarPreview(); + setUser(null); + setStatus("unauthenticated"); + useOrganizationStore.getState().setSelectedOrganizationId(null); + await queryClient.clear(); + } + }, + }), + [clearAvatarPreview, queryClient, refreshUser, setAvatarPreview, status, user], ); -} - -export function useLoginAction(): ( - credentials: LoginCredentialsBody -) => Promise { - const queryClient = useQueryClient(); - const setSession = useAuthStore((state) => state.setSession); - return useCallback( - async ({ email, password }: LoginCredentialsBody): Promise => { - try { - const response = await authService.signInAsync({ - email, - password, - }); - - const { accessToken, accessTokenExpiresAt } = response; - setSession(accessToken, accessTokenExpiresAt); - syncAccessToken(accessToken, accessTokenExpiresAt); - await queryClient.fetchQuery({ - queryKey: queryKeys.auth.me(), - queryFn: fetchMeAsync, - }); - return true; - } catch (error) { - logger.error("Login failed", error); - return false; - } + useEffect( + () => () => { + if (avatarPreviewRef.current) URL.revokeObjectURL(avatarPreviewRef.current); }, - [queryClient, setSession] + [], ); -} - -export function useLogoutAction(): () => Promise { - const queryClient = useQueryClient(); - const clearSession = useAuthStore((state) => state.clearSession); - const setInitialized = useAuthStore((state) => state.setInitialized); - const setSelectedOrganizationId = useSetSelectedOrganizationId(); - return useCallback(async (): Promise => { - try { - await authService.logoutAsync(); - } catch (error) { - logger.error("Logout API call failed", error); - } finally { - clearSession(); - setSelectedOrganizationId(null); - setInitialized(true); - syncAccessToken(null); - queryClient.clear(); - } - }, [clearSession, queryClient, setInitialized, setSelectedOrganizationId]); + return {children}; } -export function AuthProvider({ children }: AuthProviderProps) { - const queryClient = useQueryClient(); - const initializationRef = useRef(false); - const isInitialized = useAuthInitialization(); - const isAuthenticated = useIsAuthenticated(); - const selectedOrganizationId = useSelectedOrganizationId(); - const setSession = useAuthStore((state) => state.setSession); - const clearSession = useAuthStore((state) => state.clearSession); - const setInitialized = useAuthStore((state) => state.setInitialized); - const setSelectedOrganizationId = useSetSelectedOrganizationId(); - const resetAuthClientState = useAuthStore((state) => state.resetAuthClientState); - const meQuery = useMeQuery(isInitialized && isAuthenticated); - const user = meQuery.data ?? null; - - const clearAuthState = useCallback( - (options: ClearAuthStateOptions = {}) => { - if (options.resetInitialization) { - resetAuthClientState(); - } else { - clearSession(); - setSelectedOrganizationId(null); - setInitialized(true); - } - - syncAccessToken(null); - queryClient.clear(); - }, - [ - clearSession, - queryClient, - resetAuthClientState, - setInitialized, - setSelectedOrganizationId, - ] - ); - - useEffect(() => { - setOnRefreshFailure(() => { - clearAuthState(); - window.location.href = "/auth/sign-in"; - }); - }, [clearAuthState]); - - useEffect(() => { - if (!user) { - setSelectedOrganizationId(null); - return; - } - - if (user.organizations.length === 0) { - setSelectedOrganizationId(null); - return; - } - - if ( - selectedOrganizationId && - user.organizations.some((organization) => organization.id === selectedOrganizationId) - ) { - return; - } - - setSelectedOrganizationId(user.organizations[0].id); - }, [selectedOrganizationId, setSelectedOrganizationId, user]); - - useEffect(() => { - if (initializationRef.current) { - return; - } - - initializationRef.current = true; - - const initializeAuth = async () => { - localStorage.removeItem("_authAccessToken"); - localStorage.removeItem("_authTokenType"); - localStorage.removeItem("_authExpiresIn"); - localStorage.removeItem("_authRefreshToken"); - - try { - const response = await authService.refreshAsync(); - const { accessToken, accessTokenExpiresAt } = response; - setSession(accessToken, accessTokenExpiresAt); - syncAccessToken(accessToken, accessTokenExpiresAt); - } catch { - logger.debug("No existing session to restore"); - clearAuthState({ resetInitialization: true }); - } finally { - setInitialized(true); - } - }; - - initializeAuth(); - }, [clearAuthState, setInitialized, setSession]); - - return <>{children}; +// This hook intentionally shares the provider's context for the app shell and routes. +// eslint-disable-next-line react-refresh/only-export-components +export function useAuth() { + const value = useContext(AuthContext); + if (!value) throw new Error("useAuth must be used inside AuthProvider"); + return value; } diff --git a/apps/frontend/src/auth/auth-store.ts b/apps/frontend/src/auth/auth-store.ts index 0b49471..35a5ab1 100644 --- a/apps/frontend/src/auth/auth-store.ts +++ b/apps/frontend/src/auth/auth-store.ts @@ -1,62 +1,20 @@ import { create } from "zustand"; -import { createJSONStorage, persist } from "zustand/middleware"; +import { persist } from "zustand/middleware"; -export interface AuthClientState { - token: string | null; - tokenExpiresAt: string | null; - isInitialized: boolean; +interface OrganizationState { selectedOrganizationId: string | null; + setSelectedOrganizationId: (id: string | null) => void; } -export interface AuthClientActions { - setSession: (token: string | null, tokenExpiresAt?: string | null) => void; - clearSession: () => void; - setInitialized: (isInitialized: boolean) => void; - setSelectedOrganizationId: (selectedOrganizationId: string | null) => void; - resetAuthClientState: () => void; -} - -type AuthStore = AuthClientState & AuthClientActions; - -export const useAuthStore = create()( +export const useOrganizationStore = create()( persist( (set) => ({ - token: null, - tokenExpiresAt: null, - isInitialized: false, selectedOrganizationId: null, - setSession: (token, tokenExpiresAt) => - set({ - token, - tokenExpiresAt: tokenExpiresAt ?? null, - }), - clearSession: () => - set({ - token: null, - tokenExpiresAt: null, - }), - setInitialized: (isInitialized) => - set({ - isInitialized, - }), - setSelectedOrganizationId: (selectedOrganizationId) => - set({ - selectedOrganizationId, - }), - resetAuthClientState: () => - set({ - token: null, - tokenExpiresAt: null, - isInitialized: false, - selectedOrganizationId: null, - }), + setSelectedOrganizationId: (selectedOrganizationId) => set({ selectedOrganizationId }), }), { - name: "bitfinance-auth", - storage: createJSONStorage(() => localStorage), - partialize: (state) => ({ - selectedOrganizationId: state.selectedOrganizationId, - }), - } - ) + name: "bitfinance-preferences", + partialize: (state) => ({ selectedOrganizationId: state.selectedOrganizationId }), + }, + ), ); diff --git a/apps/frontend/src/auth/get-safe-return-url.ts b/apps/frontend/src/auth/get-safe-return-url.ts deleted file mode 100644 index eea696d..0000000 --- a/apps/frontend/src/auth/get-safe-return-url.ts +++ /dev/null @@ -1,13 +0,0 @@ -const DEFAULT_RETURN_URL = "/dashboard"; - -export function getSafeReturnUrl(returnUrl: string | null | undefined): string { - if (!returnUrl) { - return DEFAULT_RETURN_URL; - } - - if (!returnUrl.startsWith("/") || returnUrl.startsWith("//")) { - return DEFAULT_RETURN_URL; - } - - return returnUrl; -} diff --git a/apps/frontend/src/auth/safe-return-to.ts b/apps/frontend/src/auth/safe-return-to.ts new file mode 100644 index 0000000..6d83609 --- /dev/null +++ b/apps/frontend/src/auth/safe-return-to.ts @@ -0,0 +1,3 @@ +export function safeReturnTo(value: string | null) { + return value?.startsWith("/") && !value.startsWith("//") ? value : "/dashboard"; +} diff --git a/apps/frontend/src/auth/types.ts b/apps/frontend/src/auth/types.ts deleted file mode 100644 index e080352..0000000 --- a/apps/frontend/src/auth/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type Organization = { - id: string; - name: string; -}; - -export type User = { - id: string; - username: string; - fullName: string; - email: string; - avatarUrl?: string | null; - organizations: Organization[]; -}; diff --git a/apps/frontend/src/components/app-sidebar.tsx b/apps/frontend/src/components/app-sidebar.tsx deleted file mode 100644 index bfd4696..0000000 --- a/apps/frontend/src/components/app-sidebar.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import * as React from "react"; -import { Link, useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; - -import { useCurrentUser } from "@/auth/auth-provider"; -import { - desktopSidebarNavigation, - isAppNavItemActive, -} from "@/layouts/app-navigation"; - -import { NavUser } from "@/components/nav-user"; -import { OrganizationSwitcher } from "@/components/organization-switcher"; -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarGroup, - SidebarGroupContent, - SidebarGroupLabel, - SidebarHeader, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - SidebarRail, -} from "@/components/ui/sidebar"; - -import logoImg from "/assets/app-icon.png"; - -export function AppSidebar({ ...props }: React.ComponentProps) { - const { t } = useTranslation(); - const currentUserQuery = useCurrentUser(); - const user = currentUserQuery.data ?? null; - const location = useLocation(); - - const groupedItems = desktopSidebarNavigation.reduce< - Record - >((acc, item) => { - if (!acc[item.section]) { - acc[item.section] = []; - } - acc[item.section].push(item); - return acc; - }, {}); - - return ( - - -
- - BitFinance logo - -
- -
-
-
- - {Object.entries(groupedItems).map(([section, items]) => ( - - - {t(`sidebar.sections.${section}`)} - - - - {items.map((item) => ( - - - - {t(`sidebar.${item.id}`)} - - - - ))} - - - - ))} - - - - - -
- ); -} diff --git a/apps/frontend/src/components/feedback/empty-state.tsx b/apps/frontend/src/components/feedback/empty-state.tsx new file mode 100644 index 0000000..264ddd9 --- /dev/null +++ b/apps/frontend/src/components/feedback/empty-state.tsx @@ -0,0 +1,25 @@ +import { FileText } from "lucide-react"; +import { ReactNode } from "react"; + +export function EmptyState({ + icon: Icon = FileText, + title, + description, + action, +}: { + icon?: typeof FileText; + title: string; + description: string; + action?: ReactNode; +}) { + return ( +
+ + + +

{title}

+

{description}

+ {action} +
+ ); +} diff --git a/apps/frontend/src/components/feedback/error-state.tsx b/apps/frontend/src/components/feedback/error-state.tsx new file mode 100644 index 0000000..e3a5e0b --- /dev/null +++ b/apps/frontend/src/components/feedback/error-state.tsx @@ -0,0 +1,21 @@ +import { RotateCcw } from "lucide-react"; +import { useTranslation } from "react-i18next"; + +import { EmptyState } from "@/components/feedback/empty-state"; +import { Button } from "@/components/ui/button"; + +export function ErrorState({ message, onRetry }: { message: string; onRetry: () => void }) { + const { t } = useTranslation(); + return ( + + {t("errors.tryAgain")} + + } + /> + ); +} diff --git a/apps/frontend/src/components/feedback/loading-state.tsx b/apps/frontend/src/components/feedback/loading-state.tsx new file mode 100644 index 0000000..476e6ee --- /dev/null +++ b/apps/frontend/src/components/feedback/loading-state.tsx @@ -0,0 +1,11 @@ +import { useTranslation } from "react-i18next"; + +export function LoadingState({ label }: { label?: string }) { + const { t } = useTranslation(); + return ( +
+
+ ); +} diff --git a/apps/frontend/src/components/layout/app-shell.tsx b/apps/frontend/src/components/layout/app-shell.tsx new file mode 100644 index 0000000..8ec95a3 --- /dev/null +++ b/apps/frontend/src/components/layout/app-shell.tsx @@ -0,0 +1,216 @@ +import { + Building2, + CircleDollarSign, + CreditCard, + LayoutDashboard, + LogOut, + Moon, + MoreHorizontal, + ReceiptText, + Settings2, + SunMedium, + UsersRound, +} from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { Link, NavLink, Outlet, useLocation, useNavigate } from "react-router-dom"; +import { useAuth } from "@/auth/auth-provider"; +import { useOrganizationStore } from "@/auth/auth-store"; +import { NotificationBell } from "@/components/navigation/notification-bell"; +import { Avatar } from "@/components/ui/avatar"; +import { BrandMark } from "@/components/ui/brand-mark"; +import { IconButton } from "@/components/ui/icon-button"; +import { Select } from "@/components/ui/select"; +import { useOrganizationsQuery } from "@/hooks/queries/use-organization-queries"; +import { useTheme } from "@/hooks/use-theme"; + +const navItems = [ + { to: "/dashboard", labelKey: "nav.overview", icon: LayoutDashboard, end: true }, + { to: "/dashboard/bills", labelKey: "nav.bills", icon: ReceiptText }, + { to: "/dashboard/expenses", labelKey: "nav.expenses", icon: CreditCard }, +]; + +function OrganizationSwitcher() { + const { user } = useAuth(); + const organizations = useOrganizationsQuery(Boolean(user)); + const selectedId = useOrganizationStore((state) => state.selectedOrganizationId); + const setSelectedId = useOrganizationStore((state) => state.setSelectedOrganizationId); + const items = organizations.data ?? user?.organizations ?? []; + const { t } = useTranslation(); + return ( +
+ + setFrom(event.target.value)} + required + /> + + +
+ {from > to && ( +

+ {t("common.endDateError")} +

+ )} +
+ + +
+ + )} + + ); +} diff --git a/apps/frontend/src/components/organization-switcher.tsx b/apps/frontend/src/components/organization-switcher.tsx deleted file mode 100644 index aca1140..0000000 --- a/apps/frontend/src/components/organization-switcher.tsx +++ /dev/null @@ -1,294 +0,0 @@ -import { Check, ChevronsUpDown, Plus, Settings2, X } from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; - -import type { Organization } from "@/auth/types"; -import { - useSelectedOrganization, - useSetSelectedOrganizationId, -} from "@/auth/auth-provider"; -import { Avatar, AvatarFallback } from "@/components/ui/avatar"; -import { Button } from "@/components/ui/button"; -import { - Drawer, - DrawerClose, - DrawerContent, - DrawerTitle, - DrawerTrigger, -} from "@/components/ui/drawer"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from "@/components/ui/sidebar"; -import { useIsMobile } from "@/hooks/use-mobile"; -import { cn } from "@/lib/utils"; - -interface OrganizationSwitcherProps { - organizations: Organization[]; - variant?: "sidebar" | "topbar"; -} - -function getOrganizationInitials(name?: string): string { - const normalizedName = name?.trim().replace(/\s+/g, " ") ?? ""; - if (!normalizedName) { - return "OR"; - } - - const parts = normalizedName.split(" "); - - if (parts.length === 1) { - const firstTwoLetters = Array.from(parts[0]).slice(0, 2).join("").toUpperCase(); - return firstTwoLetters || "OR"; - } - - const initials = `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase(); - return initials || "OR"; -} - -function OrganizationSwitcherActions({ - manageLabel, - createLabel, -}: { - manageLabel: string; - createLabel: string; -}) { - return ( - <> - - - - {manageLabel} - - - - - - {createLabel} - - - - ); -} - -export function OrganizationSwitcher({ - organizations, - variant = "sidebar", -}: OrganizationSwitcherProps) { - const { t } = useTranslation(); - const selectedOrganization = useSelectedOrganization(); - const setSelectedOrganizationId = useSetSelectedOrganizationId(); - const isMobile = useIsMobile(); - - if (variant === "topbar") { - if (isMobile) { - return ( - - - - - -
-
- - {t("sidebar.select")} - - - - -
- -
- {organizations.length > 0 ? ( -
- {organizations.map((organization) => ( - - - - ))} - -
-
- - - - - - -
-
- ) : ( -
-

- {t("organization.switcher.empty")} -

- - - -
- )} -
-
- - - ); - } - - return ( - - - - - - {organizations.length > 0 ? ( - <> - {organizations.map((organization) => ( - setSelectedOrganizationId(organization.id)} - > - {organization.name} - {organization.id === selectedOrganization?.id ? ( - - ) : null} - - ))} - - - - ) : ( - <> - - - - {t("organization.switcher.create")} - - - - )} - - - ); - } - - return ( - - - - - - - {selectedOrganization?.name ?? t("sidebar.select")} - - - - - - {organizations.length > 0 ? ( - <> - {organizations.map((organization) => ( - setSelectedOrganizationId(organization.id)} - > - {organization.name} - {organization.id === selectedOrganization?.id ? ( - - ) : null} - - ))} - - - - ) : ( - - - - {t("organization.switcher.create")} - - - )} - - - - - ); -} diff --git a/apps/frontend/src/components/page-shell.tsx b/apps/frontend/src/components/page-shell.tsx deleted file mode 100644 index 7378d75..0000000 --- a/apps/frontend/src/components/page-shell.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { type ReactNode } from "react"; - -import { cn } from "@/lib/utils"; - -interface PageContainerProps { - children: ReactNode; - className?: string; -} - -export function PageContainer({ children, className }: PageContainerProps) { - return ( -
- {children} -
- ); -} - -export interface PageHeaderProps { - title: ReactNode; - description?: ReactNode; - actions?: ReactNode; - className?: string; -} - -export function PageHeader({ - title, - description, - actions, - className, -}: PageHeaderProps) { - return ( -
-
-

{title}

- {description ? ( -

{description}

- ) : null} -
- {actions ?
{actions}
: null} -
- ); -} diff --git a/apps/frontend/src/components/protected-route.tsx b/apps/frontend/src/components/protected-route.tsx deleted file mode 100644 index 627f7a1..0000000 --- a/apps/frontend/src/components/protected-route.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { - useAuthInitialization, - useCurrentUser, - useIsAuthenticated, -} from "@/auth/auth-provider"; -import { Navigate, useLocation } from "react-router-dom"; - -interface ProtectedRouteProps { - children: React.ReactNode; -} - -export function ProtectedRoute({ children }: ProtectedRouteProps) { - const isInitialized = useAuthInitialization(); - const isAuthenticated = useIsAuthenticated(); - const currentUserQuery = useCurrentUser(); - const location = useLocation(); - const returnUrl = `${location.pathname}${location.search}${location.hash}`; - const user = currentUserQuery.data ?? null; - const hasOrganizations = (user?.organizations.length ?? 0) > 0; - const isCreateOrganizationRoute = location.pathname === "/account/create-organization"; - const isLoading = - !isInitialized || (isAuthenticated && currentUserQuery.isPending); - - if (isLoading) { - return ( -
-
-
- ); - } - - if (!isAuthenticated) { - return ( - - ); - } - - if (!isCreateOrganizationRoute && !hasOrganizations) { - return ; - } - - return <>{children}; -} diff --git a/apps/frontend/src/components/routing/protected-route.tsx b/apps/frontend/src/components/routing/protected-route.tsx new file mode 100644 index 0000000..c452fb2 --- /dev/null +++ b/apps/frontend/src/components/routing/protected-route.tsx @@ -0,0 +1,20 @@ +import type { ReactNode } from "react"; +import { useTranslation } from "react-i18next"; +import { Navigate, useLocation } from "react-router-dom"; + +import { useAuth } from "@/auth/auth-provider"; +import { LoadingState } from "@/components/feedback/loading-state"; + +export function ProtectedRoute({ children }: { children: ReactNode }) { + const { t } = useTranslation(); + const auth = useAuth(); + const location = useLocation(); + if (auth.status === "initializing") return ; + if (auth.status !== "authenticated") { + const returnTo = `${location.pathname}${location.search}`; + return ; + } + if (!auth.user?.organizations.length && location.pathname !== "/account/create-organization") + return ; + return <>{children}; +} diff --git a/apps/frontend/src/components/search-form.tsx b/apps/frontend/src/components/search-form.tsx deleted file mode 100644 index bda415b..0000000 --- a/apps/frontend/src/components/search-form.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Search } from "lucide-react" - -import { Label } from "@/components/ui/label" -import { - SidebarGroup, - SidebarGroupContent, - SidebarInput, -} from "@/components/ui/sidebar" - -export function SearchForm({ ...props }: React.ComponentProps<"form">) { - return ( -
- - - - - - - -
- ) -} diff --git a/apps/frontend/src/components/ui/adaptive-modal.tsx b/apps/frontend/src/components/ui/adaptive-modal.tsx deleted file mode 100644 index 9ae6519..0000000 --- a/apps/frontend/src/components/ui/adaptive-modal.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { type ReactNode } from "react"; - -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { - Drawer, - DrawerClose, - DrawerContent, - DrawerDescription, - DrawerFooter, - DrawerHeader, - DrawerTitle, - DrawerTrigger, -} from "@/components/ui/drawer"; -import { useIsMobile } from "@/hooks/use-mobile"; -import { cn } from "@/lib/utils"; - -interface OpenStateProps { - open?: boolean; - defaultOpen?: boolean; - onOpenChange?: (open: boolean) => void; -} - -export interface AdaptiveModalProps extends OpenStateProps { - trigger?: ReactNode; - title?: ReactNode; - description?: ReactNode; - children: ReactNode; - contentClassName?: string; - headerClassName?: string; - bodyClassName?: string; - footer?: ReactNode; - footerClassName?: string; -} - -export function AdaptiveModal({ - open, - defaultOpen, - onOpenChange, - trigger, - title, - description, - children, - contentClassName, - headerClassName, - bodyClassName, - footer, - footerClassName, -}: AdaptiveModalProps) { - const isMobile = useIsMobile(); - - const shouldRenderHeader = Boolean(title || description); - - if (isMobile) { - return ( - - {trigger ? {trigger} : null} - -
- {shouldRenderHeader ? ( - - {title ? {title} : null} - {description ? ( - {description} - ) : null} - - ) : null} - -
- {children} -
- - {footer ? ( - {footer} - ) : null} -
-
-
- ); - } - - return ( - - {trigger ? {trigger} : null} - - {shouldRenderHeader ? ( - - {title ? {title} : null} - {description ? ( - {description} - ) : null} - - ) : null} - -
{children}
- - {footer ? {footer} : null} -
-
- ); -} - -export interface AdaptiveConfirmProps extends OpenStateProps { - trigger?: ReactNode; - title: ReactNode; - description?: ReactNode; - cancelLabel: ReactNode; - confirmLabel: ReactNode; - onConfirm: () => void; - confirmClassName?: string; - cancelClassName?: string; - contentClassName?: string; - headerClassName?: string; - footerClassName?: string; -} - -export function AdaptiveConfirm({ - open, - defaultOpen, - onOpenChange, - trigger, - title, - description, - cancelLabel, - confirmLabel, - onConfirm, - confirmClassName, - cancelClassName, - contentClassName, - headerClassName, - footerClassName, -}: AdaptiveConfirmProps) { - const isMobile = useIsMobile(); - - if (isMobile) { - return ( - - {trigger ? {trigger} : null} - - - {title} - {description ? {description} : null} - - - - - - - - - - - - ); - } - - return ( - - {trigger ? {trigger} : null} - - - {title} - {description ? ( - {description} - ) : null} - - - {cancelLabel} - - {confirmLabel} - - - - - ); -} diff --git a/apps/frontend/src/components/ui/alert-dialog.tsx b/apps/frontend/src/components/ui/alert-dialog.tsx deleted file mode 100644 index e68c62c..0000000 --- a/apps/frontend/src/components/ui/alert-dialog.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import * as React from "react" -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" - -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" - -const AlertDialog = AlertDialogPrimitive.Root - -const AlertDialogTrigger = AlertDialogPrimitive.Trigger - -const AlertDialogPortal = AlertDialogPrimitive.Portal - -const AlertDialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName - -const AlertDialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - -)) -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName - -const AlertDialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -AlertDialogHeader.displayName = "AlertDialogHeader" - -const AlertDialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -AlertDialogFooter.displayName = "AlertDialogFooter" - -const AlertDialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName - -const AlertDialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName - -const AlertDialogAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName - -const AlertDialogCancel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName - -export { - AlertDialog, - AlertDialogPortal, - AlertDialogOverlay, - AlertDialogTrigger, - AlertDialogContent, - AlertDialogHeader, - AlertDialogFooter, - AlertDialogTitle, - AlertDialogDescription, - AlertDialogAction, - AlertDialogCancel, -} diff --git a/apps/frontend/src/components/ui/alert.tsx b/apps/frontend/src/components/ui/alert.tsx deleted file mode 100644 index 7eeb6f8..0000000 --- a/apps/frontend/src/components/ui/alert.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; - -import { cn } from "@/lib/utils"; - -const alertVariants = cva( - "relative w-full rounded-lg border border-border bg-background p-4 text-foreground [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", - { - variants: { - variant: { - default: "", - destructive: - "border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900", - warning: - "border-yellow-500/50 text-yellow-800 bg-yellow-50 dark:border-yellow-500 [&>svg]:text-yellow-500 dark:border-yellow-900/50 dark:text-yellow-900 dark:dark:border-yellow-900 dark:[&>svg]:text-yellow-900", - }, - }, - defaultVariants: { - variant: "default", - }, - } -); - -const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps ->(({ className, variant, ...props }, ref) => ( -
-)); -Alert.displayName = "Alert"; - -const AlertTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -AlertTitle.displayName = "AlertTitle"; - -const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -AlertDescription.displayName = "AlertDescription"; - -export { Alert, AlertTitle, AlertDescription }; diff --git a/apps/frontend/src/components/ui/avatar.tsx b/apps/frontend/src/components/ui/avatar.tsx index 991f56e..5ce1da0 100644 --- a/apps/frontend/src/components/ui/avatar.tsx +++ b/apps/frontend/src/components/ui/avatar.tsx @@ -1,48 +1,15 @@ -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" - -import { cn } from "@/lib/utils" - -const Avatar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -Avatar.displayName = AvatarPrimitive.Root.displayName - -const AvatarImage = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AvatarImage.displayName = AvatarPrimitive.Image.displayName - -const AvatarFallback = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName - -export { Avatar, AvatarImage, AvatarFallback } +export function Avatar({ + initials, + src, + size = "md", +}: { + initials: string; + src?: string; + size?: "sm" | "md" | "lg"; +}) { + return src ? ( + + ) : ( + {initials} + ); +} diff --git a/apps/frontend/src/components/ui/badge.tsx b/apps/frontend/src/components/ui/badge.tsx deleted file mode 100644 index e36abff..0000000 --- a/apps/frontend/src/components/ui/badge.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const badgeVariants = cva( - "inline-flex items-center rounded-full border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-background", - { - variants: { - variant: { - default: - "border-transparent bg-foreground text-background hover:bg-foreground/80", - secondary: - "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - destructive: - "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} - -function Badge({ className, variant, ...props }: BadgeProps) { - return ( -
- ) -} - -export { Badge, badgeVariants } diff --git a/apps/frontend/src/components/ui/brand-mark.tsx b/apps/frontend/src/components/ui/brand-mark.tsx new file mode 100644 index 0000000..62a9885 --- /dev/null +++ b/apps/frontend/src/components/ui/brand-mark.tsx @@ -0,0 +1,18 @@ +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; + +export function BrandMark({ compact = false }: { compact?: boolean }) { + const { t } = useTranslation(); + return ( + + + + bitfinance + + + ); +} diff --git a/apps/frontend/src/components/ui/breadcrumb.tsx b/apps/frontend/src/components/ui/breadcrumb.tsx deleted file mode 100644 index 60e6c96..0000000 --- a/apps/frontend/src/components/ui/breadcrumb.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { ChevronRight, MoreHorizontal } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Breadcrumb = React.forwardRef< - HTMLElement, - React.ComponentPropsWithoutRef<"nav"> & { - separator?: React.ReactNode - } ->(({ ...props }, ref) =>