diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml new file mode 100644 index 0000000..1df7465 --- /dev/null +++ b/.codex/environments/environment.toml @@ -0,0 +1,6 @@ +# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY +version = 1 +name = "atlantis" + +[setup] +script = "npm install" diff --git a/.dockerignore b/.dockerignore index 6d40632..803ead9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -25,6 +25,7 @@ yarn-error.log* .env.test.local .env.production.local !.env.example +.env.bkp # IDE and editor .idea @@ -66,11 +67,24 @@ vitest.config.* # Development tools .eslintrc* .prettierrc* +.prettierignore .editorconfig tsconfig.tsbuildinfo +next-env.d.ts # Prisma migrations history (schema.template.prisma is needed) prisma/migrations # Data directory (mounted at runtime) data/ + + +# Other +.github/ +.codex/ +screenshots/ +data_new/ +plan/ +examples/ +TODO.md +AGENTS.md diff --git a/.env.example b/.env.example index 36a94ab..9e30e33 100644 --- a/.env.example +++ b/.env.example @@ -13,6 +13,14 @@ PRISMA_SKIP_AUTOPUSH= # Falls back to in-memory cache if not set # REDIS_URL=redis://localhost:6379 +# Live sync transport +# Use socket (SSE) for static instances, polling for serverless deployments +# Accepted values: socket | polling +NEXT_PUBLIC_LIVE_SYNC_METHOD=socket +# Polling interval in milliseconds (used only when method=polling) +# Accepted values: 3000 | 5000 | 10000 | 30000 +NEXT_PUBLIC_LIVE_SYNC_POLL_INTERVAL_MS=5000 + # API Access # Set to true to enable the /api/access endpoints and API docs integration ENABLE_API_ACCESS=false diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 750946a..9cbafe6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,6 +9,7 @@ labels: bug Clear summary of the issue. **Steps to Reproduce** + 1. 2. 3. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7a48baa..9664806 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,11 @@ ## Summary + Describe the changes and motivation. Fixes # (issue) ## Checklist + - [ ] Tested changes locally - [ ] Updated documentation (if applicable) -- [ ] Follows project style \ No newline at end of file +- [ ] Follows project style diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..687448f --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,30 @@ +name: Lint and Formatting +permissions: + contents: read +on: + push: + branches: ['main', 'master'] + pull_request: + branches: ['main', 'master'] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + + - name: Install Dependencies + run: npm ci + + - name: Run ESLint + run: npm run lint + + - name: Run Prettier formatting check + run: npx prettier --check . diff --git a/AGENTS.md b/AGENTS.md index 0281cbc..600cfd7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,8 +10,17 @@ Purpose: concise, high-signal defaults for this Next.js 16 + TypeScript + Tailwi - Diagrams: Mermaid editor; persisted to Prisma SQLite or JSON backup. - Notes: see `src/app/notes`, server layouts fetch data and render client shells. - Icons/Fonts/Themes: lucide-react, `next/font`, `next-themes` (light/dark toggle). +- Code map: `plan/code-map.md` is the required map-first index for file ownership and task routing. - Editors: no Cursor rules (`.cursor/` missing); no Copilot instructions (`.github/copilot-instructions.md` missing). This file is authoritative. +## Mandatory Code Map Workflow + +- Always read `plan/code-map.md` before searching or editing code. +- Use map-first navigation: start with the intent map and open those files before broad searching. +- Avoid blind repo-wide searches unless the code map does not cover the task. +- If you add/move/rename files, routes, folders, or exported functions, update `plan/code-map.md` in the same change. +- Treat stale code-map entries as bugs; fix them as part of the task. + ## Commands (npm) - Install deps: `npm install` (first step before any command). @@ -32,13 +41,14 @@ Purpose: concise, high-signal defaults for this Next.js 16 + TypeScript + Tailwi ## Project Map - `src/app/`: routes/layout. `src/app/page.tsx` uses ISR 30s. -- `src/app/[id]/`: diagram editor (client-heavy); gate browser libs with mounted checks. +- `src/app/diagram/[id]/`: diagram editor (client-heavy); gate browser libs with mounted checks. - `src/app/notes/`: notes layout + list; dynamic fetch with `getNotePage`; entry page shows empty-state; `[id]/page` loads note with `getNoteById` and renders `NoteWorkspace`; `dynamic = 'force-dynamic'` on layout and page to avoid caching. - `src/app/api/`: API routes; keep server-only. - `src/components/`: feature/layout components. Avoid touching `src/components/ui` unless fixing a shared UI bug. - `src/lib/`: utilities, data access (`notes-data`), types, Zustand store. - `data/`: SQLite db/backups; `public/`: static assets; `scripts/`: bootstrap + Prisma helpers (bootstrap must run before dev/build). - `docs/`: repo docs; update this file and `docs/AI.md` if conventions change. +- `plan/`: planning docs; `plan/code-map.md` must stay current with structure and ownership. ## Styling @@ -149,6 +159,7 @@ Purpose: concise, high-signal defaults for this Next.js 16 + TypeScript + Tailwi - Docs live in `docs/`; see `docs/AI.md` for AI/agent usage guidance. - Update this file when commands, tooling, or conventions change. +- Update `plan/code-map.md` whenever code structure, directory ownership, routes, or exported responsibilities change. ## Extension Checklist diff --git a/docker-compose.simple.yml b/docker-compose.simple.yml index 2d9671d..3f7945f 100644 --- a/docker-compose.simple.yml +++ b/docker-compose.simple.yml @@ -8,7 +8,7 @@ services: container_name: atlantis restart: unless-stopped ports: - - "${PORT:-3000}:3000" + - '${PORT:-3000}:3000' volumes: # Persist diagram data - map to your preferred location # Default: uses Docker named volume @@ -23,7 +23,7 @@ services: - DATABASE_URL=${DATABASE_URL:-} # No REDIS_URL - uses in-memory caching healthcheck: - test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/" ] + test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/'] interval: 30s timeout: 10s retries: 3 diff --git a/docker-compose.yml b/docker-compose.yml index 6bdd1af..755b200 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,10 @@ services: atlantis: image: strikead/atlantis:latest container_name: atlantis + user: '1001:1001' restart: unless-stopped ports: - - "${PORT:-3000}:3000" + - '${PORT:-3000}:3000' volumes: # Persist diagram data - map to your preferred location # Default: uses Docker named volume @@ -19,11 +20,24 @@ services: - REDIS_URL=${REDIS_URL:-redis://redis:6379} # Database connection (optional - uses SQLite if not set) - DATABASE_URL=${DATABASE_URL:-} + # AI Configuration (OpenAI or Google AI Studio keys) + - AI_API_KEY=${AI_API_KEY:-} + # Live sync transport (socket or polling) + - NEXT_PUBLIC_LIVE_SYNC_METHOD=${NEXT_PUBLIC_LIVE_SYNC_METHOD:-socket} + - NEXT_PUBLIC_LIVE_SYNC_POLL_INTERVAL_MS=${NEXT_PUBLIC_LIVE_SYNC_POLL_INTERVAL_MS:-5000} + networks: + - atlantis-network depends_on: redis: condition: service_healthy healthcheck: - test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/" ] + test: + [ + 'CMD', + 'node', + '-e', + "fetch('http://127.0.0.1:3000/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))", + ] interval: 30s timeout: 10s retries: 3 @@ -34,16 +48,24 @@ services: container_name: atlantis-redis restart: unless-stopped ports: - - "6379:6379" + - '6379:6379' volumes: - - ${ATLANTIS_DATA_DIR:-atlantis_data}:/data + - atlantis_redis_data:/data command: redis-server --appendonly yes + networks: + - atlantis-network healthcheck: - test: [ "CMD", "redis-cli", "ping" ] + test: ['CMD', 'redis-cli', 'ping'] interval: 10s timeout: 5s retries: 3 +networks: + atlantis-network: + driver: bridge + volumes: atlantis_data: driver: local + atlantis_redis_data: + driver: local diff --git a/docs/AI.md b/docs/AI.md index 3753b27..c0dea7a 100644 --- a/docs/AI.md +++ b/docs/AI.md @@ -12,7 +12,7 @@ Server endpoint: `POST /api/ai/assist` (requires valid CSRF token). UI handles C 2. **Providers**: - **OpenAI**: Default. Model: `gpt-4o-mini`. - - **Gemini**: Model: `gemini-2.5-flash` (override with `GEMINI_MODEL`). + - **Gemini**: Model: `gemini-3.1-flash-lite-preview` (override with `GEMINI_MODEL`). - **Auto-detect**: Chooses provider from key prefix (`sk-...` vs `AIza...`/`gsk_...`). ## Usage diff --git a/docs/CONTAINER_STARTUP.md b/docs/CONTAINER_STARTUP.md index 14b2c90..a67a310 100644 --- a/docs/CONTAINER_STARTUP.md +++ b/docs/CONTAINER_STARTUP.md @@ -136,7 +136,8 @@ PORT=8080 ATLANTIS_DATA_DIR=./my-data docker compose up -d | `PRISMA_AUTO_APPLY` | `true` (non-prod), `false` (prod) | Auto-runs `prisma db push` on server start to ensure schema exists. | | `PRISMA_SKIP_AUTOPUSH` | `false` | Set to `true` to skip all db push/seed operations. | | `ENABLE_API_ACCESS` | `false` | Set to `true` to enable the REST API and /docs. | -| `GEMINI_MODEL` | `gemini-2.5-flash` | Override default Gemini model when using Gemini provider. | +| `GEMINI_MODEL` | `gemini-3.1-flash-lite-preview` | Override default Gemini model when using Gemini provider. | +| `GEMINI_API_VERSION` | `v1` or `v1beta` | Gemini API version; auto-detects `v1beta` for preview models. | | `ATLANTIS_DATA_DIR` | `./data` | Host bind mount for data when using provided compose files. | ## Versioning diff --git a/docs/index.html b/docs/index.html index 701d78e..7c8e82c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,298 +1,356 @@ - + - - - - - - - + + + + + + Atlantis - Self-Hosted Diagrams & Notes - - - - - + + + + + - +
-
-
-
+
+
+
-
-
- - Self-Hosted & Open Source -
-

- Create Beautiful
- Diagrams & Notes -

-

- A self-hosted platform for Mermaid.js diagrams, notes, and knowledge management. - Built with Next.js, Tailwind CSS, and Shadcn UI. -

- - +
+
+ + Self-Hosted & Open Source +
+

+ Create Beautiful
+ Diagrams & Notes +

+

+ A self-hosted platform for Mermaid.js diagrams, notes, and knowledge management. Built + with Next.js, Tailwind CSS, and Shadcn UI. +

+ + -
-
-
-
- - - -
-
localhost:3000
-
-
- Atlantis Dashboard Preview -
+
+
+
+
+
+ + +
+
localhost:3000
+
+
+ Atlantis Dashboard Preview +
+
-
-
-

Packed with Features

-

Everything you need to create, organize, and manage your diagrams and notes. -

+
+
+

Packed with Features

+

+ Everything you need to create, organize, and manage your diagrams and notes. +

+
+
+
+
+ + + + + +
+

Modern Editor

+

Split-pane interface with live preview for real-time diagram editing.

+
+
+
+ + + +
+

Full Mermaid Support

+

All Mermaid.js diagram types supported out of the box.

+
+
+
+ + + + + +
+

Docker Ready

+

Deploy instantly with Docker. Supports PostgreSQL, MySQL, or SQLite.

+
+
+
+ + + +
-
-
-
- - - - - -
-

Modern Editor

-

Split-pane interface with live preview for real-time diagram editing.

-
-
-
- - - -
-

Full Mermaid Support

-

All Mermaid.js diagram types supported out of the box.

-
-
-
- - - - - - -
-

Docker Ready

-

Deploy instantly with Docker. Supports PostgreSQL, MySQL, or SQLite.

-
-
-
- - - - - -
-

Dark/Light Mode

-

Beautiful UI that automatically adapts to your system preference.

-
-
-
- - - - -
-

Favorites

-

Organize your diagrams by starring important ones for quick access.

-
-
-
- - - - - -
-

Backup & Restore

-

Export your data to JSON and restore whenever needed.

-
+

Dark/Light Mode

+

Beautiful UI that automatically adapts to your system preference.

+
+
+
+ + +
+

Favorites

+

Organize your diagrams by starring important ones for quick access.

+
+
+
+ + + + + +
+

Backup & Restore

+

Export your data to JSON and restore whenever needed.

+
+
-
-
-

See it in Action

-

Beautiful interface designed for productivity and ease of use.

+
+
+

See it in Action

+

+ Beautiful interface designed for productivity and ease of use. +

+
+
-
-
-

Get Started in Seconds

-

Run Atlantis instantly with Docker or set up for local development.

-
-
- - -
-
-
-
-
- Terminal - -
-
docker run -d -p 3000:3000 \
+      
+
+

Get Started in Seconds

+

+ Run Atlantis instantly with Docker or set up for local development. +

+
+
+ + +
+
+
+
+
+ Terminal + +
+
docker run -d -p 3000:3000 \
   -v $(pwd)/data:/app/data \
   --name atlantis \
   strikead/atlantis:latest
-
-

- - - - - - Then open http://localhost:3000 in your - browser. -

-
-
-
-
- Terminal - -
-
# Clone the repository
+            
+

+ + + + + + Then open http://localhost:3000 in + your browser. +

+
+
+
+
+ Terminal + +
+
# Clone the repository
 git clone https://github.com/Fantastic-Computing-Machine/atlantis.git
 cd atlantis
 
@@ -304,117 +362,149 @@ 

Get Started in Seconds

-
-

- - - - - - Requires Node.js 18+ installed on your machine. -

-
+

+ + + + + + Requires Node.js 18+ installed on your machine. +

+
+
-
-
-
-

Ready to get started?

-

Join the community and start creating beautiful diagrams today.

- -
+
+
+

Ready to get started?

+

Join the community and start creating beautiful diagrams today.

+
+
- - - \ No newline at end of file + + diff --git a/docs/settings.md b/docs/settings.md index 85855f8..3ee4029 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -26,7 +26,7 @@ Atlantis provides configurable settings accessible via the `/settings` page. ### Supported Models - **OpenAI**: `gpt-4o-mini` -- **Gemini**: `gemini-2.5-flash` (configurable via `GEMINI_MODEL` env var) +- **Gemini**: `gemini-3.1-flash-lite-preview` (configurable via `GEMINI_MODEL` env var) > **Note**: When `AI_API_KEY` environment variable is set, the key cannot be modified through the UI and is shown as "read-only". @@ -67,7 +67,8 @@ Settings can also be configured via environment variables. These are especially | `DATABASE_URL` | `file:./data/atlantis.db` | Database connection string (`DB_CONNECTION` alias supported) | | `REDIS_URL` | _(none)_ | Redis connection (e.g., `redis://redis:6379`) | | `AI_API_KEY` | _(none)_ | AI API key for OpenAI/Gemini features | -| `GEMINI_MODEL` | `gemini-2.5-flash` | Gemini model to use | +| `GEMINI_MODEL` | `gemini-3.1-flash-lite-preview` | Gemini model to use | +| `GEMINI_API_VERSION` | `v1` or `v1beta` (auto-detected) | Gemini API version (defaults to `v1beta` for `-preview` models) | | `ENABLE_API_ACCESS` | `false` | Enable REST API endpoints and `/docs` (requires CSRF cookie/header for writes) | | `PRISMA_AUTO_APPLY` | `true` (dev), `false` (prod) | Dev bootstrap only: auto-run `prisma db push` during `npm run dev`/`npm run build` (Docker entrypoint/`npm run start` always runs `prisma db push`) | | `PRISMA_SKIP_AUTOPUSH` | `false` | Dev bootstrap only: skip automatic db push/seed in `scripts/bootstrap.js` (no effect on `npm run start` or Docker) | diff --git a/docs/styles.css b/docs/styles.css index 0a2fb2a..3d39007 100644 --- a/docs/styles.css +++ b/docs/styles.css @@ -1,797 +1,844 @@ /* CSS Variables & Theme */ :root { - --primary-hue: 220; - --accent-hue: 270; - --bg-dark: hsl(222, 47%, 7%); - --bg-card: hsl(222, 40%, 10%); - --bg-card-hover: hsl(222, 40%, 13%); - --text-primary: hsl(220, 20%, 95%); - --text-secondary: hsl(220, 15%, 65%); - --text-muted: hsl(220, 10%, 45%); - --border-color: hsl(220, 30%, 18%); - --gradient-start: hsl(var(--primary-hue), 100%, 65%); - --gradient-mid: hsl(calc(var(--primary-hue) + 40), 100%, 60%); - --gradient-end: hsl(var(--accent-hue), 100%, 70%); - --shadow-glow: 0 0 60px hsla(var(--primary-hue), 100%, 50%, 0.15); - --radius-sm: 8px; - --radius-md: 12px; - --radius-lg: 20px; - --radius-xl: 28px; + --primary-hue: 220; + --accent-hue: 270; + --bg-dark: hsl(222, 47%, 7%); + --bg-card: hsl(222, 40%, 10%); + --bg-card-hover: hsl(222, 40%, 13%); + --text-primary: hsl(220, 20%, 95%); + --text-secondary: hsl(220, 15%, 65%); + --text-muted: hsl(220, 10%, 45%); + --border-color: hsl(220, 30%, 18%); + --gradient-start: hsl(var(--primary-hue), 100%, 65%); + --gradient-mid: hsl(calc(var(--primary-hue) + 40), 100%, 60%); + --gradient-end: hsl(var(--accent-hue), 100%, 70%); + --shadow-glow: 0 0 60px hsla(var(--primary-hue), 100%, 50%, 0.15); + --radius-sm: 8px; + --radius-md: 12px; + --radius-lg: 20px; + --radius-xl: 28px; } /* Reset & Base Styles */ -*, *::before, *::after { - margin: 0; - padding: 0; - box-sizing: border-box; +*, +*::before, +*::after { + margin: 0; + padding: 0; + box-sizing: border-box; } html { - scroll-behavior: smooth; + scroll-behavior: smooth; } body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background-color: var(--bg-dark); - color: var(--text-primary); - line-height: 1.6; - overflow-x: hidden; + font-family: + 'Inter', + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + sans-serif; + background-color: var(--bg-dark); + color: var(--text-primary); + line-height: 1.6; + overflow-x: hidden; } a { - color: inherit; - text-decoration: none; + color: inherit; + text-decoration: none; } img { - max-width: 100%; - height: auto; - display: block; + max-width: 100%; + height: auto; + display: block; } /* Animated Background */ .bg-animation { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: -1; - overflow: hidden; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; + overflow: hidden; } .gradient-orb { - position: absolute; - border-radius: 50%; - filter: blur(80px); - opacity: 0.4; - animation: float 20s ease-in-out infinite; + position: absolute; + border-radius: 50%; + filter: blur(80px); + opacity: 0.4; + animation: float 20s ease-in-out infinite; } .orb-1 { - width: 600px; - height: 600px; - background: linear-gradient(135deg, hsla(220, 100%, 50%, 0.5), hsla(280, 100%, 50%, 0.3)); - top: -200px; - right: -100px; - animation-delay: 0s; + width: 600px; + height: 600px; + background: linear-gradient(135deg, hsla(220, 100%, 50%, 0.5), hsla(280, 100%, 50%, 0.3)); + top: -200px; + right: -100px; + animation-delay: 0s; } .orb-2 { - width: 500px; - height: 500px; - background: linear-gradient(135deg, hsla(280, 100%, 50%, 0.4), hsla(180, 100%, 50%, 0.3)); - bottom: -150px; - left: -100px; - animation-delay: -7s; + width: 500px; + height: 500px; + background: linear-gradient(135deg, hsla(280, 100%, 50%, 0.4), hsla(180, 100%, 50%, 0.3)); + bottom: -150px; + left: -100px; + animation-delay: -7s; } .orb-3 { - width: 400px; - height: 400px; - background: linear-gradient(135deg, hsla(180, 100%, 50%, 0.3), hsla(220, 100%, 50%, 0.4)); - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - animation-delay: -14s; + width: 400px; + height: 400px; + background: linear-gradient(135deg, hsla(180, 100%, 50%, 0.3), hsla(220, 100%, 50%, 0.4)); + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + animation-delay: -14s; } @keyframes float { - 0%, 100% { transform: translate(0, 0) scale(1); } - 25% { transform: translate(30px, -30px) scale(1.05); } - 50% { transform: translate(-20px, 20px) scale(0.95); } - 75% { transform: translate(20px, 30px) scale(1.02); } + 0%, + 100% { + transform: translate(0, 0) scale(1); + } + 25% { + transform: translate(30px, -30px) scale(1.05); + } + 50% { + transform: translate(-20px, 20px) scale(0.95); + } + 75% { + transform: translate(20px, 30px) scale(1.02); + } } /* Container */ .container { - max-width: 1200px; - margin: 0 auto; - padding: 0 24px; + max-width: 1200px; + margin: 0 auto; + padding: 0 24px; } /* Navigation */ .navbar { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - padding: 16px 0; - background: hsla(222, 47%, 7%, 0.8); - backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border-color); + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + padding: 16px 0; + background: hsla(222, 47%, 7%, 0.8); + backdrop-filter: blur(20px); + border-bottom: 1px solid var(--border-color); } .nav-container { - max-width: 1200px; - margin: 0 auto; - padding: 0 24px; - display: flex; - align-items: center; - justify-content: space-between; + max-width: 1200px; + margin: 0 auto; + padding: 0 24px; + display: flex; + align-items: center; + justify-content: space-between; } .nav-brand { - display: flex; - align-items: center; - gap: 10px; - font-weight: 700; - font-size: 1.25rem; + display: flex; + align-items: center; + gap: 10px; + font-weight: 700; + font-size: 1.25rem; } .brand-icon { - font-size: 1.5rem; + font-size: 1.5rem; } .nav-links { - display: flex; - align-items: center; - gap: 32px; + display: flex; + align-items: center; + gap: 32px; } .nav-links a { - font-size: 0.9rem; - font-weight: 500; - color: var(--text-secondary); - transition: color 0.2s; + font-size: 0.9rem; + font-weight: 500; + color: var(--text-secondary); + transition: color 0.2s; } .nav-links a:hover { - color: var(--text-primary); + color: var(--text-primary); } .nav-github { - display: flex; - align-items: center; - gap: 8px; - padding: 8px 16px; - background: var(--bg-card); - border-radius: var(--radius-sm); - border: 1px solid var(--border-color); + display: flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + background: var(--bg-card); + border-radius: var(--radius-sm); + border: 1px solid var(--border-color); } .nav-github:hover { - background: var(--bg-card-hover); + background: var(--bg-card-hover); } /* Hero Section */ .hero { - min-height: 100vh; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 60px; - align-items: center; - padding: 120px 24px 80px; - max-width: 1400px; - margin: 0 auto; + min-height: 100vh; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 60px; + align-items: center; + padding: 120px 24px 80px; + max-width: 1400px; + margin: 0 auto; } .hero-content { - max-width: 600px; + max-width: 600px; } .hero-badge { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 8px 16px; - background: hsla(var(--primary-hue), 100%, 50%, 0.1); - border: 1px solid hsla(var(--primary-hue), 100%, 50%, 0.3); - border-radius: 100px; - font-size: 0.85rem; - font-weight: 500; - color: var(--gradient-start); - margin-bottom: 24px; + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + background: hsla(var(--primary-hue), 100%, 50%, 0.1); + border: 1px solid hsla(var(--primary-hue), 100%, 50%, 0.3); + border-radius: 100px; + font-size: 0.85rem; + font-weight: 500; + color: var(--gradient-start); + margin-bottom: 24px; } .badge-dot { - width: 8px; - height: 8px; - background: var(--gradient-start); - border-radius: 50%; - animation: pulse 2s infinite; + width: 8px; + height: 8px; + background: var(--gradient-start); + border-radius: 50%; + animation: pulse 2s infinite; } @keyframes pulse { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.5; transform: scale(1.2); } + 0%, + 100% { + opacity: 1; + transform: scale(1); + } + 50% { + opacity: 0.5; + transform: scale(1.2); + } } .hero-title { - font-size: clamp(2.5rem, 5vw, 4rem); - font-weight: 800; - line-height: 1.1; - margin-bottom: 24px; - letter-spacing: -0.02em; + font-size: clamp(2.5rem, 5vw, 4rem); + font-weight: 800; + line-height: 1.1; + margin-bottom: 24px; + letter-spacing: -0.02em; } .gradient-text { - background: linear-gradient(135deg, var(--gradient-start), var(--gradient-mid), var(--gradient-end)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; + background: linear-gradient( + 135deg, + var(--gradient-start), + var(--gradient-mid), + var(--gradient-end) + ); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; } .hero-subtitle { - font-size: 1.15rem; - color: var(--text-secondary); - margin-bottom: 32px; - line-height: 1.7; + font-size: 1.15rem; + color: var(--text-secondary); + margin-bottom: 32px; + line-height: 1.7; } .hero-buttons { - display: flex; - gap: 16px; - flex-wrap: wrap; - margin-bottom: 40px; + display: flex; + gap: 16px; + flex-wrap: wrap; + margin-bottom: 40px; } /* Buttons */ .btn { - display: inline-flex; - align-items: center; - gap: 10px; - padding: 14px 28px; - border-radius: var(--radius-md); - font-weight: 600; - font-size: 0.95rem; - transition: all 0.3s ease; - cursor: pointer; - border: none; + display: inline-flex; + align-items: center; + gap: 10px; + padding: 14px 28px; + border-radius: var(--radius-md); + font-weight: 600; + font-size: 0.95rem; + transition: all 0.3s ease; + cursor: pointer; + border: none; } .btn-primary { - background: linear-gradient(135deg, var(--gradient-start), var(--gradient-mid)); - color: white; - box-shadow: 0 4px 20px hsla(var(--primary-hue), 100%, 50%, 0.3); + background: linear-gradient(135deg, var(--gradient-start), var(--gradient-mid)); + color: white; + box-shadow: 0 4px 20px hsla(var(--primary-hue), 100%, 50%, 0.3); } .btn-primary:hover { - transform: translateY(-2px); - box-shadow: 0 8px 30px hsla(var(--primary-hue), 100%, 50%, 0.4); + transform: translateY(-2px); + box-shadow: 0 8px 30px hsla(var(--primary-hue), 100%, 50%, 0.4); } .btn-secondary { - background: var(--bg-card); - border: 1px solid var(--border-color); - color: var(--text-primary); + background: var(--bg-card); + border: 1px solid var(--border-color); + color: var(--text-primary); } .btn-secondary:hover { - background: var(--bg-card-hover); - border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); + background: var(--bg-card-hover); + border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); } .hero-stats { - display: flex; - gap: 12px; - flex-wrap: wrap; + display: flex; + gap: 12px; + flex-wrap: wrap; } .stat-item img { - height: 24px; + height: 24px; } /* Hero Image */ .hero-image { - perspective: 1000px; + perspective: 1000px; } .browser-mockup { - background: var(--bg-card); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); - overflow: hidden; - box-shadow: var(--shadow-glow); - transform: rotateY(-5deg) rotateX(2deg); - transition: transform 0.5s ease; + background: var(--bg-card); + border-radius: var(--radius-lg); + border: 1px solid var(--border-color); + overflow: hidden; + box-shadow: var(--shadow-glow); + transform: rotateY(-5deg) rotateX(2deg); + transition: transform 0.5s ease; } .browser-mockup:hover { - transform: rotateY(0) rotateX(0); + transform: rotateY(0) rotateX(0); } .browser-header { - display: flex; - align-items: center; - gap: 16px; - padding: 12px 16px; - background: hsl(222, 40%, 8%); - border-bottom: 1px solid var(--border-color); + display: flex; + align-items: center; + gap: 16px; + padding: 12px 16px; + background: hsl(222, 40%, 8%); + border-bottom: 1px solid var(--border-color); } .browser-dots { - display: flex; - gap: 8px; + display: flex; + gap: 8px; } .dot { - width: 12px; - height: 12px; - border-radius: 50%; + width: 12px; + height: 12px; + border-radius: 50%; } -.dot.red { background: #ff5f57; } -.dot.yellow { background: #febc2e; } -.dot.green { background: #28c840; } +.dot.red { + background: #ff5f57; +} +.dot.yellow { + background: #febc2e; +} +.dot.green { + background: #28c840; +} .browser-address { - flex: 1; - background: var(--bg-dark); - padding: 6px 12px; - border-radius: 6px; - font-size: 0.8rem; - color: var(--text-muted); + flex: 1; + background: var(--bg-dark); + padding: 6px 12px; + border-radius: 6px; + font-size: 0.8rem; + color: var(--text-muted); } .browser-content img { - width: 100%; - display: block; + width: 100%; + display: block; } /* Sections */ section { - padding: 100px 0; + padding: 100px 0; } .section-header { - text-align: center; - max-width: 600px; - margin: 0 auto 60px; + text-align: center; + max-width: 600px; + margin: 0 auto 60px; } .section-title { - font-size: clamp(2rem, 4vw, 2.75rem); - font-weight: 700; - margin-bottom: 16px; + font-size: clamp(2rem, 4vw, 2.75rem); + font-weight: 700; + margin-bottom: 16px; } .section-subtitle { - font-size: 1.1rem; - color: var(--text-secondary); + font-size: 1.1rem; + color: var(--text-secondary); } /* Features Grid */ .features { - background: linear-gradient(180deg, transparent, hsla(222, 47%, 5%, 0.5), transparent); + background: linear-gradient(180deg, transparent, hsla(222, 47%, 5%, 0.5), transparent); } .features-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); - gap: 24px; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 24px; } .feature-card { - padding: 32px; - background: var(--bg-card); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); - transition: all 0.3s ease; + padding: 32px; + background: var(--bg-card); + border-radius: var(--radius-lg); + border: 1px solid var(--border-color); + transition: all 0.3s ease; } .feature-card:hover { - background: var(--bg-card-hover); - transform: translateY(-4px); - border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); + background: var(--bg-card-hover); + transform: translateY(-4px); + border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); } .feature-icon { - width: 56px; - height: 56px; - display: flex; - align-items: center; - justify-content: center; - background: linear-gradient(135deg, hsla(var(--primary-hue), 100%, 50%, 0.15), hsla(var(--accent-hue), 100%, 50%, 0.1)); - border-radius: var(--radius-md); - margin-bottom: 20px; + width: 56px; + height: 56px; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient( + 135deg, + hsla(var(--primary-hue), 100%, 50%, 0.15), + hsla(var(--accent-hue), 100%, 50%, 0.1) + ); + border-radius: var(--radius-md); + margin-bottom: 20px; } .feature-icon svg { - width: 28px; - height: 28px; - stroke: var(--gradient-start); + width: 28px; + height: 28px; + stroke: var(--gradient-start); } .feature-card h3 { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 10px; + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 10px; } .feature-card p { - color: var(--text-secondary); - font-size: 0.95rem; + color: var(--text-secondary); + font-size: 0.95rem; } /* Screenshots Gallery */ .screenshots-gallery { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 24px; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 24px; } .screenshot-item { - border-radius: var(--radius-lg); - overflow: hidden; - background: var(--bg-card); - border: 1px solid var(--border-color); - transition: all 0.3s ease; + border-radius: var(--radius-lg); + overflow: hidden; + background: var(--bg-card); + border: 1px solid var(--border-color); + transition: all 0.3s ease; } .screenshot-item:hover { - transform: scale(1.02); - border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); - box-shadow: var(--shadow-glow); + transform: scale(1.02); + border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); + box-shadow: var(--shadow-glow); } .screenshot-wrapper { - aspect-ratio: 16/10; - overflow: hidden; + aspect-ratio: 16/10; + overflow: hidden; } .screenshot-wrapper img { - width: 100%; - height: 100%; - object-fit: cover; - transition: transform 0.5s ease; + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; } .screenshot-item:hover .screenshot-wrapper img { - transform: scale(1.05); + transform: scale(1.05); } .screenshot-info { - padding: 20px; + padding: 20px; } .screenshot-info h4 { - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 6px; + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 6px; } .screenshot-info p { - color: var(--text-secondary); - font-size: 0.9rem; + color: var(--text-secondary); + font-size: 0.9rem; } /* Quick Start */ .quickstart { - background: linear-gradient(180deg, transparent, hsla(222, 47%, 5%, 0.5), transparent); + background: linear-gradient(180deg, transparent, hsla(222, 47%, 5%, 0.5), transparent); } .quickstart-tabs { - display: flex; - justify-content: center; - gap: 8px; - margin-bottom: 32px; + display: flex; + justify-content: center; + gap: 8px; + margin-bottom: 32px; } .tab-btn { - padding: 12px 28px; - background: var(--bg-card); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - color: var(--text-secondary); - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; + padding: 12px 28px; + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + color: var(--text-secondary); + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; } .tab-btn:hover { - background: var(--bg-card-hover); + background: var(--bg-card-hover); } .tab-btn.active { - background: linear-gradient(135deg, hsla(var(--primary-hue), 100%, 50%, 0.15), hsla(var(--accent-hue), 100%, 50%, 0.1)); - border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); - color: var(--text-primary); + background: linear-gradient( + 135deg, + hsla(var(--primary-hue), 100%, 50%, 0.15), + hsla(var(--accent-hue), 100%, 50%, 0.1) + ); + border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); + color: var(--text-primary); } .tab-content { - display: none; - max-width: 700px; - margin: 0 auto; + display: none; + max-width: 700px; + margin: 0 auto; } .tab-content.active { - display: block; + display: block; } .code-block { - background: hsl(222, 50%, 6%); - border-radius: var(--radius-md); - border: 1px solid var(--border-color); - overflow: hidden; + background: hsl(222, 50%, 6%); + border-radius: var(--radius-md); + border: 1px solid var(--border-color); + overflow: hidden; } .code-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 12px 16px; - background: hsl(222, 45%, 8%); - border-bottom: 1px solid var(--border-color); - font-size: 0.85rem; - color: var(--text-muted); + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 16px; + background: hsl(222, 45%, 8%); + border-bottom: 1px solid var(--border-color); + font-size: 0.85rem; + color: var(--text-muted); } .copy-btn { - display: flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - background: var(--bg-card); - border: 1px solid var(--border-color); - border-radius: 6px; - color: var(--text-secondary); - cursor: pointer; - font-size: 0.8rem; - transition: all 0.2s; + display: flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-secondary); + cursor: pointer; + font-size: 0.8rem; + transition: all 0.2s; } .copy-btn:hover { - background: var(--bg-card-hover); - color: var(--text-primary); + background: var(--bg-card-hover); + color: var(--text-primary); } .code-block pre { - padding: 24px; - overflow-x: auto; + padding: 24px; + overflow-x: auto; } .code-block code { - font-family: 'JetBrains Mono', 'Fira Code', monospace; - font-size: 0.9rem; - line-height: 1.7; - color: hsl(180, 70%, 70%); + font-family: 'JetBrains Mono', 'Fira Code', monospace; + font-size: 0.9rem; + line-height: 1.7; + color: hsl(180, 70%, 70%); } .quickstart-note { - display: flex; - align-items: center; - gap: 10px; - margin-top: 20px; - padding: 16px; - background: hsla(var(--primary-hue), 100%, 50%, 0.1); - border-radius: var(--radius-md); - font-size: 0.9rem; - color: var(--text-secondary); + display: flex; + align-items: center; + gap: 10px; + margin-top: 20px; + padding: 16px; + background: hsla(var(--primary-hue), 100%, 50%, 0.1); + border-radius: var(--radius-md); + font-size: 0.9rem; + color: var(--text-secondary); } .quickstart-note a { - color: var(--gradient-start); - font-weight: 500; + color: var(--gradient-start); + font-weight: 500; } .quickstart-note svg { - stroke: var(--gradient-start); - flex-shrink: 0; + stroke: var(--gradient-start); + flex-shrink: 0; } /* Documentation Cards */ .docs { - padding: 60px 0; + padding: 60px 0; } .docs-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); - gap: 20px; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 20px; } .doc-card { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - padding: 28px; - background: var(--bg-card); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); - transition: all 0.3s ease; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 12px; + padding: 28px; + background: var(--bg-card); + border-radius: var(--radius-lg); + border: 1px solid var(--border-color); + transition: all 0.3s ease; } .doc-card:hover { - background: var(--bg-card-hover); - transform: translateY(-2px); - border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); + background: var(--bg-card-hover); + transform: translateY(-2px); + border-color: hsla(var(--primary-hue), 100%, 50%, 0.3); } .doc-card svg { - width: 32px; - height: 32px; - stroke: var(--gradient-start); + width: 32px; + height: 32px; + stroke: var(--gradient-start); } .doc-card h4 { - font-weight: 600; - font-size: 1.1rem; + font-weight: 600; + font-size: 1.1rem; } .doc-card p { - color: var(--text-secondary); - font-size: 0.9rem; + color: var(--text-secondary); + font-size: 0.9rem; } /* CTA Section */ .cta { - padding: 80px 0; + padding: 80px 0; } .cta-content { - text-align: center; - max-width: 600px; - margin: 0 auto; - padding: 60px; - background: linear-gradient(135deg, hsla(var(--primary-hue), 100%, 50%, 0.08), hsla(var(--accent-hue), 100%, 50%, 0.05)); - border-radius: var(--radius-xl); - border: 1px solid hsla(var(--primary-hue), 100%, 50%, 0.2); + text-align: center; + max-width: 600px; + margin: 0 auto; + padding: 60px; + background: linear-gradient( + 135deg, + hsla(var(--primary-hue), 100%, 50%, 0.08), + hsla(var(--accent-hue), 100%, 50%, 0.05) + ); + border-radius: var(--radius-xl); + border: 1px solid hsla(var(--primary-hue), 100%, 50%, 0.2); } .cta-content h2 { - font-size: 2rem; - font-weight: 700; - margin-bottom: 12px; + font-size: 2rem; + font-weight: 700; + margin-bottom: 12px; } .cta-content p { - color: var(--text-secondary); - margin-bottom: 32px; + color: var(--text-secondary); + margin-bottom: 32px; } .cta-buttons { - display: flex; - justify-content: center; - gap: 16px; - flex-wrap: wrap; + display: flex; + justify-content: center; + gap: 16px; + flex-wrap: wrap; } .btn-coffee { - background: linear-gradient(135deg, #FFDD00, #FFB700); - color: #000; - font-weight: 700; + background: linear-gradient(135deg, #ffdd00, #ffb700); + color: #000; + font-weight: 700; } .btn-coffee:hover { - transform: translateY(-2px); - box-shadow: 0 8px 30px rgba(255, 221, 0, 0.3); + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(255, 221, 0, 0.3); } /* Footer */ .footer { - padding: 40px 0; - border-top: 1px solid var(--border-color); + padding: 40px 0; + border-top: 1px solid var(--border-color); } .footer-content { - display: flex; - flex-direction: column; - align-items: center; - gap: 20px; - text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + text-align: center; } .footer-brand { - display: flex; - align-items: center; - gap: 8px; - font-weight: 700; - font-size: 1.1rem; + display: flex; + align-items: center; + gap: 8px; + font-weight: 700; + font-size: 1.1rem; } .footer-links { - display: flex; - gap: 24px; + display: flex; + gap: 24px; } .footer-links a { - color: var(--text-secondary); - font-size: 0.9rem; - transition: color 0.2s; + color: var(--text-secondary); + font-size: 0.9rem; + transition: color 0.2s; } .footer-links a:hover { - color: var(--text-primary); + color: var(--text-primary); } .footer-copyright { - color: var(--text-muted); - font-size: 0.85rem; + color: var(--text-muted); + font-size: 0.85rem; } .footer-copyright a { - color: var(--text-secondary); + color: var(--text-secondary); } .footer-copyright a:hover { - color: var(--text-primary); + color: var(--text-primary); } /* Responsive */ @media (max-width: 968px) { - .hero { - grid-template-columns: 1fr; - gap: 40px; - padding-top: 100px; - } + .hero { + grid-template-columns: 1fr; + gap: 40px; + padding-top: 100px; + } - .hero-content { - text-align: center; - max-width: 100%; - } + .hero-content { + text-align: center; + max-width: 100%; + } - .hero-buttons { - justify-content: center; - } + .hero-buttons { + justify-content: center; + } - .hero-stats { - justify-content: center; - } + .hero-stats { + justify-content: center; + } - .browser-mockup { - transform: none; - } + .browser-mockup { + transform: none; + } - .nav-links { - display: none; - } + .nav-links { + display: none; + } } @media (max-width: 640px) { - .hero { - padding: 80px 16px 60px; - } - - section { - padding: 60px 0; - } - - .hero-title { - font-size: 2.25rem; - } - - .hero-buttons { - flex-direction: column; - } - - .btn { - width: 100%; - justify-content: center; - } - - .features-grid { - grid-template-columns: 1fr; - } - - .cta-content { - padding: 40px 24px; - } - - .cta-buttons { - flex-direction: column; - } + .hero { + padding: 80px 16px 60px; + } + + section { + padding: 60px 0; + } + + .hero-title { + font-size: 2.25rem; + } + + .hero-buttons { + flex-direction: column; + } + + .btn { + width: 100%; + justify-content: center; + } + + .features-grid { + grid-template-columns: 1fr; + } + + .cta-content { + padding: 40px 24px; + } + + .cta-buttons { + flex-direction: column; + } } diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..626ca82 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,6 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; +import { defineConfig, globalIgnores } from 'eslint/config'; +import nextVitals from 'eslint-config-next/core-web-vitals'; +import nextTs from 'eslint-config-next/typescript'; const eslintConfig = defineConfig([ ...nextVitals, @@ -8,10 +8,10 @@ const eslintConfig = defineConfig([ // Override default ignores of eslint-config-next. globalIgnores([ // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", + '.next/**', + 'out/**', + 'build/**', + 'next-env.d.ts', ]), ]); diff --git a/next.config.ts b/next.config.ts index 8116173..b0f04cc 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,10 +1,10 @@ -import type { NextConfig } from "next"; -import path from "path"; +import type { NextConfig } from 'next'; +import path from 'path'; const nextConfig: NextConfig = { // Enable standalone output for Docker deployment only when requested // This allows 'next start' to work locally while still supporting optimized Docker images - output: process.env.NEXT_OUTPUT === "standalone" ? "standalone" : undefined, + output: process.env.NEXT_OUTPUT === 'standalone' ? 'standalone' : undefined, // Ensure Next.js uses the correct root for tracing dependencies outputFileTracingRoot: path.join(process.cwd()), @@ -17,21 +17,21 @@ const nextConfig: NextConfig = { return [ { // Images, fonts, and icons - immutable long-term caching - source: "/:path*.(svg|ico|png|jpg|jpeg|gif|webp|woff|woff2|ttf|eot)", + source: '/:path*.(svg|ico|png|jpg|jpeg|gif|webp|woff|woff2|ttf|eot)', headers: [ { - key: "Cache-Control", - value: "public, max-age=31536000, immutable", + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', }, ], }, { // OpenAPI spec - shorter cache with stale-while-revalidate - source: "/openapi.json", + source: '/openapi.json', headers: [ { - key: "Cache-Control", - value: "public, max-age=3600, stale-while-revalidate=86400", + key: 'Cache-Control', + value: 'public, max-age=3600, stale-while-revalidate=86400', }, ], }, @@ -40,5 +40,3 @@ const nextConfig: NextConfig = { }; export default nextConfig; - - diff --git a/package-lock.json b/package-lock.json index dbe78cf..9c3ffd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,17 +40,19 @@ "jspdf": "^4.0.0", "katex": "^0.16.28", "lucide-react": "^0.562.0", - "mermaid": "^11.12.2", - "next": "16.1.5", - "next-pwa": "^5.6.0", + "mermaid": "^11.14.0", + "next": "16.2.2", "next-themes": "^0.4.6", "pdfjs-dist": "^5.4.530", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", "prisma": "^7.3.0", "react": "19.2.3", "react-dom": "19.2.3", "react-pdf": "^10.3.0", "react-resizable-panels": "^4.4.1", "react-zoom-pan-pinch": "^3.7.0", + "recharts": "^3.8.1", "redis": "^5.10.0", "sonner": "^2.0.7", "swagger-ui-dist": "^5.17.14", @@ -68,7 +70,7 @@ "@types/react-dom": "^19", "@types/swagger-ui": "^3.52.2", "eslint": "^9", - "eslint-config-next": "16.1.2", + "eslint-config-next": "16.2.2", "prettier": "^3.8.0", "prettier-plugin-tailwindcss": "^0.7.2", "tailwindcss": "^4", @@ -106,6 +108,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -120,6 +123,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -128,1359 +132,168 @@ "node_modules/@babel/core": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", - "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", - "license": "MIT", - "dependencies": { - "@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/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.6", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", - "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "debug": "^4.4.3", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.11" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", - "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", - "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", - "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", - "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", - "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", - "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", - "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", - "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", - "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", - "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", - "license": "MIT", - "dependencies": { - "@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/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", - "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/template": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", - "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", - "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", - "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", - "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", - "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", - "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", - "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", - "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", - "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", - "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", - "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", - "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", - "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", - "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", - "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "node_modules/@babel/generator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-spread": { + "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", - "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { + "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", - "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { + "node_modules/@babel/helper-validator-option": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "node_modules/@babel/helpers": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", - "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/preset-env": { + "node_modules/@babel/parser": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^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/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.28.6", - "@babel/plugin-syntax-import-attributes": "^7.28.6", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.29.0", - "@babel/plugin-transform-async-to-generator": "^7.28.6", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.6", - "@babel/plugin-transform-class-properties": "^7.28.6", - "@babel/plugin-transform-class-static-block": "^7.28.6", - "@babel/plugin-transform-classes": "^7.28.6", - "@babel/plugin-transform-computed-properties": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.28.6", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.6", - "@babel/plugin-transform-exponentiation-operator": "^7.28.6", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.28.6", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.29.0", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", - "@babel/plugin-transform-numeric-separator": "^7.28.6", - "@babel/plugin-transform-object-rest-spread": "^7.28.6", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.28.6", - "@babel/plugin-transform-optional-chaining": "^7.28.6", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.28.6", - "@babel/plugin-transform-private-property-in-object": "^7.28.6", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.29.0", - "@babel/plugin-transform-regexp-modifiers": "^7.28.6", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.28.6", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.28.6", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.15", - "babel-plugin-polyfill-corejs3": "^0.14.0", - "babel-plugin-polyfill-regenerator": "^0.6.6", - "core-js-compat": "^3.48.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" + "@babel/types": "^7.29.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "bin": { + "parser": "bin/babel-parser.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=6.0.0" } }, "node_modules/@babel/runtime": { @@ -1496,6 +309,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -1510,6 +324,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -1528,6 +343,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -1544,56 +360,77 @@ "license": "MIT" }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.0.3", - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", "license": "MIT" }, "node_modules/@chevrotain/gast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/gast/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", "license": "MIT" }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", "license": "Apache-2.0" }, + "node_modules/@clack/core": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", + "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", + "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", + "license": "MIT", + "dependencies": { + "@clack/core": "0.5.0", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, "node_modules/@codemirror/autocomplete": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", @@ -1706,7 +543,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.1.tgz", "integrity": "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -1752,7 +588,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.4.tgz", "integrity": "sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==", "license": "MIT", - "peer": true, "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } @@ -1774,7 +609,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.11.tgz", "integrity": "sha512-bWdeR8gWM87l4DB/kYSF9A+dVackzDb/V56Tq7QVrQ7rn86W0rgZFtlL3g3pem6AeGcb9NQNoy3ao4WpW4h5tQ==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -1783,31 +617,30 @@ } }, "node_modules/@electric-sql/pglite": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz", - "integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==", - "license": "Apache-2.0", - "peer": true + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz", + "integrity": "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==", + "license": "Apache-2.0" }, "node_modules/@electric-sql/pglite-socket": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.0.20.tgz", - "integrity": "sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.1.tgz", + "integrity": "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==", "license": "Apache-2.0", "bin": { "pglite-server": "dist/scripts/server.js" }, "peerDependencies": { - "@electric-sql/pglite": "0.3.15" + "@electric-sql/pglite": "0.4.1" } }, "node_modules/@electric-sql/pglite-tools": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.2.20.tgz", - "integrity": "sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.1.tgz", + "integrity": "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==", "license": "Apache-2.0", "peerDependencies": { - "@electric-sql/pglite": "0.3.15" + "@electric-sql/pglite": "0.4.1" } }, "node_modules/@emnapi/core": { @@ -2026,9 +859,9 @@ "license": "MIT" }, "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", "license": "MIT", "engines": { "node": ">=18.14.1" @@ -2576,6 +1409,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -2586,6 +1420,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2596,37 +1431,36 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@lezer/common": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.0.tgz", @@ -2723,72 +1557,12 @@ "license": "MIT" }, "node_modules/@mermaid-js/parser": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz", - "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==", - "license": "MIT", - "dependencies": { - "langium": "3.3.1" - } - }, - "node_modules/@mrleebo/prisma-ast": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.13.1.tgz", - "integrity": "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.0.tgz", + "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==", "license": "MIT", "dependencies": { - "chevrotain": "^10.5.0", - "lilconfig": "^2.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@mrleebo/prisma-ast/node_modules/@chevrotain/cst-dts-gen": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz", - "integrity": "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "10.5.0", - "@chevrotain/types": "10.5.0", - "lodash": "4.17.21" - } - }, - "node_modules/@mrleebo/prisma-ast/node_modules/@chevrotain/gast": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.5.0.tgz", - "integrity": "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "10.5.0", - "lodash": "4.17.21" - } - }, - "node_modules/@mrleebo/prisma-ast/node_modules/@chevrotain/types": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.5.0.tgz", - "integrity": "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==", - "license": "Apache-2.0" - }, - "node_modules/@mrleebo/prisma-ast/node_modules/@chevrotain/utils": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.5.0.tgz", - "integrity": "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==", - "license": "Apache-2.0" - }, - "node_modules/@mrleebo/prisma-ast/node_modules/chevrotain": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", - "integrity": "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/cst-dts-gen": "10.5.0", - "@chevrotain/gast": "10.5.0", - "@chevrotain/types": "10.5.0", - "@chevrotain/utils": "10.5.0", - "lodash": "4.17.21", - "regexp-to-ast": "0.5.0" + "langium": "^4.0.0" } }, "node_modules/@napi-rs/canvas": { @@ -3055,15 +1829,15 @@ } }, "node_modules/@next/env": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.5.tgz", - "integrity": "sha512-CRSCPJiSZoi4Pn69RYBDI9R7YK2g59vLexPQFXY0eyw+ILevIenCywzg+DqmlBik9zszEnw2HLFOUlLAcJbL7g==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.2.tgz", + "integrity": "sha512-LqSGz5+xGk9EL/iBDr2yo/CgNQV6cFsNhRR2xhSXYh7B/hb4nePCxlmDvGEKG30NMHDFf0raqSyOZiQrO7BkHQ==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.2.tgz", - "integrity": "sha512-jjO5BKDxZEXt2VCAnAG/ldULnpxeXspjCo9AZErV3Lm5HmNj8r2rS+eUMIAAj6mXPAOiPqAMgVPGnkyhPyDx4g==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.2.tgz", + "integrity": "sha512-IOPbWzDQ+76AtjZioaCjpIY72xNSDMnarZ2GMQ4wjNLvnJEJHqxQwGFhgnIWLV9klb4g/+amg88Tk5OXVpyLTw==", "dev": true, "license": "MIT", "dependencies": { @@ -3071,9 +1845,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.5.tgz", - "integrity": "sha512-eK7Wdm3Hjy/SCL7TevlH0C9chrpeOYWx2iR7guJDaz4zEQKWcS1IMVfMb9UKBFMg1XgzcPTYPIp1Vcpukkjg6Q==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.2.tgz", + "integrity": "sha512-B92G3ulrwmkDSEJEp9+XzGLex5wC1knrmCSIylyVeiAtCIfvEJYiN3v5kXPlYt5R4RFlsfO/v++aKV63Acrugg==", "cpu": [ "arm64" ], @@ -3087,9 +1861,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.5.tgz", - "integrity": "sha512-foQscSHD1dCuxBmGkbIr6ScAUF6pRoDZP6czajyvmXPAOFNnQUJu2Os1SGELODjKp/ULa4fulnBWoHV3XdPLfA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.2.tgz", + "integrity": "sha512-7ZwSgNKJNQiwW0CKhNm9B1WS2L1Olc4B2XY0hPYCAL3epFnugMhuw5TMWzMilQ3QCZcCHoYm9NGWTHbr5REFxw==", "cpu": [ "x64" ], @@ -3103,9 +1877,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.5.tgz", - "integrity": "sha512-qNIb42o3C02ccIeSeKjacF3HXotGsxh/FMk/rSRmCzOVMtoWH88odn2uZqF8RLsSUWHcAqTgYmPD3pZ03L9ZAA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.2.tgz", + "integrity": "sha512-c3m8kBHMziMgo2fICOP/cd/5YlrxDU5YYjAJeQLyFsCqVF8xjOTH/QYG4a2u48CvvZZSj1eHQfBCbyh7kBr30Q==", "cpu": [ "arm64" ], @@ -3119,9 +1893,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.5.tgz", - "integrity": "sha512-U+kBxGUY1xMAzDTXmuVMfhaWUZQAwzRaHJ/I6ihtR5SbTVUEaDRiEU9YMjy1obBWpdOBuk1bcm+tsmifYSygfw==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.2.tgz", + "integrity": "sha512-VKLuscm0P/mIfzt+SDdn2+8TNNJ7f0qfEkA+az7OqQbjzKdBxAHs0UvuiVoCtbwX+dqMEL9U54b5wQ/aN3dHeg==", "cpu": [ "arm64" ], @@ -3135,9 +1909,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.5.tgz", - "integrity": "sha512-gq2UtoCpN7Ke/7tKaU7i/1L7eFLfhMbXjNghSv0MVGF1dmuoaPeEVDvkDuO/9LVa44h5gqpWeJ4mRRznjDv7LA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.2.tgz", + "integrity": "sha512-kU3OPHJq6sBUjOk7wc5zJ7/lipn8yGldMoAv4z67j6ov6Xo/JvzA7L7LCsyzzsXmgLEhk3Qkpwqaq/1+XpNR3g==", "cpu": [ "x64" ], @@ -3151,9 +1925,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.5.tgz", - "integrity": "sha512-bQWSE729PbXT6mMklWLf8dotislPle2L70E9q6iwETYEOt092GDn0c+TTNj26AjmeceSsC4ndyGsK5nKqHYXjQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.2.tgz", + "integrity": "sha512-CKXRILyErMtUftp+coGcZ38ZwE/Aqq45VMCcRLr2I4OXKrgxIBDXHnBgeX/UMil0S09i2JXaDL3Q+TN8D/cKmg==", "cpu": [ "x64" ], @@ -3167,9 +1941,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.5.tgz", - "integrity": "sha512-LZli0anutkIllMtTAWZlDqdfvjWX/ch8AFK5WgkNTvaqwlouiD1oHM+WW8RXMiL0+vAkAJyAGEzPPjO+hnrSNQ==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.2.tgz", + "integrity": "sha512-sS/jSk5VUoShUqINJFvNjVT7JfR5ORYj/+/ZpOYbbIohv/lQfduWnGAycq2wlknbOql2xOR0DoV0s6Xfcy49+g==", "cpu": [ "arm64" ], @@ -3183,9 +1957,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.5.tgz", - "integrity": "sha512-7is37HJTNQGhjPpQbkKjKEboHYQnCgpVt/4rBrrln0D9nderNxZ8ZWs8w1fAtzUx7wEyYjQ+/13myFgFj6K2Ng==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.2.tgz", + "integrity": "sha512-aHaKceJgdySReT7qeck5oShucxWRiiEuwCGK8HHALe6yZga8uyFpLkPgaRw3kkF04U7ROogL/suYCNt/+CuXGA==", "cpu": [ "x64" ], @@ -3202,6 +1976,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -3215,6 +1990,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -3224,6 +2000,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -3243,6 +2020,12 @@ "node": ">=12.4.0" } }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, "node_modules/@prisma/adapter-better-sqlite3": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@prisma/adapter-better-sqlite3/-/adapter-better-sqlite3-7.2.0.tgz", @@ -3295,14 +2078,14 @@ "license": "Apache-2.0" }, "node_modules/@prisma/config": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.3.0.tgz", - "integrity": "sha512-QyMV67+eXF7uMtKxTEeQqNu/Be7iH+3iDZOQZW5ttfbSwBamCSdwPszA0dum+Wx27I7anYTPLmRmMORKViSW1A==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.6.0.tgz", + "integrity": "sha512-MuAz1MK4PeG5/03YzfzX3CnFVHQ6qePGwUpQRzPzX5tT0ffJ3Tzi9zJZbBc+VzEGFCM8ghW/gTVDR85Syjt+Yw==", "license": "Apache-2.0", "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", - "effect": "3.18.4", + "effect": "3.20.0", "empathic": "2.0.0" } }, @@ -3313,21 +2096,21 @@ "license": "Apache-2.0" }, "node_modules/@prisma/dev": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.20.0.tgz", - "integrity": "sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ==", + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.3.tgz", + "integrity": "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==", "license": "ISC", "dependencies": { - "@electric-sql/pglite": "0.3.15", - "@electric-sql/pglite-socket": "0.0.20", - "@electric-sql/pglite-tools": "0.2.20", - "@hono/node-server": "1.19.9", - "@mrleebo/prisma-ast": "0.13.1", + "@electric-sql/pglite": "0.4.1", + "@electric-sql/pglite-socket": "0.1.1", + "@electric-sql/pglite-tools": "0.3.1", + "@hono/node-server": "1.19.11", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", + "@prisma/streams-local": "0.1.2", "foreground-child": "3.3.1", "get-port-please": "3.2.0", - "hono": "4.11.4", + "hono": "^4.12.8", "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", @@ -3347,63 +2130,63 @@ } }, "node_modules/@prisma/engines": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.3.0.tgz", - "integrity": "sha512-cWRQoPDXPtR6stOWuWFZf9pHdQ/o8/QNWn0m0zByxf5Kd946Q875XdEJ52pEsX88vOiXUmjuPG3euw82mwQNMg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.6.0.tgz", + "integrity": "sha512-Sn5edRzhHqgRV2M+A0eIbY442B4mReWWf3pKs/LKreYgW7oa/up8JtK/s4iv/EQA097cyboZ08mmkpbLp+tZ3w==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.3.0", - "@prisma/engines-version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", - "@prisma/fetch-engine": "7.3.0", - "@prisma/get-platform": "7.3.0" + "@prisma/debug": "7.6.0", + "@prisma/engines-version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711", + "@prisma/fetch-engine": "7.6.0", + "@prisma/get-platform": "7.6.0" } }, "node_modules/@prisma/engines-version": { - "version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735.tgz", - "integrity": "sha512-IH2va2ouUHihyiTTRW889LjKAl1CusZOvFfZxCDNpjSENt7g2ndFsK0vdIw/72v7+jCN6YgkHmdAP/BI7SDgyg==", + "version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711.tgz", + "integrity": "sha512-r51DLcJ8bDRSrBEJF3J4cinoWyGA7rfP2mG6lD90VqIbGNOkbfcLcXalSVjq5Y6brQS3vcjrq4GbyUb1Cb7vkw==", "license": "Apache-2.0" }, "node_modules/@prisma/engines/node_modules/@prisma/debug": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.3.0.tgz", - "integrity": "sha512-yh/tHhraCzYkffsI1/3a7SHX8tpgbJu1NPnuxS4rEpJdWAUDHUH25F1EDo6PPzirpyLNkgPPZdhojQK804BGtg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.6.0.tgz", + "integrity": "sha512-LpHr3qos4lQZ6sxwjStf59YBht7m9/QF7NSQsMH6qGENWZu2w3UkQUGn1h5iRkDjnWRj3VHykOu9qFhps4ADvA==", "license": "Apache-2.0" }, "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.3.0.tgz", - "integrity": "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.6.0.tgz", + "integrity": "sha512-ohZDwXvtmnbzOcutR2D13lDWpZP1wQjmPyztmt0AwXLzQI7q95EE7NYCvS+M6N6SivT+BM0NOqLmTH3wms4L3A==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.3.0" + "@prisma/debug": "7.6.0" } }, "node_modules/@prisma/fetch-engine": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.3.0.tgz", - "integrity": "sha512-Mm0F84JMqM9Vxk70pzfNpGJ1lE4hYjOeLMu7nOOD1i83nvp8MSAcFYBnHqLvEZiA6onUR+m8iYogtOY4oPO5lQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.6.0.tgz", + "integrity": "sha512-N575Ni95c3FkduWY/eKTHqNYgNbceZ1tQaSknVtJjpKmiiBXmniESn/GTxsDvICC4ZeiNrXxioGInzQrCdx16w==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.3.0", - "@prisma/engines-version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", - "@prisma/get-platform": "7.3.0" + "@prisma/debug": "7.6.0", + "@prisma/engines-version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711", + "@prisma/get-platform": "7.6.0" } }, "node_modules/@prisma/fetch-engine/node_modules/@prisma/debug": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.3.0.tgz", - "integrity": "sha512-yh/tHhraCzYkffsI1/3a7SHX8tpgbJu1NPnuxS4rEpJdWAUDHUH25F1EDo6PPzirpyLNkgPPZdhojQK804BGtg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.6.0.tgz", + "integrity": "sha512-LpHr3qos4lQZ6sxwjStf59YBht7m9/QF7NSQsMH6qGENWZu2w3UkQUGn1h5iRkDjnWRj3VHykOu9qFhps4ADvA==", "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.3.0.tgz", - "integrity": "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.6.0.tgz", + "integrity": "sha512-ohZDwXvtmnbzOcutR2D13lDWpZP1wQjmPyztmt0AwXLzQI7q95EE7NYCvS+M6N6SivT+BM0NOqLmTH3wms4L3A==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.3.0" + "@prisma/debug": "7.6.0" } }, "node_modules/@prisma/get-platform": { @@ -3421,11 +2204,57 @@ "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", "license": "Apache-2.0" }, + "node_modules/@prisma/streams-local": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.2.tgz", + "integrity": "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==", + "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.12.0", + "better-result": "^2.7.0", + "env-paths": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "engines": { + "bun": ">=1.3.6", + "node": ">=22.0.0" + } + }, + "node_modules/@prisma/streams-local/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@prisma/streams-local/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/@prisma/studio-core": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.13.1.tgz", - "integrity": "sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.27.3.tgz", + "integrity": "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==", "license": "Apache-2.0", + "dependencies": { + "@radix-ui/react-toggle": "1.1.10", + "chart.js": "4.5.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0", + "pnpm": "8" + }, "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", @@ -4115,9 +2944,39 @@ "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "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 + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", @@ -4134,19 +2993,14 @@ } } }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { @@ -4398,7 +3252,6 @@ "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.10.0.tgz", "integrity": "sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==", "license": "MIT", - "peer": true, "dependencies": { "cluster-key-slot": "1.1.2" }, @@ -4442,105 +3295,53 @@ "@redis/client": "^5.10.0" } }, - "node_modules/@replit/codemirror-indentation-markers": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/@replit/codemirror-indentation-markers/-/codemirror-indentation-markers-6.5.3.tgz", - "integrity": "sha512-hL5Sfvw3C1vgg7GolLe/uxX5T3tmgOA3ZzqlMv47zjU1ON51pzNWiVbS22oh6crYhtVhv8b3gdXwoYp++2ilHw==", - "license": "MIT", - "peerDependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "peerDependenciesMeta": { - "@types/babel__core": { + "react": { + "optional": true + }, + "react-redux": { "optional": true } } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", "license": "MIT", - "dependencies": { - "sourcemap-codec": "^1.4.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@replit/codemirror-indentation-markers": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/@replit/codemirror-indentation-markers/-/codemirror-indentation-markers-6.5.3.tgz", + "integrity": "sha512-hL5Sfvw3C1vgg7GolLe/uxX5T3tmgOA3ZzqlMv47zjU1ON51pzNWiVbS22oh6crYhtVhv8b3gdXwoYp++2ilHw==", "license": "MIT", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" } }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "license": "MIT" - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -4561,26 +3362,11 @@ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "license": "MIT" }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "license": "Apache-2.0", - "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "license": "MIT", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" }, "node_modules/@swc/helpers": { "version": "0.5.15", @@ -5186,30 +3972,11 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, "node_modules/@types/geojson": { @@ -5218,20 +3985,11 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -5254,16 +4012,11 @@ "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", "license": "MIT" }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "license": "MIT" - }, "node_modules/@types/node": { "version": "20.19.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.29.tgz", "integrity": "sha512-YrT9ArrGaHForBaCNwFjoqJWmn8G1Pr7+BH/vwyLHciA9qT/wSiuOhxGCT50JA5xLvFBd6PIiGkE3afxcPE1nw==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5287,7 +4040,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5298,20 +4050,10 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/swagger-ui": { "version": "3.52.4", "resolved": "https://registry.npmjs.org/@types/swagger-ui/-/swagger-ui-3.52.4.tgz", @@ -5323,6 +4065,13 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -5370,7 +4119,6 @@ "integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/types": "8.53.0", @@ -5515,9 +4263,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -5525,13 +4273,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -5948,170 +4696,21 @@ "win32" ] }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "license": "MIT", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0" - }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6119,18 +4718,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -6142,11 +4729,11 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6158,54 +4745,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6255,6 +4794,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6290,24 +4830,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -6410,6 +4932,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -6434,34 +4957,30 @@ "dev": true, "license": "MIT" }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, - "node_modules/at-least-node": { + "node_modules/atomic-sleep": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "license": "ISC", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", "engines": { - "node": ">= 4.0.0" + "node": ">=8.0.0" } }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -6502,68 +5021,11 @@ "node": ">= 0.4" } }, - "node_modules/babel-loader": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", - "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", - "license": "MIT", - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.4", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", - "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.6", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", - "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6", - "core-js-compat": "^3.48.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", - "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/base64-arraybuffer": { @@ -6597,12 +5059,27 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", - "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", + "version": "2.10.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.14.tgz", + "integrity": "sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/better-result": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.7.0.tgz", + "integrity": "sha512-7zrmXjAK8u8Z6SOe4R65XObOR5X+Y2I/VVku3t5cPOGQ8/WsBcfFmfnIPiEl5EBMDOzPHRwbiPbMtQBKYdw7RA==", + "license": "MIT", + "dependencies": { + "@clack/prompts": "^0.11.0" + }, + "bin": { + "better-result": "bin/cli.mjs" } }, "node_modules/better-sqlite3": { @@ -6619,15 +5096,6 @@ "node": "20.x || 22.x || 23.x || 24.x || 25.x" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -6673,9 +5141,10 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -6686,6 +5155,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -6698,6 +5168,7 @@ "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -6713,7 +5184,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -6728,24 +5198,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/c12": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", @@ -6795,6 +5247,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -6813,6 +5266,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -6826,6 +5280,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -6905,18 +5360,30 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chevrotain": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", "license": "Apache-2.0", "dependencies": { - "@chevrotain/cst-dts-gen": "11.0.3", - "@chevrotain/gast": "11.0.3", - "@chevrotain/regexp-to-ast": "11.0.3", - "@chevrotain/types": "11.0.3", - "@chevrotain/utils": "11.0.3", - "lodash-es": "4.17.21" + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", + "lodash-es": "4.17.23" } }, "node_modules/chevrotain-allstar": { @@ -6932,9 +5399,9 @@ } }, "node_modules/chevrotain/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", "license": "MIT" }, "node_modules/chokidar": { @@ -6958,15 +5425,6 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "license": "ISC" }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, "node_modules/citty": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", @@ -6988,21 +5446,6 @@ "url": "https://polar.sh/cva" } }, - "node_modules/clean-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", - "license": "MIT", - "dependencies": { - "del": "^4.1.1" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": ">=4.0.0 <6.0.0" - } - }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -7073,6 +5516,12 @@ "dev": true, "license": "MIT" }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -7082,25 +5531,11 @@ "node": ">= 10" } }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/confbox": { @@ -7122,6 +5557,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/core-js": { @@ -7136,19 +5572,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", - "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/cose-base": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", @@ -7178,15 +5601,6 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/css-line-break": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", @@ -7208,7 +5622,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -7609,7 +6022,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -7695,9 +6107,9 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "license": "MIT", "dependencies": { "d3": "^7.9.0", @@ -7715,6 +6127,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -7732,6 +6145,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -7749,6 +6163,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -7772,6 +6187,15 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/dayjs": { "version": "1.11.19", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", @@ -7782,6 +6206,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -7795,6 +6220,12 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -7826,15 +6257,6 @@ "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/deepmerge-ts": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", @@ -7848,6 +6270,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -7865,6 +6288,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -7879,70 +6303,15 @@ } }, "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.6.tgz", + "integrity": "sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug==", "license": "MIT" }, - "node_modules/del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", - "license": "MIT", - "dependencies": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" @@ -7987,18 +6356,6 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -8013,9 +6370,9 @@ } }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -8037,6 +6394,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -8048,34 +6406,20 @@ } }, "node_modules/effect": { - "version": "3.18.4", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", - "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz", + "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.267", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -8085,15 +6429,6 @@ "dev": true, "license": "MIT" }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/empathic": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", @@ -8113,9 +6448,10 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -8125,10 +6461,23 @@ "node": ">=10.13.0" } }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/es-abstract": { "version": "1.24.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -8197,6 +6546,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8206,6 +6556,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8239,16 +6590,11 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "license": "MIT" - }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -8261,6 +6607,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8289,6 +6636,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7", @@ -8302,10 +6650,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", + "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8330,7 +6689,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8386,13 +6744,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.2.tgz", - "integrity": "sha512-y97rpFfUsaXdXlQc2FMl/yqRc5yfVVKtKRcv+7LeyBrKh83INFegJuZBE28dc9Chp4iKXwmjaW4sHHx/mgyDyA==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.2.tgz", + "integrity": "sha512-6VlvEhwoug2JpVgjZDhyXrJXUEuPY++TddzIpTaIRvlvlXXFgvQUtm3+Zr84IjFm0lXtJt73w19JA08tOaZVwg==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.1.2", + "@next/eslint-plugin-next": "16.2.2", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -8516,7 +6874,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8721,6 +7078,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -8733,34 +7091,27 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "license": "MIT" - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" }, "node_modules/expand-template": { "version": "2.0.3", @@ -8799,6 +7150,12 @@ "node": ">=8.0.0" } }, + "node_modules/fast-copy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", + "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8809,6 +7166,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -8825,6 +7183,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -8837,6 +7196,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -8857,6 +7217,12 @@ "pako": "^2.1.0" } }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -8877,6 +7243,7 @@ "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -8907,40 +7274,11 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "license": "MIT" }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -8949,23 +7287,6 @@ "node": ">=8" } }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8998,9 +7319,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -9008,6 +7329,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -9068,45 +7390,11 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "license": "MIT" }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9116,6 +7404,7 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -9136,6 +7425,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9154,6 +7444,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9163,6 +7454,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -9172,6 +7464,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -9199,13 +7492,7 @@ "license": "MIT", "engines": { "node": ">=6" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "license": "ISC" + } }, "node_modules/get-port-please": { "version": "3.2.0", @@ -9217,6 +7504,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -9230,6 +7518,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -9279,27 +7568,6 @@ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "license": "MIT" }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "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", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -9313,12 +7581,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause" - }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -9336,6 +7598,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -9348,30 +7611,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9393,9 +7637,10 @@ "license": "MIT" }, "node_modules/graphmatch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.0.tgz", - "integrity": "sha512-0E62MaTW5rPZVRLyIJZG/YejmdA/Xr1QydHEw3Vt+qOKkMIOE8WDLc9ZX2bmAjtJFZcId4lEdrdmASsEy7D1QA==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz", + "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==", + "license": "MIT" }, "node_modules/hachure-fill": { "version": "0.5.2", @@ -9407,6 +7652,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9419,6 +7665,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9428,6 +7675,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -9440,6 +7688,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.0" @@ -9455,6 +7704,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9467,6 +7717,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -9482,6 +7733,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -9490,6 +7742,12 @@ "node": ">= 0.4" } }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -9508,11 +7766,10 @@ } }, "node_modules/hono": { - "version": "4.11.5", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.5.tgz", - "integrity": "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==", + "version": "4.12.10", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.10.tgz", + "integrity": "sha512-mx/p18PLy5og9ufies2GOSUqep98Td9q4i/EF6X7yJgAiIopxqdfIO3jbqsi3jRgTgw88jMDEzVKi+V2EF+27w==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -9549,12 +7806,6 @@ "node": ">=0.10.0" } }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "license": "ISC" - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -9579,11 +7830,22 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -9611,17 +7873,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -9638,6 +7889,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9667,6 +7919,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -9684,6 +7937,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, "license": "MIT", "dependencies": { "async-function": "^1.0.0", @@ -9703,6 +7957,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -9718,6 +7973,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -9757,6 +8013,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9769,6 +8026,7 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -9784,6 +8042,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9801,6 +8060,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9817,6 +8077,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9826,6 +8087,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -9841,6 +8103,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -9860,6 +8123,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -9872,6 +8136,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9880,16 +8145,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "license": "MIT" - }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9902,6 +8162,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -9911,6 +8172,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -9923,48 +8185,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "license": "MIT", - "dependencies": { - "is-path-inside": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "license": "MIT", - "dependencies": { - "path-is-inside": "^1.0.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -9975,6 +8195,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9989,19 +8210,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10014,6 +8227,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -10025,22 +8239,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -10057,6 +8260,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10074,6 +8278,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -10089,6 +8294,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10101,6 +8307,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -10116,6 +8323,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -10132,6 +8340,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -10158,52 +8367,6 @@ "node": ">= 0.4" } }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -10213,6 +8376,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10236,6 +8408,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -10251,22 +8424,11 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -10280,6 +8442,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -10288,41 +8451,20 @@ "node": ">=6" } }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jspdf": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.0.0.tgz", - "integrity": "sha512-w12U97Z6edKd2tXDn3LzTLg7C7QLJlx0BPfM3ecjK2BckUl9/81vZ+r5gK4/3KQdhAcEZhENUxRhtgYBj75MqQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.2.1.tgz", + "integrity": "sha512-YyAXyvnmjTbR4bHQRLzex3CuINCDlQnBqoSYyjJwTP2x9jDLuKDzy7aKUl0hgx3uhcl7xzg32agn5vlie6HIlQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.28.4", + "@babel/runtime": "^7.28.6", "fast-png": "^6.2.0", "fflate": "^0.8.1" }, "optionalDependencies": { "canvg": "^3.0.11", "core-js": "^3.6.0", - "dompurify": "^3.2.4", + "dompurify": "^3.3.1", "html2canvas": "^1.0.0-rc.5" } }, @@ -10383,19 +8525,20 @@ "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" }, "node_modules/langium": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", - "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", "license": "MIT", "dependencies": { - "chevrotain": "~11.0.3", - "chevrotain-allstar": "~0.3.0", + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.0.8" + "vscode-uri": "~3.1.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/language-subtag-registry": { @@ -10424,15 +8567,6 @@ "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", "license": "MIT" }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -10708,42 +8842,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "license": "MIT", - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -10760,16 +8858,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, "node_modules/lodash-es": { - "version": "4.17.22", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz", - "integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -10785,12 +8877,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "license": "MIT" - }, "node_modules/long": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", @@ -10813,6 +8899,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -10861,21 +8948,6 @@ "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/make-event-props": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-2.0.0.tgz", @@ -10901,6 +8973,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10923,81 +8996,57 @@ } } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/mermaid": { - "version": "11.12.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz", - "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", + "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^0.6.3", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.0", "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "katex": "^0.16.25", "khroma": "^2.1.0", - "lodash-es": "^4.17.21", - "marked": "^16.2.1", + "lodash-es": "^4.17.23", + "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", - "ts-dedent": "^2.2.0", - "uuid": "^11.1.0" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 0.6" + "node": ">=8.6" } }, "node_modules/mimic-response": { @@ -11013,9 +9062,10 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -11070,6 +9120,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/mysql2": { @@ -11167,21 +9218,15 @@ "dev": true, "license": "MIT" }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" - }, "node_modules/next": { - "version": "16.1.5", - "resolved": "https://registry.npmjs.org/next/-/next-16.1.5.tgz", - "integrity": "sha512-f+wE+NSbiQgh3DSAlTaw2FwY5yGdVViAtp8TotNQj4kk4Q8Bh1sC/aL9aH+Rg1YAVn18OYXsRDT7U/079jgP7w==", + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.2.tgz", + "integrity": "sha512-i6AJdyVa4oQjyvX/6GeER8dpY/xlIV+4NMv/svykcLtURJSy/WzDnnUk/TM4d0uewFHK7xSQz4TbIwPgjky+3A==", "license": "MIT", "dependencies": { - "@next/env": "16.1.5", + "@next/env": "16.2.2", "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.8.3", + "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -11193,15 +9238,15 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.1.5", - "@next/swc-darwin-x64": "16.1.5", - "@next/swc-linux-arm64-gnu": "16.1.5", - "@next/swc-linux-arm64-musl": "16.1.5", - "@next/swc-linux-x64-gnu": "16.1.5", - "@next/swc-linux-x64-musl": "16.1.5", - "@next/swc-win32-arm64-msvc": "16.1.5", - "@next/swc-win32-x64-msvc": "16.1.5", - "sharp": "^0.34.4" + "@next/swc-darwin-arm64": "16.2.2", + "@next/swc-darwin-x64": "16.2.2", + "@next/swc-linux-arm64-gnu": "16.2.2", + "@next/swc-linux-arm64-musl": "16.2.2", + "@next/swc-linux-x64-gnu": "16.2.2", + "@next/swc-linux-x64-musl": "16.2.2", + "@next/swc-win32-arm64-msvc": "16.2.2", + "@next/swc-win32-x64-msvc": "16.2.2", + "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -11226,23 +9271,6 @@ } } }, - "node_modules/next-pwa": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/next-pwa/-/next-pwa-5.6.0.tgz", - "integrity": "sha512-XV8g8C6B7UmViXU8askMEYhWwQ4qc/XqJGnexbLV68hzKaGHZDMtHsm2TNxFcbR7+ypVuth/wwpiIlMwpRJJ5A==", - "license": "MIT", - "dependencies": { - "babel-loader": "^8.2.5", - "clean-webpack-plugin": "^4.0.0", - "globby": "^11.0.4", - "terser-webpack-plugin": "^5.3.3", - "workbox-webpack-plugin": "^6.5.4", - "workbox-window": "^6.5.4" - }, - "peerDependencies": { - "next": ">=9.0.0" - } - }, "node_modules/next-themes": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", @@ -11315,6 +9343,7 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, "license": "MIT" }, "node_modules/nypm": { @@ -11357,6 +9386,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11366,6 +9396,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11378,6 +9409,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11387,6 +9419,7 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -11478,6 +9511,15 @@ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", "license": "MIT" }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -11509,6 +9551,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.6", @@ -11554,24 +9597,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/package-manager-detector": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", @@ -11607,26 +9632,12 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "license": "(WTFPL OR MIT)" - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -11640,17 +9651,9 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, "license": "MIT" }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -11687,7 +9690,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.17.1.tgz", "integrity": "sha512-EIR+jXdYNSMOrpRp7g6WgQr7SaZNZfS7IzZIO0oTNEeibq956JxeD15t3Jk3zZH0KH8DmOIx38qJfQenoE8bXQ==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.10.0", "pg-pool": "^3.11.0", @@ -11788,9 +9790,10 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -11799,99 +9802,78 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "license": "MIT", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", "license": "MIT", "dependencies": { - "find-up": "^4.0.0" + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" }, - "engines": { - "node": ">=8" + "bin": { + "pino": "bin.js" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" + "split2": "^4.0.0" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" }, - "engines": { - "node": ">=8" + "bin": { + "pino-pretty": "bin.js" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/pino-pretty/node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" }, "node_modules/pkg-types": { "version": "1.3.1", @@ -11924,6 +9906,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -12052,7 +10035,6 @@ "integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -12142,30 +10124,17 @@ } } }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/prisma": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.3.0.tgz", - "integrity": "sha512-ApYSOLHfMN8WftJA+vL6XwAPOh/aZ0BgUyyKPwUFgjARmG6EBI9LzDPf6SWULQMSAxydV9qn5gLj037nPNlg2w==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.6.0.tgz", + "integrity": "sha512-OKJIPT81K3+F+AayIkY/Y3mkF2NWoFh7lZApaaqPYy7EHILKdO0VsmGkP+hDKYTySHsFSyLWXm/JgcR1B8fY1Q==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { - "@prisma/config": "7.3.0", - "@prisma/dev": "0.20.0", - "@prisma/engines": "7.3.0", - "@prisma/studio-core": "0.13.1", + "@prisma/config": "7.6.0", + "@prisma/dev": "0.24.3", + "@prisma/engines": "7.6.0", + "@prisma/studio-core": "0.27.3", "mysql2": "3.15.3", "postgres": "3.4.7" }, @@ -12188,6 +10157,22 @@ } } }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -12231,6 +10216,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12256,6 +10242,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -12272,6 +10259,12 @@ ], "license": "MIT" }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -12282,15 +10275,6 @@ "performance-now": "^2.1.0" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -12330,7 +10314,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -12340,7 +10323,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -12352,7 +10334,6 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, "node_modules/react-pdf": { @@ -12396,6 +10377,29 @@ "@napi-rs/canvas": "^0.1.80" } }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-remove-scroll": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", @@ -12516,6 +10520,45 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/recharts": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.1.tgz", + "integrity": "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/redis": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/redis/-/redis-5.10.0.tgz", @@ -12532,10 +10575,26 @@ "node": ">= 18" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -12554,24 +10613,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -12579,16 +10620,11 @@ "license": "MIT", "optional": true }, - "node_modules/regexp-to-ast": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "license": "MIT" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -12605,41 +10641,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, "node_modules/remeda": { "version": "2.33.4", "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", @@ -12658,10 +10659,17 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -12711,6 +10719,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -12719,87 +10728,19 @@ }, "node_modules/rgbcolor": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", - "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", - "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", - "optional": true, - "engines": { - "node": ">= 0.8.15" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "license": "Unlicense" - }, - "node_modules/rollup": { - "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", - "license": "MIT", - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", + "optional": true, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.8.15" } }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" }, "node_modules/roughjs": { "version": "4.6.6", @@ -12817,6 +10758,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -12846,6 +10788,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -12885,6 +10828,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -12901,6 +10845,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -12914,6 +10859,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -12926,28 +10880,27 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, - "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12958,19 +10911,11 @@ "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -12988,6 +10933,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -13003,6 +10949,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -13096,6 +11043,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -13115,6 +11063,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -13131,6 +11080,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -13149,6 +11099,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -13221,13 +11172,19 @@ "simple-concat": "^1.0.0" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "atomic-sleep": "^1.0.0" } }, "node_modules/sonner": { @@ -13240,21 +11197,6 @@ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "license": "MIT" - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -13264,23 +11206,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "license": "MIT" - }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -13326,6 +11251,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -13363,6 +11289,7 @@ "version": "4.0.12", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13401,6 +11328,7 @@ "version": "1.2.10", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13422,6 +11350,7 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13440,6 +11369,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -13453,20 +11383,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "license": "BSD-2-Clause", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -13477,15 +11393,6 @@ "node": ">=4" } }, - "node_modules/strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -13538,6 +11445,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -13550,6 +11458,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -13598,6 +11507,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -13635,145 +11545,6 @@ "node": ">=6" } }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "license": "MIT", - "dependencies": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, "node_modules/text-segmentation": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", @@ -13784,6 +11555,18 @@ "utrie": "^1.0.2" } }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -13835,12 +11618,11 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13852,6 +11634,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -13860,15 +11643,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -13958,22 +11732,11 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -13988,6 +11751,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -14007,6 +11771,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -14028,6 +11793,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -14050,7 +11816,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14093,86 +11858,27 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "license": "MIT", - "dependencies": { - "crypto-random-string": "^2.0.0" + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" }, "node_modules/unrs-resolver": { "version": "1.11.1", @@ -14209,20 +11915,11 @@ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "license": "MIT", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -14253,6 +11950,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -14301,6 +11999,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/usehooks-ts": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz", @@ -14359,6 +12066,28 @@ } } }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -14403,9 +12132,9 @@ "license": "MIT" }, "node_modules/vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "license": "MIT" }, "node_modules/w3c-keyname": { @@ -14423,170 +12152,6 @@ "loose-envify": "^1.0.0" } }, - "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", - "license": "MIT", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "license": "BSD-2-Clause" - }, - "node_modules/webpack": { - "version": "5.105.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", - "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.28.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.19.0", - "es-module-lexer": "^2.0.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", - "watchpack": "^2.5.1", - "webpack-sources": "^3.3.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "license": "MIT", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -14606,6 +12171,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -14625,6 +12191,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -14652,6 +12219,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -14670,6 +12238,7 @@ "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -14697,281 +12266,6 @@ "node": ">=0.10.0" } }, - "node_modules/workbox-background-sync": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", - "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", - "license": "MIT", - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-broadcast-update": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", - "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-build": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", - "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", - "license": "MIT", - "dependencies": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.6.0", - "workbox-broadcast-update": "6.6.0", - "workbox-cacheable-response": "6.6.0", - "workbox-core": "6.6.0", - "workbox-expiration": "6.6.0", - "workbox-google-analytics": "6.6.0", - "workbox-navigation-preload": "6.6.0", - "workbox-precaching": "6.6.0", - "workbox-range-requests": "6.6.0", - "workbox-recipes": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0", - "workbox-streams": "6.6.0", - "workbox-sw": "6.6.0", - "workbox-window": "6.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", - "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", - "license": "MIT", - "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/workbox-build/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/workbox-build/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/workbox-build/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "deprecated": "The work that was done in this beta branch won't be included in future versions", - "license": "BSD-3-Clause", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", - "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", - "deprecated": "workbox-background-sync@6.6.0", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-core": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", - "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==", - "license": "MIT" - }, - "node_modules/workbox-expiration": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", - "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", - "license": "MIT", - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-google-analytics": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", - "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", - "deprecated": "It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained", - "license": "MIT", - "dependencies": { - "workbox-background-sync": "6.6.0", - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", - "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-precaching": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", - "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-range-requests": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", - "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-recipes": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", - "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", - "license": "MIT", - "dependencies": { - "workbox-cacheable-response": "6.6.0", - "workbox-core": "6.6.0", - "workbox-expiration": "6.6.0", - "workbox-precaching": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-routing": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", - "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-strategies": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", - "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-streams": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", - "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", - "license": "MIT", - "dependencies": { - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0" - } - }, - "node_modules/workbox-sw": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", - "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==", - "license": "MIT" - }, - "node_modules/workbox-webpack-plugin": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", - "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.6.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": "^4.4.0 || ^5.9.0" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "license": "MIT", - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/workbox-window": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", - "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", - "license": "MIT", - "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.6.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -14991,6 +12285,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yocto-queue": { @@ -15021,7 +12316,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index b6b6580..c713fdb 100644 --- a/package.json +++ b/package.json @@ -46,24 +46,26 @@ "jspdf": "^4.0.0", "katex": "^0.16.28", "lucide-react": "^0.562.0", - "mermaid": "^11.12.2", - "next": "16.1.5", - "next-pwa": "^5.6.0", + "mermaid": "^11.14.0", + "next": "16.2.2", "next-themes": "^0.4.6", "pdfjs-dist": "^5.4.530", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "prisma": "^7.3.0", "react": "19.2.3", "react-dom": "19.2.3", "react-pdf": "^10.3.0", "react-resizable-panels": "^4.4.1", "react-zoom-pan-pinch": "^3.7.0", + "recharts": "^3.8.1", "redis": "^5.10.0", "sonner": "^2.0.7", "swagger-ui-dist": "^5.17.14", "tailwind-merge": "^3.4.0", "usehooks-ts": "^3.1.1", "zod": "^4.3.5", - "zustand": "^5.0.10", - "prisma": "^7.3.0" + "zustand": "^5.0.10" }, "devDependencies": { "@prisma/config": "^7.2.0", @@ -74,7 +76,7 @@ "@types/react-dom": "^19", "@types/swagger-ui": "^3.52.2", "eslint": "^9", - "eslint-config-next": "16.1.2", + "eslint-config-next": "16.2.2", "prettier": "^3.8.0", "prettier-plugin-tailwindcss": "^0.7.2", "tailwindcss": "^4", @@ -84,4 +86,4 @@ "overrides": { "hono": "^4.11.4" } -} \ No newline at end of file +} diff --git a/plan/code-map.md b/plan/code-map.md new file mode 100644 index 0000000..d9f79e3 --- /dev/null +++ b/plan/code-map.md @@ -0,0 +1,55 @@ +# Atlantis Code Map (Compact) + +Goal: minimize search tokens and maximize first-pass routing accuracy. + +## Hard Rules + +- Read this file before edits. +- Route via Intent Map first; avoid blind repo-wide search. +- If intent is missing, add it in the same change. +- Update this file whenever paths/routes/exports/responsibilities/schema change. + +## Umbrella Intent Map (Sequential) + +1. Dashboard/Home -> `src/app/page.tsx` -> `src/lib/dashboard-data.ts` -> `src/components/InsightsPanel.tsx` + `src/components/DashboardSection.tsx` (home composition + stats). +2. Diagram list/filter/paging -> `src/app/diagram/page.tsx` -> `src/components/DiagramGrid.tsx` -> `src/app/api/diagrams/route.ts` -> `src/lib/data.ts`. +3. Diagram editor/canvas/save/checkpoints -> `src/app/diagram/[id]/page.tsx` -> `src/components/DiagramEditor.tsx` + `src/components/Editor.tsx` + `src/components/Canvas.tsx` + `src/components/CheckpointHistory.tsx` -> `src/app/api/diagrams/[id]/route.ts` + `src/app/api/diagrams/[id]/checkpoint/route.ts` -> `src/lib/data.ts`. +4. Notes shell/list/workspace/editor -> `src/app/notes/layout.tsx` + `src/app/notes/page.tsx` + `src/app/notes/[id]/page.tsx` -> `src/components/notes/NotesLayoutClient.tsx` + `src/components/notes/NoteList.tsx` + `src/components/notes/NoteWorkspace.tsx` + `src/components/notes/NoteEditor.tsx` -> `src/lib/notes-data.ts`. +5. Notes markdown/latex/todo/search UX -> `src/components/notes/NoteMarkdownPreview.tsx` + `src/components/notes/NoteLatexPreview.tsx` + `src/components/notes/TodoList.tsx` + `src/components/notes/NoteSearchReplace.tsx` -> `src/app/api/notes/compile/route.ts`. +6. Tags (pages/settings/CRUD) -> `src/app/tags/page.tsx` + `src/app/tags/[tagSlug]/page.tsx` + `src/app/settings/tags/page.tsx` -> `src/app/api/tags/route.ts` + `src/app/api/tags/[id]/route.ts`. +7. Settings + advanced prefs/stats chart -> `src/app/settings/page.tsx` -> `src/components/ui/chart.tsx` -> `src/app/api/settings/advanced/route.ts` + `src/app/api/settings/ai-key/route.ts` + `src/app/api/settings/stats/route.ts` -> `src/lib/settings.ts` + `src/lib/store.ts`. +8. AI assistant -> `src/components/AiChatPanel.tsx` -> `src/app/api/ai/assist/route.ts` -> `src/app/api/settings/ai-key/route.ts` + `src/lib/settings.ts`. +9. Live sync/SSE/collab -> `src/lib/useLiveSync.ts` + `src/lib/useListSync.ts` + `src/lib/pubsub.ts` -> `src/app/api/sync/stream/route.ts` + `src/app/api/sync/publish/route.ts` -> `src/lib/live-sync-config.ts`. +10. Cache/freshness behavior -> `src/lib/cache.ts` -> `src/app/api/diagrams/route.ts` + `src/app/api/diagrams/[id]/route.ts` + `src/app/api/notes/route.ts` + `src/app/api/notes/[id]/route.ts`. +11. API docs/public access API -> `src/app/docs/page.tsx` + `src/components/ApiDoc.tsx` + `docs/API_GUIDE.md` -> `src/app/api/access/diagrams/route.ts` + `src/app/api/access/diagrams/[id]/route.ts` + `src/app/api/access/notes/route.ts` + `src/app/api/access/notes/[id]/route.ts`. +12. CSRF/auth guard -> `src/lib/csrf.ts` + `src/lib/csrf-client.ts` + `src/lib/csrf-constants.ts` -> `src/app/api/csrf/route.ts`. +13. Backup/restore/wipe -> `src/app/api/backup/route.ts` + `src/app/api/settings/wipe/route.ts` -> `src/lib/data.ts` + `src/lib/schemas.ts`. +14. DB/provider/bootstrap changes -> `prisma/schema.prisma` + `src/lib/prisma.ts` + `src/lib/database-url.ts` + `scripts/database-url.js` + `scripts/bootstrap.js` + `scripts/prepare-prisma-schema.js` + `scripts/backfill-tag-counts.js`. + +## Ownership Map (Condensed) + +- `src/app/`: App Router pages/layout/error. +- `src/app/api/`: server endpoints by feature domain. +- `src/components/`: feature UI; `src/components/notes/` is notes-specific; `src/components/ui/` shared primitives (includes chart wrappers in `src/components/ui/chart.tsx`). +- `src/lib/`: domain logic (data, notes-data, cache, sync, csrf, settings, schemas, types, store). +- `prisma/`: schema source of truth. +- `scripts/`: bootstrap/prisma/backfill flows. +- `docs/`: user-facing docs. + +## Critical Contracts + +- Models: `prisma/schema.prisma`. +- Shared types: `src/lib/types.ts`. +- Validation: `src/lib/schemas.ts`. +- Diagram service: `src/lib/data.ts`. +- Note service: `src/lib/notes-data.ts`. +- Settings service/store: `src/lib/settings.ts` + `src/lib/store.ts`. + +## Required Map Update Triggers + +- Added/moved/renamed file/folder/route. +- Added/renamed/removed exported function that changes ownership. +- Changed module responsibility. +- Changed schema or persistence/bootstrap flow. + +If any trigger is true, update this file in the same change. diff --git a/postcss.config.mjs b/postcss.config.mjs index 61e3684..297374d 100644 --- a/postcss.config.mjs +++ b/postcss.config.mjs @@ -1,6 +1,6 @@ const config = { plugins: { - "@tailwindcss/postcss": {}, + '@tailwindcss/postcss': {}, }, }; diff --git a/prisma.config.ts b/prisma.config.ts index b99de5d..05d463e 100644 --- a/prisma.config.ts +++ b/prisma.config.ts @@ -1,6 +1,7 @@ import { defineConfig } from '@prisma/config'; +import { resolveDatabaseUrl } from './scripts/database-url'; -const url = process.env.DATABASE_URL ?? process.env.DB_CONNECTION ?? 'file:./data/atlantis.db'; +const url = resolveDatabaseUrl(); export default defineConfig({ datasource: { diff --git a/prisma/prisma.config.ts b/prisma/prisma.config.ts index 8614ca6..fc465ea 100644 --- a/prisma/prisma.config.ts +++ b/prisma/prisma.config.ts @@ -1,14 +1,10 @@ import path from 'node:path'; import { defineConfig } from 'prisma/config'; - -// Resolve the database URL from environment variables -function resolveDatabaseUrl(): string { - return process.env.DATABASE_URL || process.env.DB_CONNECTION || 'file:./data/atlantis.db'; -} +import { resolveDatabaseUrl } from '../scripts/database-url'; export default defineConfig({ - schema: path.join(__dirname, 'schema.prisma'), - datasource: { - url: resolveDatabaseUrl(), - }, + schema: path.join(__dirname, 'schema.prisma'), + datasource: { + url: resolveDatabaseUrl(), + }, }); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7527236..95e2475 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,5 +1,6 @@ generator client { provider = "prisma-client-js" + previewFeatures = ["fullTextSearchPostgres"] } // Provider is resolved from env (DB_CONNECTION or PRISMA_PROVIDER) with sqlite fallback @@ -7,7 +8,7 @@ generator client { // Supported providers: postgresql, mysql, sqlite datasource db { - provider = "sqlite" + provider = "postgresql" } @@ -39,7 +40,7 @@ model Diagram { tags Tag[] @@index([updatedAt], map: "diagram_updatedAt_idx") - @@index([searchVector], map: "diagram_searchVector_idx") + } model Content { @@ -75,7 +76,7 @@ model Note { @@index([updatedAt], map: "note_updatedAt_idx") @@index([hasTodos], map: "note_hasTodos_idx") - @@index([searchVector], map: "note_searchVector_idx") + @@index([starred], map: "note_starred_idx") } diff --git a/prisma/schema.template.prisma b/prisma/schema.template.prisma index 56c4026..ab1161f 100644 --- a/prisma/schema.template.prisma +++ b/prisma/schema.template.prisma @@ -1,5 +1,6 @@ generator client { provider = "prisma-client-js" + @@PREVIEW_FEATURES@@ } // Provider is resolved from env (DB_CONNECTION or PRISMA_PROVIDER) with sqlite fallback diff --git a/public/manifest.json b/public/manifest.json index 30f7d19..562a2f4 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,24 +1,24 @@ { - "name": "Atlantis", - "short_name": "Atlantis", - "description": "Your second brain for diagrams and notes", - "start_url": "/", - "display": "standalone", - "background_color": "#0a0a0a", - "theme_color": "#3b82f6", - "orientation": "portrait-primary", - "icons": [ - { - "src": "/icon-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "any maskable" - }, - { - "src": "/icon-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "any maskable" - } - ] -} \ No newline at end of file + "name": "Atlantis", + "short_name": "Atlantis", + "description": "Your second brain for diagrams and notes", + "start_url": "/", + "display": "standalone", + "background_color": "#0a0a0a", + "theme_color": "#3b82f6", + "orientation": "portrait-primary", + "icons": [ + { + "src": "/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ] +} diff --git a/public/openapi.json b/public/openapi.json index 6be1a2c..d379885 100644 --- a/public/openapi.json +++ b/public/openapi.json @@ -23,9 +23,7 @@ "paths": { "/api/access/diagrams": { "get": { - "tags": [ - "Diagrams" - ], + "tags": ["Diagrams"], "summary": "List all diagrams", "description": "Retrieve a paginated list of all stored diagrams. Requires `ENABLE_API_ACCESS=true`.", "parameters": [ @@ -65,9 +63,7 @@ } }, "post": { - "tags": [ - "Diagrams" - ], + "tags": ["Diagrams"], "summary": "Create a new diagram", "description": "Create a new diagram with Mermaid content. Validates syntax before saving. Requires `ENABLE_API_ACCESS=true`.", "requestBody": { @@ -102,9 +98,7 @@ }, "/api/access/diagrams/{id}": { "get": { - "tags": [ - "Diagrams" - ], + "tags": ["Diagrams"], "summary": "Get a single diagram", "description": "Retrieve the full details of a specific diagram by ID. Requires `ENABLE_API_ACCESS=true`.", "parameters": [ @@ -140,9 +134,7 @@ }, "/api/access/notes": { "get": { - "tags": [ - "Notes" - ], + "tags": ["Notes"], "summary": "List all notes", "description": "Retrieve a list of notes. Content is omitted from the list for performance. Requires `ENABLE_API_ACCESS=true`.", "parameters": [ @@ -182,9 +174,7 @@ } }, "post": { - "tags": [ - "Notes" - ], + "tags": ["Notes"], "summary": "Create a new note", "description": "Create a new note. Requires `ENABLE_API_ACCESS=true`.", "requestBody": { @@ -219,9 +209,7 @@ }, "/api/access/notes/{id}": { "get": { - "tags": [ - "Notes" - ], + "tags": ["Notes"], "summary": "Get a note", "description": "Retrieve a specific note by ID. Requires `ENABLE_API_ACCESS=true`.", "parameters": [ @@ -293,9 +281,7 @@ }, "CreateDiagramRequest": { "type": "object", - "required": [ - "content" - ], + "required": ["content"], "properties": { "title": { "type": "string", @@ -428,4 +414,4 @@ } } } -} \ No newline at end of file +} diff --git a/public/sw.js b/public/sw.js index 096e99c..b20f1bd 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1,123 +1,16 @@ -/** - * Minimal Service Worker for client-side caching - * - * Caching strategy: - * - Static assets (_next/static): Cache-first with network fallback - * - API responses: Network-first with cache fallback - * - Pages: Network-first with offline fallback - */ +// Disabled service worker (no caching) to keep SSE/live sync reliable. +// If you re-enable, ensure /api and /api/sync/stream are always network-only. -const CACHE_NAME = 'atlantis-v1'; -const STATIC_CACHE_NAME = 'atlantis-static-v1'; - -// Assets to precache on install -const PRECACHE_ASSETS = [ - '/', - '/manifest.json', -]; - -// Install event - precache essential assets -self.addEventListener('install', (event) => { - event.waitUntil( - caches.open(CACHE_NAME).then((cache) => { - return cache.addAll(PRECACHE_ASSETS); - }) - ); - // Skip waiting to activate immediately - self.skipWaiting(); +self.addEventListener('install', () => { + // Activate immediately + self.skipWaiting(); }); -// Activate event - clean up old caches self.addEventListener('activate', (event) => { - event.waitUntil( - caches.keys().then((cacheNames) => { - return Promise.all( - cacheNames - .filter((name) => name !== CACHE_NAME && name !== STATIC_CACHE_NAME) - .map((name) => caches.delete(name)) - ); - }) - ); - // Take control of all pages immediately - self.clients.claim(); + // Take control immediately + event.waitUntil(self.clients.claim()); }); -// Fetch event - implement caching strategies -self.addEventListener('fetch', (event) => { - const { request } = event; - const url = new URL(request.url); - - // Skip non-GET requests - if (request.method !== 'GET') { - return; - } - - // Skip chrome-extension and other non-http(s) requests - if (!url.protocol.startsWith('http')) { - return; - } - - // Static assets: Cache-first strategy - if (url.pathname.startsWith('/_next/static/') || - /\.(js|css|woff2?|ttf|eot|svg|png|jpg|jpeg|gif|ico|webp)$/.test(url.pathname)) { - event.respondWith( - caches.open(STATIC_CACHE_NAME).then((cache) => { - return cache.match(request).then((response) => { - if (response) { - return response; - } - return fetch(request).then((networkResponse) => { - // Only cache successful responses - if (networkResponse.ok) { - cache.put(request, networkResponse.clone()); - } - return networkResponse; - }); - }); - }) - ); - return; - } - - // API requests: Network-first with cache fallback - if (url.pathname.startsWith('/api/')) { - event.respondWith( - fetch(request) - .then((response) => { - // Cache successful GET responses - if (response.ok) { - const responseClone = response.clone(); - caches.open(CACHE_NAME).then((cache) => { - cache.put(request, responseClone); - }); - } - return response; - }) - .catch(() => { - return caches.match(request); - }) - ); - return; - } - - // Pages: Network-first with offline fallback - event.respondWith( - fetch(request) - .then((response) => { - // Cache successful page responses - if (response.ok) { - const responseClone = response.clone(); - caches.open(CACHE_NAME).then((cache) => { - cache.put(request, responseClone); - }); - } - return response; - }) - .catch(() => { - return caches.match(request).then((response) => { - // Return cached response or fall back to homepage - return response || caches.match('/'); - }); - }) - ); +self.addEventListener('fetch', () => { + // No caching; allow network to proceed unmodified }); diff --git a/scripts/backfill-tag-counts.js b/scripts/backfill-tag-counts.js index 625d4c2..749d4a5 100644 --- a/scripts/backfill-tag-counts.js +++ b/scripts/backfill-tag-counts.js @@ -1,21 +1,15 @@ /* eslint-disable @typescript-eslint/no-require-imports */ const Database = require('better-sqlite3'); -const path = require('path'); +const { resolveDatabaseUrl, sqlitePathFromUrl } = require('./database-url'); -const dbPath = (() => { - const url = process.env.DATABASE_URL || process.env.DB_CONNECTION; - if (url && !url.startsWith('file:')) { - console.error('This script only supports SQLite (file: URLs).'); - process.exit(1); - } - if (!url) { - return path.resolve(__dirname, '../data/atlantis.db'); - } - // Parse file URL: strip prefix, query params, etc - const withoutPrefix = url.replace(/^file:/, ''); - const withoutQuery = withoutPrefix.split('?')[0].split('#')[0]; - return path.resolve(process.cwd(), withoutQuery); -})(); +const url = resolveDatabaseUrl(); + +if (!url.startsWith('file:')) { + console.error('This script only supports SQLite (file: URLs).'); + process.exit(1); +} + +const dbPath = sqlitePathFromUrl(url); console.log(`Using database: ${dbPath}`); diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index 5b08fea..a02359d 100644 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -4,6 +4,7 @@ const { spawnSync } = require('child_process'); const path = require('path'); const fs = require('fs'); const { buildSearchVector } = require('./searchVector'); +const { resolveDatabaseUrl, sqlitePathFromUrl } = require('./database-url'); // Try to load .env if present try { @@ -19,9 +20,6 @@ const lifecycle = process.env.npm_lifecycle_event; const isProd = process.env.NODE_ENV === 'production'; const isCI = process.env.CI === 'true'; const isDevScript = lifecycle === 'dev'; -if (!process.env.DATABASE_URL && process.env.DB_CONNECTION) { - process.env.DATABASE_URL = process.env.DB_CONNECTION; -} const autoApplyEnv = process.env.PRISMA_AUTO_APPLY; const skipAutoPush = process.env.PRISMA_SKIP_AUTOPUSH === 'true'; const forceGenerate = process.env.PRISMA_FORCE_GENERATE === 'true'; @@ -41,10 +39,9 @@ function run(cmd, args, options = {}) { } } -function ensureDataDir() { - const url = process.env.DATABASE_URL || process.env.DB_CONNECTION; +function ensureDataDir(url) { if (!url || !url.startsWith('file:')) return; - const filePath = toSqlitePath(url); + const filePath = sqlitePathFromUrl(url); const dir = path.dirname(filePath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); @@ -53,7 +50,7 @@ function ensureDataDir() { function createAdapter(url) { if (url.startsWith('file:')) { - ensureDataDir(); + ensureDataDir(url); try { // Optional dependency in some builds const { PrismaBetterSqlite3 } = require('@prisma/adapter-better-sqlite3'); @@ -110,7 +107,9 @@ async function backfillSearchVectors(url) { } async function main() { - ensureDataDir(); + const url = ensureDatabaseUrl(); + const isSqlite = url.startsWith('file:'); + const sqliteNeedsPush = isSqlite && needsSqliteDbPush(url); // Step 1: ensure provider-substituted schema run('node', ['scripts/prepare-prisma-schema.js']); @@ -123,10 +122,6 @@ async function main() { // Step 3: apply schema to DB // Always push for SQLite if database file is missing or empty (ensures tables exist) // Also push in dev mode or when explicitly enabled - const url = ensureDatabaseUrl(); - const isSqlite = url.startsWith('file:'); - const sqliteNeedsPush = isSqlite && needsSqliteDbPush(url); - if (!skipAutoPush && (shouldAutoApply || sqliteNeedsPush)) { run('npx', ['prisma', 'db', 'push']); } @@ -145,7 +140,7 @@ async function main() { * Check if SQLite database needs a push (missing or very small file = no tables) */ function needsSqliteDbPush(url) { - const filePath = toSqlitePath(url); + const filePath = sqlitePathFromUrl(url); try { const stats = fs.statSync(filePath); // SQLite header is 100 bytes; an empty schema db is typically ~12KB+ @@ -157,19 +152,10 @@ function needsSqliteDbPush(url) { } } -function toSqlitePath(url) { - const withoutPrefix = url.replace(/^file:/, ''); - const withoutQuery = withoutPrefix.split('?')[0].split('#')[0]; - return path.resolve(root, withoutQuery); -} - function ensureDatabaseUrl() { - const existing = process.env.DATABASE_URL || process.env.DB_CONNECTION; - if (existing) return existing; - const fallback = 'file:./data/atlantis.db'; - process.env.DATABASE_URL = fallback; - ensureDataDir(); - return fallback; + const url = resolveDatabaseUrl(); + ensureDataDir(url); + return url; } main().catch((err) => { diff --git a/scripts/database-url.js b/scripts/database-url.js new file mode 100644 index 0000000..7b89c1f --- /dev/null +++ b/scripts/database-url.js @@ -0,0 +1,80 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +const projectRoots = [process.cwd(), path.resolve(__dirname, '..')]; +const defaultSqlitePath = path.join(projectRoots[0], 'data', 'atlantis.db'); +const fallbackSqlitePath = path.join(os.tmpdir(), 'atlantis', 'atlantis.db'); + +function ensureDir(dirPath) { + try { + fs.mkdirSync(dirPath, { recursive: true }); + } catch { + /* noop */ + } +} + +function isWritablePath(filePath) { + const dir = path.dirname(filePath); + ensureDir(dir); + + try { + fs.accessSync(dir, fs.constants.W_OK); + if (fs.existsSync(filePath)) { + fs.accessSync(filePath, fs.constants.W_OK); + } + return true; + } catch { + return false; + } +} + +/** + * Convert a Prisma SQLite URL into an absolute file system path. + * @param {string} url + * @returns {string} + */ +function sqlitePathFromUrl(url) { + const withoutPrefix = url.replace(/^file:/, ''); + const withoutQuery = withoutPrefix.split(/[?#]/)[0]; + if (path.isAbsolute(withoutQuery)) return withoutQuery; + return path.resolve(process.cwd(), withoutQuery); +} + +function resolveSqlitePath() { + const candidates = projectRoots.map((root) => path.join(root, 'data', 'atlantis.db')); + + candidates.push(fallbackSqlitePath); + + const seen = new Set(); + for (const candidate of candidates) { + if (seen.has(candidate)) continue; + seen.add(candidate); + if (isWritablePath(candidate)) return candidate; + console.warn(`[database-url] path not writable, skipping: ${candidate}`); + } + + ensureDir(path.dirname(fallbackSqlitePath)); + return fallbackSqlitePath; +} + +function resolveDatabaseUrl() { + const envUrl = process.env.DATABASE_URL || process.env.DB_CONNECTION; + if (envUrl) { + process.env.DATABASE_URL = envUrl; + return envUrl; + } + + const sqlitePath = resolveSqlitePath(); + const url = `file:${sqlitePath}`; + process.env.DATABASE_URL = url; + return url; +} + +module.exports = { + defaultSqlitePath, + fallbackSqlitePath, + resolveDatabaseUrl, + sqlitePathFromUrl, +}; diff --git a/scripts/prepare-prisma-schema.js b/scripts/prepare-prisma-schema.js index 4e76438..4c04e74 100644 --- a/scripts/prepare-prisma-schema.js +++ b/scripts/prepare-prisma-schema.js @@ -3,10 +3,13 @@ const fs = require('fs'); const path = require('path'); function resolveProvider() { - const raw = (process.env.DATABASE_URL || process.env.DB_CONNECTION || process.env.PRISMA_PROVIDER || '').toLowerCase(); + const envVar = + process.env.DATABASE_URL || process.env.DB_CONNECTION || process.env.PRISMA_PROVIDER || ''; + const raw = envVar.toLowerCase(); + if (raw.includes('postgres')) return 'postgresql'; if (raw.includes('mysql')) return 'mysql'; - if (raw.includes('sqlite') || raw.startsWith('file:')) return 'sqlite'; + return 'sqlite'; } @@ -17,17 +20,15 @@ function main() { const template = fs.readFileSync(templatePath, 'utf-8'); - let noteIndex = '@@index([searchVector], map: "note_searchVector_idx")'; - let diagramIndex = '@@index([searchVector], map: "diagram_searchVector_idx")'; - - if (provider === 'postgresql') { - // We use GIN indexes for Postgres, managed manually - noteIndex = ''; - diagramIndex = ''; - } + // GIN indexes for Postgres are managed manually + const isPostgres = provider === 'postgresql'; + const noteIndex = isPostgres ? '' : '@@index([searchVector], map: "note_searchVector_idx")'; + const diagramIndex = isPostgres ? '' : '@@index([searchVector], map: "diagram_searchVector_idx")'; + const previewFeatures = isPostgres ? 'previewFeatures = ["fullTextSearchPostgres"]' : ''; const nextSchema = template .replace(/@@PROVIDER@@/g, provider) + .replace(/@@PREVIEW_FEATURES@@/g, previewFeatures) .replace(/@@NOTE_INDEX@@/g, noteIndex) .replace(/@@DIAGRAM_INDEX@@/g, diagramIndex); @@ -36,5 +37,3 @@ function main() { } main(); - - diff --git a/scripts/verify-optimization.ts b/scripts/verify-optimization.ts index e0bafab..4f01e36 100644 --- a/scripts/verify-optimization.ts +++ b/scripts/verify-optimization.ts @@ -3,88 +3,93 @@ import { createNote, updateNoteById, deleteNoteById } from '../src/lib/notes-dat import { createDiagram, deleteDiagramById } from '../src/lib/data'; async function main() { - console.log('Starting verification...'); - - // 1. Create a Test Tag - const tagName = `test-tag-${Date.now()}`; - const tagSlug = `test-tag-${Date.now()}`; - const tag = await prisma.tag.create({ - data: { name: tagName, slug: tagSlug }, - }); - console.log(`Created tag: ${tagName} (ID: ${tag.id}, Usage: ${tag.usageCount})`); - - if (tag.usageCount !== 0) throw new Error('Initial usage count should be 0'); - - // 2. Create Note with Tag and Todo - console.log('Creating note...'); - const note = await createNote({ - title: 'Test Note', - content: 'This is a test note\n- [ ] Todo item', - tags: [tag.id] - }); - - // Verify Note - const noteCheck = await prisma.note.findUnique({ where: { id: note.id } }); - if (!noteCheck?.hasTodos) throw new Error('Note should have hasTodos=true'); - console.log('Note hasTodos verified.'); - - // Verify Tag Usage - const tagCheck1 = await prisma.tag.findUnique({ where: { id: tag.id } }); - if (tagCheck1?.usageCount !== 1) throw new Error(`Tag usage should be 1, got ${tagCheck1?.usageCount}`); - console.log('Tag usage after note creation verified (1).'); - - // 3. Update Note (Remove Todo, Keep Tag) - console.log('Updating note (removing todo)...'); - await updateNoteById(note.id, { - content: 'Todo is done now', - tags: [tag.id] // Keep tag - }); - - const noteCheck2 = await prisma.note.findUnique({ where: { id: note.id } }); - if (noteCheck2?.hasTodos) throw new Error('Note should have hasTodos=false'); - console.log('Note hasTodos update verified.'); - - const tagCheck2 = await prisma.tag.findUnique({ where: { id: tag.id } }); - if (tagCheck2?.usageCount !== 1) throw new Error(`Tag usage should be 1, got ${tagCheck2?.usageCount}`); - - // 4. Create Diagram with Tag - console.log('Creating diagram...'); - const diagram = await createDiagram({ - title: 'Test Diagram', - content: 'graph TD; A-->B;', - tags: [tag.id] - }); - - const tagCheck3 = await prisma.tag.findUnique({ where: { id: tag.id } }); - if (tagCheck3?.usageCount !== 2) throw new Error(`Tag usage should be 2, got ${tagCheck3?.usageCount}`); - console.log('Tag usage after diagram creation verified (2).'); - - // 5. Delete Note - console.log('Deleting note...'); - await deleteNoteById(note.id); - - const tagCheck4 = await prisma.tag.findUnique({ where: { id: tag.id } }); - if (tagCheck4?.usageCount !== 1) throw new Error(`Tag usage should be 1, got ${tagCheck4?.usageCount}`); - console.log('Tag usage after note deletion verified (1).'); - - // 6. Delete Diagram - console.log('Deleting diagram...'); - await deleteDiagramById(diagram.id); - - const tagCheck5 = await prisma.tag.findUnique({ where: { id: tag.id } }); - if (tagCheck5?.usageCount !== 0) throw new Error(`Tag usage should be 0, got ${tagCheck5?.usageCount}`); - console.log('Tag usage after diagram deletion verified (0).'); - - // Cleanup - await prisma.tag.delete({ where: { id: tag.id } }); - console.log('Verification Complete!'); + console.log('Starting verification...'); + + // 1. Create a Test Tag + const tagName = `test-tag-${Date.now()}`; + const tagSlug = `test-tag-${Date.now()}`; + const tag = await prisma.tag.create({ + data: { name: tagName, slug: tagSlug }, + }); + console.log(`Created tag: ${tagName} (ID: ${tag.id}, Usage: ${tag.usageCount})`); + + if (tag.usageCount !== 0) throw new Error('Initial usage count should be 0'); + + // 2. Create Note with Tag and Todo + console.log('Creating note...'); + const note = await createNote({ + title: 'Test Note', + content: 'This is a test note\n- [ ] Todo item', + tags: [tag.id], + }); + + // Verify Note + const noteCheck = await prisma.note.findUnique({ where: { id: note.id } }); + if (!noteCheck?.hasTodos) throw new Error('Note should have hasTodos=true'); + console.log('Note hasTodos verified.'); + + // Verify Tag Usage + const tagCheck1 = await prisma.tag.findUnique({ where: { id: tag.id } }); + if (tagCheck1?.usageCount !== 1) + throw new Error(`Tag usage should be 1, got ${tagCheck1?.usageCount}`); + console.log('Tag usage after note creation verified (1).'); + + // 3. Update Note (Remove Todo, Keep Tag) + console.log('Updating note (removing todo)...'); + await updateNoteById(note.id, { + content: 'Todo is done now', + tags: [tag.id], // Keep tag + }); + + const noteCheck2 = await prisma.note.findUnique({ where: { id: note.id } }); + if (noteCheck2?.hasTodos) throw new Error('Note should have hasTodos=false'); + console.log('Note hasTodos update verified.'); + + const tagCheck2 = await prisma.tag.findUnique({ where: { id: tag.id } }); + if (tagCheck2?.usageCount !== 1) + throw new Error(`Tag usage should be 1, got ${tagCheck2?.usageCount}`); + + // 4. Create Diagram with Tag + console.log('Creating diagram...'); + const diagram = await createDiagram({ + title: 'Test Diagram', + content: 'graph TD; A-->B;', + tags: [tag.id], + }); + + const tagCheck3 = await prisma.tag.findUnique({ where: { id: tag.id } }); + if (tagCheck3?.usageCount !== 2) + throw new Error(`Tag usage should be 2, got ${tagCheck3?.usageCount}`); + console.log('Tag usage after diagram creation verified (2).'); + + // 5. Delete Note + console.log('Deleting note...'); + await deleteNoteById(note.id); + + const tagCheck4 = await prisma.tag.findUnique({ where: { id: tag.id } }); + if (tagCheck4?.usageCount !== 1) + throw new Error(`Tag usage should be 1, got ${tagCheck4?.usageCount}`); + console.log('Tag usage after note deletion verified (1).'); + + // 6. Delete Diagram + console.log('Deleting diagram...'); + await deleteDiagramById(diagram.id); + + const tagCheck5 = await prisma.tag.findUnique({ where: { id: tag.id } }); + if (tagCheck5?.usageCount !== 0) + throw new Error(`Tag usage should be 0, got ${tagCheck5?.usageCount}`); + console.log('Tag usage after diagram deletion verified (0).'); + + // Cleanup + await prisma.tag.delete({ where: { id: tag.id } }); + console.log('Verification Complete!'); } main() - .catch(e => { - console.error(e); - process.exit(1); - }) - .finally(async () => { - await prisma.$disconnect(); - }); + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/src/app/api/access/diagrams/[id]/route.ts b/src/app/api/access/diagrams/[id]/route.ts index 0f43ce9..cda01fd 100644 --- a/src/app/api/access/diagrams/[id]/route.ts +++ b/src/app/api/access/diagrams/[id]/route.ts @@ -5,10 +5,7 @@ import { NextResponse } from 'next/server'; const apiAccessEnabled = process.env.ENABLE_API_ACCESS?.trim().toLowerCase() === 'true'; -export async function GET( - request: Request, - { params }: { params: Promise<{ id: string }> } -) { +export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) { if (!apiAccessEnabled) { return new NextResponse('API Access Disabled', { status: 403 }); } diff --git a/src/app/api/access/notes/[id]/route.ts b/src/app/api/access/notes/[id]/route.ts index 0c04911..798ece4 100644 --- a/src/app/api/access/notes/[id]/route.ts +++ b/src/app/api/access/notes/[id]/route.ts @@ -6,33 +6,30 @@ import { NextResponse } from 'next/server'; const apiAccessEnabled = process.env.ENABLE_API_ACCESS?.trim().toLowerCase() === 'true'; const PRIVATE_CONTENT_MESSAGE = 'Content policy in effect.'; -export async function GET( - request: Request, - { params }: { params: Promise<{ id: string }> } -) { - if (!apiAccessEnabled) { - return new NextResponse('API Access Disabled', { status: 403 }); - } - - try { - await ensureCsrfCookie(); - const { id } = await params; - const note = await getNoteById(id); +export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) { + if (!apiAccessEnabled) { + return new NextResponse('API Access Disabled', { status: 403 }); + } - if (!note) { - return NextResponse.json({ error: 'Note not found' }, { status: 404 }); - } + try { + await ensureCsrfCookie(); + const { id } = await params; + const note = await getNoteById(id); - if (note.private) { - return NextResponse.json({ - ...note, - content: PRIVATE_CONTENT_MESSAGE - }); - } + if (!note) { + return NextResponse.json({ error: 'Note not found' }, { status: 404 }); + } - return NextResponse.json(note); - } catch (error) { - logApiError('GET /api/access/notes/[id]', error); - return NextResponse.json({ error: 'Failed to fetch note' }, { status: 500 }); + if (note.private) { + return NextResponse.json({ + ...note, + content: PRIVATE_CONTENT_MESSAGE, + }); } + + return NextResponse.json(note); + } catch (error) { + logApiError('GET /api/access/notes/[id]', error); + return NextResponse.json({ error: 'Failed to fetch note' }, { status: 500 }); + } } diff --git a/src/app/api/access/notes/route.ts b/src/app/api/access/notes/route.ts index a776b30..4394133 100644 --- a/src/app/api/access/notes/route.ts +++ b/src/app/api/access/notes/route.ts @@ -7,79 +7,82 @@ import { noteCreateSchema } from '@/lib/schemas'; const apiAccessEnabled = process.env.ENABLE_API_ACCESS?.trim().toLowerCase() === 'true'; export async function GET(request: Request) { - if (!apiAccessEnabled) { - return new NextResponse('API Access Disabled', { status: 403 }); - } + if (!apiAccessEnabled) { + return new NextResponse('API Access Disabled', { status: 403 }); + } - try { - await ensureCsrfCookie(); + try { + await ensureCsrfCookie(); - const { searchParams } = new URL(request.url); - const page = Math.max(parseInt(searchParams.get('page') || '1', 10), 1); - const limit = Math.max(parseInt(searchParams.get('limit') || '10', 10), 1); - const offset = (page - 1) * limit; + const { searchParams } = new URL(request.url); + const page = Math.max(parseInt(searchParams.get('page') || '1', 10), 1); + const limit = Math.max(parseInt(searchParams.get('limit') || '10', 10), 1); + const offset = (page - 1) * limit; - const notesPage = await getNotePage({ limit, offset }); + const notesPage = await getNotePage({ limit, offset }); - // Transform to consistent API response format - const paginatedNotes = notesPage.items.map((n) => ({ - id: n.id, - title: n.title, - language: n.language, - createdAt: n.createdAt, - updatedAt: n.updatedAt, - })); + // Transform to consistent API response format + const paginatedNotes = notesPage.items.map((n) => ({ + id: n.id, + title: n.title, + language: n.language, + createdAt: n.createdAt, + updatedAt: n.updatedAt, + })); - return NextResponse.json({ - data: paginatedNotes, - pagination: { - page, - limit, - total: notesPage.total, - totalPages: Math.ceil(notesPage.total / limit), - }, - }); - } catch (error) { - logApiError('GET /api/access/notes', error); - return NextResponse.json({ error: 'Failed to fetch notes' }, { status: 500 }); - } + return NextResponse.json({ + data: paginatedNotes, + pagination: { + page, + limit, + total: notesPage.total, + totalPages: Math.ceil(notesPage.total / limit), + }, + }); + } catch (error) { + logApiError('GET /api/access/notes', error); + return NextResponse.json({ error: 'Failed to fetch notes' }, { status: 500 }); + } } export async function POST(request: Request) { - if (!apiAccessEnabled) { - return new NextResponse('API Access Disabled', { status: 403 }); - } + if (!apiAccessEnabled) { + return new NextResponse('API Access Disabled', { status: 403 }); + } - if (!(await validateCsrfToken(request))) { - return csrfFailureResponse(); - } + if (!(await validateCsrfToken(request))) { + return csrfFailureResponse(); + } - try { - const body = await request.json(); - const result = noteCreateSchema.safeParse(body); + try { + const body = await request.json(); + const result = noteCreateSchema.safeParse(body); - if (!result.success) { - return NextResponse.json( - { error: 'Invalid input', details: result.error.flatten() }, - { status: 400 } - ); - } + if (!result.success) { + return NextResponse.json( + { error: 'Invalid input', details: result.error.flatten() }, + { status: 400 } + ); + } - const { title, content, language } = result.data; + const { title, content, language } = result.data; - const newNote = await createNote({ title, content, language }); + const newNote = await createNote({ title, content, language }); - return NextResponse.json({ - id: newNote.id, - title: newNote.title, - language: newNote.language, - starred: newNote.starred, - private: newNote.private, - createdAt: newNote.createdAt, - updatedAt: newNote.updatedAt, - }, { status: 201 }); - } catch (error) { - logApiError('POST /api/access/notes', error); - return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); - } + return NextResponse.json( + { + id: newNote.id, + title: newNote.title, + language: newNote.language, + starred: newNote.starred, + private: newNote.private, + createdAt: newNote.createdAt, + updatedAt: newNote.updatedAt, + }, + { status: 201 } + ); + } catch (error) { + logApiError('POST /api/access/notes', error); + return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); + } } diff --git a/src/app/api/ai/assist/route.ts b/src/app/api/ai/assist/route.ts index 5126aed..70a643a 100644 --- a/src/app/api/ai/assist/route.ts +++ b/src/app/api/ai/assist/route.ts @@ -2,6 +2,7 @@ import { csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; import { logApiError } from '@/lib/logger'; import { getAiApiKey, getAiProvider } from '@/lib/settings'; import { NextResponse } from 'next/server'; +import { OPENAI_MODEL, GEMINI_MODEL, GEMINI_API_VERSION } from '@/lib/ai/config'; type DomPurifyLike = { addHook: (hook: string, fn: () => void) => void; @@ -12,7 +13,6 @@ type DomPurifyLike = { type GlobalWithDomPurify = typeof globalThis & { DOMPurify?: DomPurifyLike }; async function ensureDomPurifyStub() { - const g = globalThis as GlobalWithDomPurify; try { @@ -45,7 +45,6 @@ async function ensureDomPurifyStub() { } } - type MermaidInstance = { parse: (content: string) => void; render: (id: string, content: string) => Promise<{ svg: string }>; @@ -56,9 +55,14 @@ let mermaidInstance: MermaidInstance | null = null; async function getMermaid(): Promise { if (mermaidInstance) return mermaidInstance; await ensureDomPurifyStub(); - const imported = (await import('mermaid')).default as { mermaid?: MermaidInstance } | MermaidInstance; + const imported = (await import('mermaid')).default as + | { mermaid?: MermaidInstance } + | MermaidInstance; const candidate = imported as MermaidInstance; - const m = typeof candidate.parse === 'function' ? candidate : (imported as { mermaid?: MermaidInstance }).mermaid; + const m = + typeof candidate.parse === 'function' + ? candidate + : (imported as { mermaid?: MermaidInstance }).mermaid; if (!m) { throw new Error('Mermaid import failed'); } @@ -71,9 +75,6 @@ async function getMermaid(): Promise { return mermaidInstance; } -const OPENAI_MODEL = 'gpt-4o-mini'; -const GEMINI_MODEL = process.env.GEMINI_MODEL || 'gemini-2.5-flash'; - const MAX_SELF_HEAL_ATTEMPTS = 2; type Provider = 'openai' | 'gemini'; @@ -150,7 +151,12 @@ function resolveProvider(apiKey: string, storedProvider: Provider | 'auto'): Pro return 'openai'; } -async function callProvider(apiKey: string, prompt: string, content: string, preferred: Provider | 'auto'): Promise { +async function callProvider( + apiKey: string, + prompt: string, + content: string, + preferred: Provider | 'auto' +): Promise { const provider = resolveProvider(apiKey, preferred); if (provider === 'gemini') { return callGemini(apiKey, prompt, content); @@ -200,7 +206,7 @@ async function callOpenAI(apiKey: string, prompt: string, content: string): Prom async function callGemini(apiKey: string, prompt: string, content: string): Promise { const userPrompt = buildUserPrompt(content, prompt); const attempt = async (model: string) => { - const endpoint = `https://generativelanguage.googleapis.com/v1/models/${model}:generateContent?key=${encodeURIComponent(apiKey)}`; + const endpoint = `https://generativelanguage.googleapis.com/${GEMINI_API_VERSION}/models/${model}:generateContent?key=${encodeURIComponent(apiKey)}`; const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -309,7 +315,14 @@ export async function POST(request: Request) { error instanceof Error && error.message ? error.message : 'Mermaid validation failed'; for (let attempt = 0; attempt < MAX_SELF_HEAL_ATTEMPTS; attempt += 1) { - const healed = await attemptSelfHeal(apiKey, storedProvider, prompt, content, sanitized, message); + const healed = await attemptSelfHeal( + apiKey, + storedProvider, + prompt, + content, + sanitized, + message + ); if (healed) { sanitized = healed; break; @@ -320,7 +333,9 @@ export async function POST(request: Request) { await validateMermaid(sanitized); } catch (finalError) { const finalMessage = - finalError instanceof Error && finalError.message ? finalError.message : 'Mermaid validation failed'; + finalError instanceof Error && finalError.message + ? finalError.message + : 'Mermaid validation failed'; return NextResponse.json( { error: 'Mermaid validation failed', details: finalMessage }, { status: 422 } diff --git a/src/app/api/diagrams/[id]/checkpoint/route.ts b/src/app/api/diagrams/[id]/checkpoint/route.ts index 086cc37..4c6f523 100644 --- a/src/app/api/diagrams/[id]/checkpoint/route.ts +++ b/src/app/api/diagrams/[id]/checkpoint/route.ts @@ -1,12 +1,15 @@ import { csrfFailureResponse, ensureCsrfCookie, validateCsrfToken } from '@/lib/csrf'; -import { createCheckpoint, deleteCheckpoint, getDiagramById, listCheckpoints, restoreCheckpoint } from '@/lib/data'; +import { + createCheckpoint, + deleteCheckpoint, + getDiagramById, + listCheckpoints, + restoreCheckpoint, +} from '@/lib/data'; import { logApiError } from '@/lib/logger'; import { NextResponse } from 'next/server'; -export async function GET( - _request: Request, - { params }: { params: Promise<{ id: string }> } -) { +export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) { try { await ensureCsrfCookie(); const { id } = await params; @@ -23,10 +26,7 @@ export async function GET( } } -export async function POST( - request: Request, - { params }: { params: Promise<{ id: string }> } -) { +export async function POST(request: Request, { params }: { params: Promise<{ id: string }> }) { if (!(await validateCsrfToken(request))) { return csrfFailureResponse(); } @@ -63,10 +63,7 @@ export async function POST( /** * Restore a checkpoint as the current version */ -export async function PATCH( - request: Request, - { params }: { params: Promise<{ id: string }> } -) { +export async function PATCH(request: Request, { params }: { params: Promise<{ id: string }> }) { if (!(await validateCsrfToken(request))) { return csrfFailureResponse(); } @@ -96,10 +93,7 @@ export async function PATCH( /** * Delete a checkpoint */ -export async function DELETE( - request: Request, - { params }: { params: Promise<{ id: string }> } -) { +export async function DELETE(request: Request, { params }: { params: Promise<{ id: string }> }) { if (!(await validateCsrfToken(request))) { return csrfFailureResponse(); } diff --git a/src/app/api/diagrams/[id]/route.ts b/src/app/api/diagrams/[id]/route.ts index 2e52ccc..6ff1f38 100644 --- a/src/app/api/diagrams/[id]/route.ts +++ b/src/app/api/diagrams/[id]/route.ts @@ -5,38 +5,70 @@ import { CachePrefixes, DEFAULT_TTL_MS, getCache, + deleteDocSnapshot, + getDocSnapshot, + setDocSnapshot, withCacheHeader, withNoCacheHeaders, + type CacheStatus, } from '@/lib/cache'; import { csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; import { deleteDiagramById, getDiagramById, updateDiagramById } from '@/lib/data'; import { logApiError } from '@/lib/logger'; +import { publishSyncEvent } from '@/lib/pubsub'; import { diagramSchema } from '@/lib/schemas'; type DiagramRouteParams = { params: Promise<{ id: string }>; }; +const toEtag = (id: string, updatedAt: string) => `W/"diagram-${id}-${updatedAt}"`; + +const diagramsCacheStatus = (fromSnapshot: boolean, fresh: boolean): CacheStatus => { + if (fresh) return 'BYPASS'; + return fromSnapshot ? 'HIT' : 'MISS'; +}; + export async function GET(request: Request, { params }: DiagramRouteParams) { try { const { id } = await params; const url = new URL(request.url); const fresh = url.searchParams.get('fresh') === 'true'; - - if (fresh) { - const diagram = await getDiagramById(id); - if (!diagram) { - return NextResponse.json({ error: 'Diagram not found' }, { status: 404 }); + const ifNoneMatch = request.headers.get('if-none-match'); + + // Prefer snapshot (Redis/memory) + const snapshot = await getDocSnapshot('diagram', id); + if (snapshot) { + const etag = toEtag(id, snapshot.updatedAt); + if (ifNoneMatch && ifNoneMatch === etag) { + return new NextResponse(null, { + status: 304, + headers: { ETag: etag }, + }); } - return withNoCacheHeaders(withCacheHeader(NextResponse.json(diagram), 'BYPASS')); + const response = NextResponse.json(snapshot); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + const withCache = withCacheHeader(response, diagramsCacheStatus(true, fresh)); + return fresh ? withNoCacheHeaders(withCache) : withCache; } const cache = getCache(); const cacheKey = CacheKeys.diagram(id); - const cached = await cache.get(cacheKey); + const cached = await cache.get(cacheKey); if (cached) { - return withCacheHeader(NextResponse.json(cached), 'HIT'); + const etag = toEtag(id, cached.updatedAt); + if (ifNoneMatch && ifNoneMatch === etag) { + return new NextResponse(null, { + status: 304, + headers: { ETag: etag }, + }); + } + const response = NextResponse.json(cached); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + return withCacheHeader(response, 'HIT'); } const diagram = await getDiagramById(id); @@ -46,8 +78,20 @@ export async function GET(request: Request, { params }: DiagramRouteParams) { } await cache.set(cacheKey, diagram, DEFAULT_TTL_MS); + await setDocSnapshot('diagram', id, diagram); + const etag = toEtag(id, diagram.updatedAt); + + if (ifNoneMatch && ifNoneMatch === etag) { + return new NextResponse(null, { + status: 304, + headers: { ETag: etag }, + }); + } - return withCacheHeader(NextResponse.json(diagram), 'MISS'); + const response = NextResponse.json(diagram); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + return withCacheHeader(response, 'MISS'); } catch (error) { logApiError('GET /api/diagrams/[id]', error); return NextResponse.json({ error: 'Failed to load diagram' }, { status: 500 }); @@ -70,10 +114,7 @@ export async function PUT(request: Request, { params }: DiagramRouteParams) { ); } - const updatedDiagram = await updateDiagramById(id, { - ...result.data, - tags: result.data.tags, - }); + const updatedDiagram = await updateDiagramById(id, result.data); if (!updatedDiagram) { return NextResponse.json({ error: 'Diagram not found' }, { status: 404 }); @@ -82,8 +123,26 @@ export async function PUT(request: Request, { params }: DiagramRouteParams) { const cache = getCache(); await cache.delete(CacheKeys.diagram(id)); await cache.deletePrefix(CachePrefixes.diagramsList); + await deleteDocSnapshot('diagram', id); + const etag = toEtag(id, updatedDiagram.updatedAt); - return NextResponse.json(updatedDiagram); + await setDocSnapshot('diagram', id, updatedDiagram); + + const source = request.headers.get('x-client-id') ?? undefined; + await publishSyncEvent({ + topic: `doc:diagram:${id}`, + payload: { id, updatedAt: updatedDiagram.updatedAt }, + source, + }); + await publishSyncEvent({ + topic: 'list:diagrams', + payload: { id, updatedAt: updatedDiagram.updatedAt }, + source, + }); + + const response = NextResponse.json(updatedDiagram); + response.headers.set('ETag', etag); + return response; } catch (error) { logApiError('PUT /api/diagrams/[id]', error); return NextResponse.json({ error: 'Failed to update diagram' }, { status: 500 }); @@ -107,6 +166,12 @@ export async function DELETE(request: Request, { params }: DiagramRouteParams) { await cache.delete(CacheKeys.diagram(id)); await cache.deletePrefix(CachePrefixes.diagramsList); + await deleteDocSnapshot('diagram', id); + + const source = request.headers.get('x-client-id') ?? undefined; + await publishSyncEvent({ topic: `doc:diagram:${id}`, payload: { id, deleted: true }, source }); + await publishSyncEvent({ topic: 'list:diagrams', payload: { id, deleted: true }, source }); + return NextResponse.json({ success: true }); } catch (error) { logApiError('DELETE /api/diagrams/[id]', error); diff --git a/src/app/api/diagrams/route.ts b/src/app/api/diagrams/route.ts index 4480b3c..e8643a6 100644 --- a/src/app/api/diagrams/route.ts +++ b/src/app/api/diagrams/route.ts @@ -1,8 +1,17 @@ import { ensureCsrfCookie, csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; import { createDiagram, getDiagramPage } from '@/lib/data'; import { logApiError } from '@/lib/logger'; +import { publishSyncEvent } from '@/lib/pubsub'; import { diagramSchema } from '@/lib/schemas'; -import { getCache, CacheKeys, CachePrefixes, DEFAULT_TTL_MS, withCacheHeader, withNoCacheHeaders, type CacheStatus } from '@/lib/cache'; +import { + getCache, + CacheKeys, + CachePrefixes, + DEFAULT_TTL_MS, + withCacheHeader, + withNoCacheHeaders, + type CacheStatus, +} from '@/lib/cache'; import { NextResponse } from 'next/server'; const DEFAULT_LIMIT = 24; @@ -20,16 +29,13 @@ export async function GET(request: Request) { const limitNumber = limit ? Number.parseInt(limit, 10) : DEFAULT_LIMIT; const offsetNumber = offset ? Number.parseInt(offset, 10) : 0; - // Bypass cache if fresh=true or if searching if (fresh || query) { const page = await getDiagramPage({ limit: limitNumber, offset: offsetNumber, query, sort }); const status: CacheStatus = fresh ? 'BYPASS' : 'MISS'; const response = withCacheHeader(NextResponse.json(page), status); - // Add no-cache headers for fresh requests to prevent browser/proxy caching return fresh ? withNoCacheHeaders(response) : response; } - // Try cache first (only for non-search requests) const cache = getCache(); const cacheKey = CacheKeys.diagramList(sort, offsetNumber, limitNumber); const cached = await cache.get(cacheKey); @@ -62,20 +68,17 @@ export async function POST(request: Request) { ); } - const { title, content, emoji, description } = result.data; + const newDiagram = await createDiagram(result.data); - const newDiagram = await createDiagram({ - title, - content, - emoji, - description, - tags: result.data.tags, - }); - - // Invalidate list cache on create const cache = getCache(); await cache.deletePrefix(CachePrefixes.diagramsList); + await publishSyncEvent({ + topic: 'list:diagrams', + payload: { id: newDiagram.id, created: true }, + source: request.headers.get('x-client-id') ?? undefined, + }); + return NextResponse.json(newDiagram); } catch (error) { logApiError('POST /api/diagrams', error); diff --git a/src/app/api/notes/[id]/route.ts b/src/app/api/notes/[id]/route.ts index a88db75..a2b841d 100644 --- a/src/app/api/notes/[id]/route.ts +++ b/src/app/api/notes/[id]/route.ts @@ -5,13 +5,17 @@ import { CacheKeys, CachePrefixes, DEFAULT_TTL_MS, + deleteDocSnapshot, getCache, + getDocSnapshot, + setDocSnapshot, withCacheHeader, withNoCacheHeaders, } from '@/lib/cache'; import { csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; import { logApiError } from '@/lib/logger'; import { deleteNoteById, getNoteById, updateNoteById } from '@/lib/notes-data'; +import { publishSyncEvent } from '@/lib/pubsub'; import { noteUpdateSchema } from '@/lib/schemas'; const PRIVATE_CONTENT_MESSAGE = 'Content policy in effect.'; @@ -19,43 +23,63 @@ type NoteRouteParams = { params: Promise<{ id: string }>; }; -const maskPrivateNote = (note: Note) => ({ - id: note.id, - title: note.title, +const maskPrivateNote = (note: Note): Note => ({ + ...note, content: PRIVATE_CONTENT_MESSAGE, - language: note.language, - starred: note.starred, - private: note.private, - emoji: note.emoji, - tags: note.tags, - createdAt: note.createdAt, - updatedAt: note.updatedAt, }); +const toEtag = (id: string, updatedAt: string) => `W/"note-${id}-${updatedAt}"`; + export async function GET(request: Request, { params }: NoteRouteParams) { try { const { id } = await params; const url = new URL(request.url); const fresh = url.searchParams.get('fresh') === 'true'; + const ifNoneMatch = request.headers.get('if-none-match'); + + const snapshot = await getDocSnapshot('note', id); + if (snapshot) { + const etag = toEtag(id, snapshot.updatedAt); + if (ifNoneMatch && ifNoneMatch === etag) { + return new NextResponse(null, { status: 304, headers: { ETag: etag } }); + } + const payload = snapshot.private ? maskPrivateNote(snapshot) : snapshot; + const response = NextResponse.json(payload); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + const withCache = withCacheHeader(response, fresh ? 'BYPASS' : 'HIT'); + return fresh ? withNoCacheHeaders(withCache) : withCache; + } if (fresh) { const note = await getNoteById(id); if (!note) { return NextResponse.json({ error: 'Note not found' }, { status: 404 }); } - if (note.private) { - const privateNote = maskPrivateNote(note); - return withNoCacheHeaders(withCacheHeader(NextResponse.json(privateNote), 'BYPASS')); - } - return withNoCacheHeaders(withCacheHeader(NextResponse.json(note), 'BYPASS')); + const finalNote = note.private ? maskPrivateNote(note) : note; + await setDocSnapshot('note', id, finalNote as Note); + const etag = toEtag(id, finalNote.updatedAt); + const response = withCacheHeader(NextResponse.json(finalNote), 'BYPASS'); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + return withNoCacheHeaders(response); } const cache = getCache(); const cacheKey = CacheKeys.note(id); - const cached = await cache.get<{ private?: boolean }>(cacheKey); + const cached = await cache.get<{ private?: boolean; updatedAt?: string; createdAt?: string }>( + cacheKey + ); if (cached) { - return withCacheHeader(NextResponse.json(cached), 'HIT'); + const etag = toEtag(id, cached.updatedAt ?? cached.createdAt ?? ''); + if (ifNoneMatch && ifNoneMatch === etag) { + return new NextResponse(null, { status: 304, headers: { ETag: etag } }); + } + const response = NextResponse.json(cached); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + return withCacheHeader(response, 'HIT'); } const note = await getNoteById(id); @@ -64,14 +88,14 @@ export async function GET(request: Request, { params }: NoteRouteParams) { return NextResponse.json({ error: 'Note not found' }, { status: 404 }); } - if (note.private) { - const privateNote = maskPrivateNote(note); - await cache.set(cacheKey, privateNote, DEFAULT_TTL_MS); - return withCacheHeader(NextResponse.json(privateNote), 'MISS'); - } - - await cache.set(cacheKey, note, DEFAULT_TTL_MS); - return withCacheHeader(NextResponse.json(note), 'MISS'); + const finalNote = note.private ? maskPrivateNote(note) : note; + await cache.set(cacheKey, finalNote, DEFAULT_TTL_MS); + await setDocSnapshot('note', id, finalNote as Note); + const etag = toEtag(id, finalNote.updatedAt); + const response = NextResponse.json(finalNote); + response.headers.set('ETag', etag); + response.headers.set('Cache-Control', 'no-cache'); + return withCacheHeader(response, 'MISS'); } catch (error) { logApiError('GET /api/notes/[id]', error); return NextResponse.json({ error: 'Failed to load note' }, { status: 500 }); @@ -111,8 +135,26 @@ export async function PATCH(request: Request, { params }: NoteRouteParams) { const cache = getCache(); await cache.delete(CacheKeys.note(id)); await cache.deletePrefix(CachePrefixes.notesList); + await deleteDocSnapshot('note', id); - return NextResponse.json(updatedNote); + await setDocSnapshot('note', id, updatedNote); + + const source = request.headers.get('x-client-id') ?? undefined; + await publishSyncEvent({ + topic: `doc:note:${id}`, + payload: { id, updatedAt: updatedNote.updatedAt }, + source, + }); + await publishSyncEvent({ + topic: 'list:notes', + payload: { id, updatedAt: updatedNote.updatedAt }, + source, + }); + + const etag = toEtag(id, updatedNote.updatedAt); + const response = NextResponse.json(updatedNote); + response.headers.set('ETag', etag); + return response; } catch (error) { logApiError('PATCH /api/notes/[id]', error); return NextResponse.json({ error: 'Failed to update note' }, { status: 500 }); @@ -136,6 +178,19 @@ export async function DELETE(request: Request, { params }: NoteRouteParams) { await cache.delete(CacheKeys.note(id)); await cache.deletePrefix(CachePrefixes.notesList); + await deleteDocSnapshot('note', id); + + await publishSyncEvent({ + topic: `doc:note:${id}`, + payload: { id, deleted: true }, + source: request.headers.get('x-client-id') ?? undefined, + }); + await publishSyncEvent({ + topic: 'list:notes', + payload: { id, deleted: true }, + source: request.headers.get('x-client-id') ?? undefined, + }); + return NextResponse.json({ success: true }); } catch (error) { logApiError('DELETE /api/notes/[id]', error); diff --git a/src/app/api/notes/route.ts b/src/app/api/notes/route.ts index bf0cc1e..131a4dc 100644 --- a/src/app/api/notes/route.ts +++ b/src/app/api/notes/route.ts @@ -1,93 +1,112 @@ +import { NextResponse } from 'next/server'; + +import { + CacheKeys, + CachePrefixes, + DEFAULT_TTL_MS, + getCache, + type CacheStatus, + withCacheHeader, + withNoCacheHeaders, +} from '@/lib/cache'; import { ensureCsrfCookie, csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; -import { createNote, getNotePage } from '@/lib/notes-data'; import { logApiError } from '@/lib/logger'; +import { createNote, getNotePage } from '@/lib/notes-data'; +import { publishSyncEvent } from '@/lib/pubsub'; import { noteCreateSchema } from '@/lib/schemas'; -import { getCache, CacheKeys, CachePrefixes, DEFAULT_TTL_MS, withCacheHeader, withNoCacheHeaders, type CacheStatus } from '@/lib/cache'; -import { NextResponse } from 'next/server'; const DEFAULT_LIMIT = 24; export async function GET(request: Request) { - try { - await ensureCsrfCookie(); - const url = new URL(request.url); - const limit = url.searchParams.get('limit'); - const offset = url.searchParams.get('offset'); - const query = url.searchParams.get('query') || undefined; - const sort = (url.searchParams.get('sort') as import('@/lib/types').NoteSortOption) || 'recent'; - const starredOnly = url.searchParams.get('starred') === 'true'; - const fresh = url.searchParams.get('fresh') === 'true'; - - const limitNumber = limit ? Number.parseInt(limit, 10) : DEFAULT_LIMIT; - const offsetNumber = offset ? Number.parseInt(offset, 10) : 0; + try { + await ensureCsrfCookie(); + const url = new URL(request.url); + const limit = url.searchParams.get('limit'); + const offset = url.searchParams.get('offset'); + const query = url.searchParams.get('query') || undefined; + const sort = (url.searchParams.get('sort') as import('@/lib/types').NoteSortOption) || 'recent'; + const starredOnly = url.searchParams.get('starred') === 'true'; + const fresh = url.searchParams.get('fresh') === 'true'; - // Bypass cache if fresh=true, searching, or starred filter - if (fresh || query || starredOnly) { - const page = await getNotePage({ limit: limitNumber, offset: offsetNumber, query, sort, starredOnly }); - const status: CacheStatus = fresh ? 'BYPASS' : 'MISS'; - const response = withCacheHeader(NextResponse.json(page), status); - // Add no-cache headers for fresh requests to prevent browser/proxy caching - return fresh ? withNoCacheHeaders(response) : response; - } + const limitNumber = limit ? Number.parseInt(limit, 10) : DEFAULT_LIMIT; + const offsetNumber = offset ? Number.parseInt(offset, 10) : 0; - // Try cache first - const cache = getCache(); - const cacheKey = CacheKeys.noteList(sort, offsetNumber, limitNumber); - const cached = await cache.get(cacheKey); - if (cached) { - return withCacheHeader(NextResponse.json(cached), 'HIT'); - } + if (fresh || query || starredOnly) { + const page = await getNotePage({ + limit: limitNumber, + offset: offsetNumber, + query, + sort, + starredOnly, + }); + const status: CacheStatus = fresh ? 'BYPASS' : 'MISS'; + const response = withCacheHeader(NextResponse.json(page), status); + return fresh ? withNoCacheHeaders(response) : response; + } - const page = await getNotePage({ limit: limitNumber, offset: offsetNumber, query, sort, starredOnly }); - await cache.set(cacheKey, page, DEFAULT_TTL_MS); - return withCacheHeader(NextResponse.json(page), 'MISS'); - } catch (error) { - logApiError('GET /api/notes', error); - return NextResponse.json({ error: 'Failed to load notes' }, { status: 500 }); + const cache = getCache(); + const cacheKey = CacheKeys.noteList(sort, offsetNumber, limitNumber); + const cached = await cache.get(cacheKey); + if (cached) { + return withCacheHeader(NextResponse.json(cached), 'HIT'); } + + const page = await getNotePage({ + limit: limitNumber, + offset: offsetNumber, + query, + sort, + starredOnly, + }); + await cache.set(cacheKey, page, DEFAULT_TTL_MS); + return withCacheHeader(NextResponse.json(page), 'MISS'); + } catch (error) { + logApiError('GET /api/notes', error); + return NextResponse.json({ error: 'Failed to load notes' }, { status: 500 }); + } } export async function POST(request: Request) { - if (!(await validateCsrfToken(request))) { - return csrfFailureResponse(); - } + if (!(await validateCsrfToken(request))) { + return csrfFailureResponse(); + } - try { - const body = await request.json(); - const result = noteCreateSchema.safeParse(body); + try { + const body = await request.json(); + const result = noteCreateSchema.safeParse(body); - if (!result.success) { - return NextResponse.json( - { error: 'Invalid input', details: result.error.flatten() }, - { status: 400 } - ); - } + if (!result.success) { + return NextResponse.json( + { error: 'Invalid input', details: result.error.flatten() }, + { status: 400 } + ); + } - const newNote = await createNote({ - title: result.data.title, - content: result.data.content, - language: result.data.language, - tags: result.data.tags, - }); + const newNote = await createNote(result.data); - // Invalidate list cache on create - const cache = getCache(); - await cache.deletePrefix(CachePrefixes.notesList); + const cache = getCache(); + await cache.deletePrefix(CachePrefixes.notesList); - // Return metadata only (without content for consistency) - return NextResponse.json({ - id: newNote.id, - title: newNote.title, - language: newNote.language, - emoji: newNote.emoji, - starred: newNote.starred, - private: newNote.private, - tags: newNote.tags, - createdAt: newNote.createdAt, - updatedAt: newNote.updatedAt, - }); - } catch (error) { - logApiError('POST /api/notes', error); - return NextResponse.json({ error: 'Unable to create note' }, { status: 500 }); - } + const source = request.headers.get('x-client-id') ?? undefined; + await publishSyncEvent({ + topic: 'list:notes', + payload: { id: newNote.id, created: true }, + source, + }); + + return NextResponse.json({ + id: newNote.id, + title: newNote.title, + language: newNote.language, + emoji: newNote.emoji, + starred: newNote.starred, + private: newNote.private, + tags: newNote.tags, + createdAt: newNote.createdAt, + updatedAt: newNote.updatedAt, + }); + } catch (error) { + logApiError('POST /api/notes', error); + return NextResponse.json({ error: 'Unable to create note' }, { status: 500 }); + } } diff --git a/src/app/api/settings/advanced/route.ts b/src/app/api/settings/advanced/route.ts index d0744dd..6af0626 100644 --- a/src/app/api/settings/advanced/route.ts +++ b/src/app/api/settings/advanced/route.ts @@ -1,55 +1,55 @@ import { csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; import { - getAdvancedSettings, - setMaxCheckpoints, - setAutoSaveDelay, - setDefaultExportFormat, - setExportScale, - type ExportFormat, - type ExportScale, + getAdvancedSettings, + setMaxCheckpoints, + setAutoSaveDelay, + setDefaultExportFormat, + setExportScale, + type ExportFormat, + type ExportScale, } from '@/lib/settings'; import { logApiError } from '@/lib/logger'; import { NextResponse } from 'next/server'; export async function GET() { - try { - const settings = await getAdvancedSettings(); - return NextResponse.json(settings); - } catch (error) { - logApiError('GET /api/settings/advanced', error); - return NextResponse.json({ error: 'Failed to load settings' }, { status: 500 }); - } + try { + const settings = await getAdvancedSettings(); + return NextResponse.json(settings); + } catch (error) { + logApiError('GET /api/settings/advanced', error); + return NextResponse.json({ error: 'Failed to load settings' }, { status: 500 }); + } } export async function PUT(request: Request) { - if (!(await validateCsrfToken(request))) { - return csrfFailureResponse(); - } + if (!(await validateCsrfToken(request))) { + return csrfFailureResponse(); + } - try { - const body = await request.json(); - const { maxCheckpoints, autoSaveDelay, defaultExportFormat, exportScale } = body ?? {}; + try { + const body = await request.json(); + const { maxCheckpoints, autoSaveDelay, defaultExportFormat, exportScale } = body ?? {}; - if (typeof maxCheckpoints === 'number') { - await setMaxCheckpoints(maxCheckpoints); - } - - if (typeof autoSaveDelay === 'number') { - await setAutoSaveDelay(autoSaveDelay); - } + if (typeof maxCheckpoints === 'number') { + await setMaxCheckpoints(maxCheckpoints); + } - if (defaultExportFormat && ['svg', 'png', 'pdf'].includes(defaultExportFormat)) { - await setDefaultExportFormat(defaultExportFormat as ExportFormat); - } + if (typeof autoSaveDelay === 'number') { + await setAutoSaveDelay(autoSaveDelay); + } - if (typeof exportScale === 'number' && [1, 2, 3].includes(exportScale)) { - await setExportScale(exportScale as ExportScale); - } + if (defaultExportFormat && ['svg', 'png', 'pdf'].includes(defaultExportFormat)) { + await setDefaultExportFormat(defaultExportFormat as ExportFormat); + } - const settings = await getAdvancedSettings(); - return NextResponse.json({ success: true, ...settings }); - } catch (error) { - logApiError('PUT /api/settings/advanced', error); - return NextResponse.json({ error: 'Failed to save settings' }, { status: 500 }); + if (typeof exportScale === 'number' && [1, 2, 3].includes(exportScale)) { + await setExportScale(exportScale as ExportScale); } + + const settings = await getAdvancedSettings(); + return NextResponse.json({ success: true, ...settings }); + } catch (error) { + logApiError('PUT /api/settings/advanced', error); + return NextResponse.json({ error: 'Failed to save settings' }, { status: 500 }); + } } diff --git a/src/app/api/settings/ai-key/route.ts b/src/app/api/settings/ai-key/route.ts index 6f6965b..ef178a4 100644 --- a/src/app/api/settings/ai-key/route.ts +++ b/src/app/api/settings/ai-key/route.ts @@ -1,12 +1,19 @@ import { csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; -import { getAiApiKey, getAiProvider, setAiApiKey, setAiProvider, isAiApiKeyFromEnv } from '@/lib/settings'; +import { + getAiApiKey, + getAiProvider, + setAiApiKey, + setAiProvider, + isAiApiKeyFromEnv, +} from '@/lib/settings'; import { logApiError } from '@/lib/logger'; import { NextResponse } from 'next/server'; +import { OPENAI_MODEL, GEMINI_MODEL } from '@/lib/ai/config'; -const OPENAI_MODEL = 'gpt-4o-mini'; -const GEMINI_MODEL = process.env.GEMINI_MODEL || 'gemini-2.5-flash'; - -function resolveModel(apiKey: string | null, provider: 'openai' | 'gemini' | 'auto'): string | null { +function resolveModel( + apiKey: string | null, + provider: 'openai' | 'gemini' | 'auto' +): string | null { if (!apiKey) return null; if (provider === 'gemini') return GEMINI_MODEL; if (provider === 'openai') return OPENAI_MODEL; @@ -27,7 +34,7 @@ export async function GET() { hasKey: Boolean(value), provider, aiModel, - fromEnv, // Indicates key is from environment variable (read-only) + fromEnv, // Indicates key is from environment variable (read-only) }); } catch (error) { logApiError('GET /api/settings/ai-key', error); @@ -65,7 +72,12 @@ export async function PUT(request: Request) { await setAiProvider(provider); } const resolvedProvider = provider ?? (await getAiProvider()); - return NextResponse.json({ success: true, hasKey: Boolean(apiKey), provider: resolvedProvider, fromEnv: false }); + return NextResponse.json({ + success: true, + hasKey: Boolean(apiKey), + provider: resolvedProvider, + fromEnv: false, + }); } catch (error) { logApiError('PUT /api/settings/ai-key', error); return NextResponse.json({ error: 'Failed to save AI key' }, { status: 500 }); diff --git a/src/app/api/settings/cache-status/route.ts b/src/app/api/settings/cache-status/route.ts index 1b71b14..e5eacbb 100644 --- a/src/app/api/settings/cache-status/route.ts +++ b/src/app/api/settings/cache-status/route.ts @@ -2,12 +2,12 @@ import { getCacheStatus, pingCache } from '@/lib/cache'; import { NextResponse } from 'next/server'; export async function GET() { - const status = getCacheStatus(); - const pingMs = await pingCache(); + const status = getCacheStatus(); + const pingMs = await pingCache(); - return NextResponse.json({ - ...status, - pingMs, - healthy: pingMs >= 0, - }); + return NextResponse.json({ + ...status, + pingMs, + healthy: pingMs >= 0, + }); } diff --git a/src/app/api/settings/db-status/route.ts b/src/app/api/settings/db-status/route.ts index 9006e9d..b6c31d8 100644 --- a/src/app/api/settings/db-status/route.ts +++ b/src/app/api/settings/db-status/route.ts @@ -1,12 +1,9 @@ import { NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; +import { resolveDatabaseUrl } from '@/lib/database-url'; type Provider = 'sqlite' | 'postgres' | 'unknown'; -function resolveDatabaseUrl(): string { - return process.env.DATABASE_URL ?? process.env.DB_CONNECTION ?? 'file:./data/atlantis.db'; -} - function describeDatabase(url: string) { if (url.startsWith('file:')) { const path = url.replace('file:', ''); diff --git a/src/app/api/settings/stats/route.ts b/src/app/api/settings/stats/route.ts index b87ba4b..2bb9dfe 100644 --- a/src/app/api/settings/stats/route.ts +++ b/src/app/api/settings/stats/route.ts @@ -2,83 +2,80 @@ import { NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; type ActivityDay = { - date: string; - notes: number; - diagrams: number; + date: string; + notes: number; + diagrams: number; }; export async function GET() { - try { - // Fetch total counts - const [totalNotes, totalDiagrams, totalTags] = await Promise.all([ - prisma.note.count(), - prisma.diagram.count(), - prisma.tag.count(), - ]); + try { + // Fetch total counts + const [totalNotes, totalDiagrams, totalTags] = await Promise.all([ + prisma.note.count(), + prisma.diagram.count(), + prisma.tag.count(), + ]); - // Calculate activity for the last 30 days - const now = new Date(); - const thirtyDaysAgo = new Date(now); - thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 29); - thirtyDaysAgo.setHours(0, 0, 0, 0); + // Calculate activity for the last 30 days + const now = new Date(); + const thirtyDaysAgo = new Date(now); + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 29); + thirtyDaysAgo.setHours(0, 0, 0, 0); - // Fetch notes and diagrams updated in the last 30 days - const [recentNotes, recentDiagrams] = await Promise.all([ - prisma.note.findMany({ - where: { updatedAt: { gte: thirtyDaysAgo } }, - select: { updatedAt: true }, - }), - prisma.diagram.findMany({ - where: { updatedAt: { gte: thirtyDaysAgo } }, - select: { updatedAt: true }, - }), - ]); + // Fetch notes and diagrams updated in the last 30 days + const [recentNotes, recentDiagrams] = await Promise.all([ + prisma.note.findMany({ + where: { updatedAt: { gte: thirtyDaysAgo } }, + select: { updatedAt: true }, + }), + prisma.diagram.findMany({ + where: { updatedAt: { gte: thirtyDaysAgo } }, + select: { updatedAt: true }, + }), + ]); - // Build activity map for the last 30 days - const activityMap = new Map(); + // Build activity map for the last 30 days + const activityMap = new Map(); - // Initialize all 30 days with zeros - for (let i = 0; i < 30; i++) { - const date = new Date(thirtyDaysAgo); - date.setDate(date.getDate() + i); - const dateStr = date.toISOString().split('T')[0]; - activityMap.set(dateStr, { notes: 0, diagrams: 0 }); - } + // Initialize all 30 days with zeros + for (let i = 0; i < 30; i++) { + const date = new Date(thirtyDaysAgo); + date.setDate(date.getDate() + i); + const dateStr = date.toISOString().split('T')[0]; + activityMap.set(dateStr, { notes: 0, diagrams: 0 }); + } - // Count notes per day - for (const note of recentNotes) { - const dateStr = note.updatedAt.toISOString().split('T')[0]; - const existing = activityMap.get(dateStr); - if (existing) { - existing.notes++; - } - } + // Count notes per day + for (const note of recentNotes) { + const dateStr = note.updatedAt.toISOString().split('T')[0]; + const existing = activityMap.get(dateStr); + if (existing) { + existing.notes++; + } + } - // Count diagrams per day - for (const diagram of recentDiagrams) { - const dateStr = diagram.updatedAt.toISOString().split('T')[0]; - const existing = activityMap.get(dateStr); - if (existing) { - existing.diagrams++; - } - } + // Count diagrams per day + for (const diagram of recentDiagrams) { + const dateStr = diagram.updatedAt.toISOString().split('T')[0]; + const existing = activityMap.get(dateStr); + if (existing) { + existing.diagrams++; + } + } - // Convert map to sorted array - const activity: ActivityDay[] = Array.from(activityMap.entries()) - .sort(([a], [b]) => a.localeCompare(b)) - .map(([date, counts]) => ({ date, ...counts })); + // Convert map to sorted array + const activity: ActivityDay[] = Array.from(activityMap.entries()) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([date, counts]) => ({ date, ...counts })); - return NextResponse.json({ - totalNotes, - totalDiagrams, - totalTags, - activity, - }); - } catch (error) { - console.error('Error fetching stats:', error); - return NextResponse.json( - { error: 'Failed to fetch statistics' }, - { status: 500 } - ); - } + return NextResponse.json({ + totalNotes, + totalDiagrams, + totalTags, + activity, + }); + } catch (error) { + console.error('Error fetching stats:', error); + return NextResponse.json({ error: 'Failed to fetch statistics' }, { status: 500 }); + } } diff --git a/src/app/api/settings/sync-status/route.ts b/src/app/api/settings/sync-status/route.ts new file mode 100644 index 0000000..1f9b740 --- /dev/null +++ b/src/app/api/settings/sync-status/route.ts @@ -0,0 +1,8 @@ +import { NextResponse } from 'next/server'; + +import { getPubSubStatus } from '@/lib/pubsub'; + +export async function GET() { + const status = await getPubSubStatus(); + return NextResponse.json(status); +} diff --git a/src/app/api/settings/wipe/route.ts b/src/app/api/settings/wipe/route.ts index 72a2e4e..4891b72 100644 --- a/src/app/api/settings/wipe/route.ts +++ b/src/app/api/settings/wipe/route.ts @@ -8,117 +8,101 @@ const wipeCodeStore = new Map(); const CODE_TTL_MS = 5 * 60 * 1000; // 5 minutes function generateConfirmationCode(): string { - const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; - let code = ''; - for (let i = 0; i < 6; i++) { - code += chars.charAt(Math.floor(Math.random() * chars.length)); - } - return code; + const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; + let code = ''; + for (let i = 0; i < 6; i++) { + code += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return code; } function cleanExpiredCodes() { - const now = Date.now(); - for (const [key, value] of wipeCodeStore.entries()) { - if (value.expires < now) { - wipeCodeStore.delete(key); - } + const now = Date.now(); + for (const [key, value] of wipeCodeStore.entries()) { + if (value.expires < now) { + wipeCodeStore.delete(key); } + } } // GET /api/settings/wipe - Generate a confirmation code (server-side) export async function GET() { - try { - const csrfToken = await ensureCsrfCookie(); - cleanExpiredCodes(); - - const code = generateConfirmationCode(); - wipeCodeStore.set(csrfToken, { - code, - expires: Date.now() + CODE_TTL_MS, - }); - - return NextResponse.json({ code }); - } catch (error) { - console.error('Generate wipe code error:', error); - return NextResponse.json( - { error: 'Failed to generate confirmation code' }, - { status: 500 } - ); - } + try { + const csrfToken = await ensureCsrfCookie(); + cleanExpiredCodes(); + + const code = generateConfirmationCode(); + wipeCodeStore.set(csrfToken, { + code, + expires: Date.now() + CODE_TTL_MS, + }); + + return NextResponse.json({ code }); + } catch (error) { + console.error('Generate wipe code error:', error); + return NextResponse.json({ error: 'Failed to generate confirmation code' }, { status: 500 }); + } } // DELETE /api/settings/wipe - Wipe all data from the database export async function DELETE(request: NextRequest) { - if (!(await validateCsrfToken(request))) { - return csrfFailureResponse(); + if (!(await validateCsrfToken(request))) { + return csrfFailureResponse(); + } + + try { + // Get the CSRF token to look up the stored code + const csrfToken = request.headers.get('x-csrf-token') || ''; + + // Get confirmation code from request body (only user's input, not expected) + const body = await request.json().catch(() => ({})); + const { confirmationCode } = body; + + if (!confirmationCode) { + return NextResponse.json({ error: 'Confirmation code required' }, { status: 400 }); } - try { - // Get the CSRF token to look up the stored code - const csrfToken = request.headers.get('x-csrf-token') || ''; - - // Get confirmation code from request body (only user's input, not expected) - const body = await request.json().catch(() => ({})); - const { confirmationCode } = body; - - if (!confirmationCode) { - return NextResponse.json( - { error: 'Confirmation code required' }, - { status: 400 } - ); - } - - // Validate against server-stored code - const stored = wipeCodeStore.get(csrfToken); - if (!stored) { - return NextResponse.json( - { error: 'No confirmation code issued. Please try again.' }, - { status: 400 } - ); - } - - if (stored.expires < Date.now()) { - wipeCodeStore.delete(csrfToken); - return NextResponse.json( - { error: 'Confirmation code expired. Please try again.' }, - { status: 400 } - ); - } - - // Timing-safe comparison - const isValid = - confirmationCode.length === stored.code.length && - crypto.timingSafeEqual( - Buffer.from(confirmationCode.toUpperCase()), - Buffer.from(stored.code) - ); - - if (!isValid) { - return NextResponse.json( - { error: 'Confirmation code does not match' }, - { status: 400 } - ); - } - - // Clear the used code - wipeCodeStore.delete(csrfToken); - - // Delete all data in order (respecting foreign key constraints) - // Content depends on Diagram, so delete Content first - await prisma.$transaction([ - prisma.content.deleteMany(), - prisma.diagram.deleteMany(), - prisma.note.deleteMany(), - prisma.setting.deleteMany(), - ]); - - return NextResponse.json({ success: true, message: 'All data has been wiped' }); - } catch (error) { - console.error('Wipe database error:', error); - return NextResponse.json( - { error: 'Failed to wipe database' }, - { status: 500 } - ); + // Validate against server-stored code + const stored = wipeCodeStore.get(csrfToken); + if (!stored) { + return NextResponse.json( + { error: 'No confirmation code issued. Please try again.' }, + { status: 400 } + ); } -} + if (stored.expires < Date.now()) { + wipeCodeStore.delete(csrfToken); + return NextResponse.json( + { error: 'Confirmation code expired. Please try again.' }, + { status: 400 } + ); + } + + // Timing-safe comparison + const isValid = + confirmationCode.length === stored.code.length && + crypto.timingSafeEqual(Buffer.from(confirmationCode.toUpperCase()), Buffer.from(stored.code)); + + if (!isValid) { + return NextResponse.json({ error: 'Confirmation code does not match' }, { status: 400 }); + } + + // Clear the used code + wipeCodeStore.delete(csrfToken); + + // Delete all data in order (respecting foreign key constraints) + // Content depends on Diagram, so delete Content first + await prisma.$transaction([ + prisma.content.deleteMany(), + prisma.diagram.deleteMany(), + prisma.note.deleteMany(), + prisma.setting.deleteMany(), + ]); + + return NextResponse.json({ success: true, message: 'All data has been wiped' }); + } catch (error) { + console.error('Wipe database error:', error); + return NextResponse.json({ error: 'Failed to wipe database' }, { status: 500 }); + } +} diff --git a/src/app/api/sync/publish/route.ts b/src/app/api/sync/publish/route.ts new file mode 100644 index 0000000..997b1e6 --- /dev/null +++ b/src/app/api/sync/publish/route.ts @@ -0,0 +1,110 @@ +import { NextResponse } from 'next/server'; + +import { getDocSnapshot, setDocSnapshot } from '@/lib/cache'; +import { csrfFailureResponse, validateCsrfToken } from '@/lib/csrf'; +import { logApiError } from '@/lib/logger'; +import { publishSyncEvent } from '@/lib/pubsub'; +import type { Diagram, Note } from '@/lib/types'; + +export const runtime = 'nodejs'; +export const dynamic = 'force-dynamic'; + +type PublishBody = { + topic?: unknown; + payload?: unknown; + source?: unknown; +}; + +const isRecord = (value: unknown): value is Record => + typeof value === 'object' && value !== null; + +const isDraftDiagramPayload = (value: unknown): value is Diagram => { + if (!isRecord(value)) return false; + return ( + typeof value.id === 'string' && + typeof value.title === 'string' && + typeof value.description === 'string' && + typeof value.content === 'string' && + typeof value.updatedAt === 'string' + ); +}; + +const isDraftNotePayload = (value: unknown): value is Note => { + if (!isRecord(value)) return false; + return ( + typeof value.id === 'string' && + typeof value.title === 'string' && + typeof value.content === 'string' && + typeof value.language === 'string' && + typeof value.updatedAt === 'string' + ); +}; + +const parseTopic = (topic: string): { type: 'diagram' | 'note'; id: string } | null => { + const parts = topic.split(':'); + if (parts.length !== 3) return null; + if (parts[0] !== 'draft') return null; + if (parts[1] !== 'diagram' && parts[1] !== 'note') return null; + if (!parts[2]) return null; + return { type: parts[1], id: parts[2] }; +}; + +export async function POST(request: Request) { + if (!(await validateCsrfToken(request))) { + return csrfFailureResponse(); + } + + try { + const body = (await request.json()) as PublishBody; + const topic = typeof body.topic === 'string' ? body.topic.trim() : ''; + if (!topic) { + return NextResponse.json({ error: 'topic is required' }, { status: 400 }); + } + + const sourceFromBody = typeof body.source === 'string' ? body.source.trim() : ''; + const source = sourceFromBody || request.headers.get('x-client-id') || undefined; + const parsedDraft = parseTopic(topic); + + const payload = body.payload; + + // Optional light de-dupe for draft events to reduce fanout chatter + if (parsedDraft && isRecord(payload)) { + if (parsedDraft.type === 'diagram' && isDraftDiagramPayload(payload)) { + const incoming = payload; + const current = await getDocSnapshot('diagram', parsedDraft.id); + if ( + current && + current.title === incoming.title && + current.description === incoming.description && + current.content === incoming.content + ) { + return NextResponse.json({ success: true, deduped: true }); + } + await setDocSnapshot('diagram', parsedDraft.id, incoming); + } else if (parsedDraft.type === 'note' && isDraftNotePayload(payload)) { + const incoming = payload; + const current = await getDocSnapshot('note', parsedDraft.id); + if ( + current && + current.title === incoming.title && + current.content === incoming.content && + current.language === incoming.language + ) { + return NextResponse.json({ success: true, deduped: true }); + } + await setDocSnapshot('note', parsedDraft.id, incoming); + } + } + + await publishSyncEvent({ + topic, + payload, + source, + }); + + return NextResponse.json({ success: true }); + } catch (error) { + logApiError('POST /api/sync/publish', error); + return NextResponse.json({ error: 'Failed to publish sync event' }, { status: 500 }); + } +} diff --git a/src/app/api/sync/stream/route.ts b/src/app/api/sync/stream/route.ts new file mode 100644 index 0000000..a2cc97f --- /dev/null +++ b/src/app/api/sync/stream/route.ts @@ -0,0 +1,93 @@ +import { NextResponse } from 'next/server'; + +import { subscribeToSyncEvents, type SyncEvent } from '@/lib/pubsub'; + +export const runtime = 'nodejs'; +export const dynamic = 'force-dynamic'; + +const encoder = new TextEncoder(); +const KEEPALIVE_INTERVAL_MS = 25000; +const MAX_TOPICS = 20; +const MAX_TOPIC_LENGTH = 120; + +export async function GET(request: Request) { + const url = new URL(request.url); + const topics = url.searchParams.getAll('topic').filter(Boolean); + + if (topics.length === 0) { + return NextResponse.json({ error: 'Missing topic parameter' }, { status: 400 }); + } + + if (topics.length > MAX_TOPICS || topics.some((topic) => topic.length > MAX_TOPIC_LENGTH)) { + return NextResponse.json({ error: 'Invalid topic parameters' }, { status: 400 }); + } + + let unsubscribe: (() => void) | null = null; + let keepalive: NodeJS.Timeout | null = null; + let closed = false; + + const cleanUp = () => { + closed = true; + if (keepalive) { + clearInterval(keepalive); + keepalive = null; + } + if (unsubscribe) { + unsubscribe(); + unsubscribe = null; + } + }; + + const stream = new ReadableStream({ + start: async (controller) => { + const close = () => { + if (closed) return; + cleanUp(); + try { + controller.close(); + } catch { + /* ignore */ + } + }; + + const safeEnqueue = (payload: string) => { + if (closed) return; + try { + controller.enqueue(encoder.encode(payload)); + } catch { + close(); + } + }; + + const sendSyncEvent = (event: SyncEvent) => { + safeEnqueue(`event: sync\ndata: ${JSON.stringify(event)}\n\n`); + }; + + const sendPing = () => { + safeEnqueue('event: ping\ndata: "keepalive"\n\n'); + }; + + sendPing(); + + unsubscribe = await subscribeToSyncEvents(topics, (event) => { + sendSyncEvent(event); + }); + + keepalive = setInterval(() => { + sendPing(); + }, KEEPALIVE_INTERVAL_MS); + + request.signal.addEventListener('abort', close, { once: true }); + }, + cancel: cleanUp, + }); + + return new Response(stream, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache, no-transform', + Connection: 'keep-alive', + 'X-Accel-Buffering': 'no', + }, + }); +} diff --git a/src/app/diagram/[id]/page.tsx b/src/app/diagram/[id]/page.tsx index 1fe185c..02210ff 100644 --- a/src/app/diagram/[id]/page.tsx +++ b/src/app/diagram/[id]/page.tsx @@ -1,4 +1,3 @@ - import { DiagramEditor } from '@/components/DiagramEditor'; import { getDiagramById } from '@/lib/data'; import { notFound } from 'next/navigation'; @@ -6,38 +5,38 @@ import { notFound } from 'next/navigation'; export const dynamic = 'force-dynamic'; export async function generateMetadata({ params }: PageProps) { - const { id } = await params; - const diagram = await getDiagramById(id); - if (!diagram) { - return { - title: 'Diagram Not Found // Atlantis', - }; - } + const { id } = await params; + const diagram = await getDiagramById(id); + if (!diagram) { return { - title: 'atlantis // diagram', - description: diagram.title, - openGraph: { - title: 'atlantis // diagram', - description: diagram.title, - }, - twitter: { - title: 'atlantis // diagram', - description: diagram.title, - }, + title: 'Diagram Not Found // Atlantis', }; + } + return { + title: 'atlantis // diagram', + description: diagram.title, + openGraph: { + title: 'atlantis // diagram', + description: diagram.title, + }, + twitter: { + title: 'atlantis // diagram', + description: diagram.title, + }, + }; } interface PageProps { - params: Promise<{ id: string }>; + params: Promise<{ id: string }>; } export default async function DiagramPage({ params }: PageProps) { - const { id } = await params; - const diagram = await getDiagramById(id); + const { id } = await params; + const diagram = await getDiagramById(id); - if (!diagram) { - notFound(); - } + if (!diagram) { + notFound(); + } - return ; + return ; } diff --git a/src/app/diagram/page.tsx b/src/app/diagram/page.tsx index 5c9d66c..1e22b8e 100644 --- a/src/app/diagram/page.tsx +++ b/src/app/diagram/page.tsx @@ -1,21 +1,20 @@ - import { DiagramGrid } from '@/components/DiagramGrid'; import { getDiagramPage } from '@/lib/data'; export const dynamic = 'force-dynamic'; export const metadata = { - title: 'atlantis // Diagrams', + title: 'atlantis // Diagrams', }; export default async function Page() { - const page = await getDiagramPage({ limit: 24, offset: 0 }); - return ( - - ); + const page = await getDiagramPage({ limit: 24, offset: 0 }); + return ( + + ); } diff --git a/src/app/docs/page.tsx b/src/app/docs/page.tsx index 47a3fe0..07bc2e2 100644 --- a/src/app/docs/page.tsx +++ b/src/app/docs/page.tsx @@ -9,16 +9,19 @@ export const metadata: Metadata = { export default function DocsPage() { return ( -
-
+
+
- + ← Back to Home

API Documentation

- Explore and test the atlantis API endpoints. - Ensure ENABLE_API_ACCESS=true is set in your environment. + Explore and test the atlantis API endpoints. Ensure ENABLE_API_ACCESS=true{' '} + is set in your environment.

diff --git a/src/app/error.tsx b/src/app/error.tsx index dec0da8..e351ed6 100644 --- a/src/app/error.tsx +++ b/src/app/error.tsx @@ -1,24 +1,24 @@ -'use client' +'use client'; -import { useEffect } from 'react' -import { Button } from '@/components/ui/button' -import { AlertTriangle } from 'lucide-react' +import { useEffect } from 'react'; +import { Button } from '@/components/ui/button'; +import { AlertTriangle } from 'lucide-react'; export default function Error({ error, reset, }: { - error: Error & { digest?: string } - reset: () => void + error: Error & { digest?: string }; + reset: () => void; }) { useEffect(() => { - console.error(error) - }, [error]) + console.error(error); + }, [error]); return (
- +

Something went wrong!

@@ -27,13 +27,11 @@ export default function Error({

- - +
- ) + ); } diff --git a/src/app/globals.css b/src/app/globals.css index fc35d13..6f9f89d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,5 +1,5 @@ -@import "tailwindcss"; -@import "tw-animate-css"; +@import 'tailwindcss'; +@import 'tw-animate-css'; @custom-variant dark (&:is(.dark *)); @@ -79,7 +79,7 @@ --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); - + /* Brand gradients */ --gradient-brand: linear-gradient(to right, #a855f7, #ec4899); --gradient-cta: linear-gradient(to right, #2563eb, #7c3aed); @@ -160,4 +160,3 @@ .animate-snow { animation: snow-fall linear infinite; } - diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 31de0ff..f716ac8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -69,5 +69,3 @@ export default function RootLayout({ ); } - - diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index 86457b4..6cc681b 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -1,24 +1,23 @@ -import Link from 'next/link' -import { Button } from '@/components/ui/button' -import { FileQuestion } from 'lucide-react' +import Link from 'next/link'; +import { Button } from '@/components/ui/button'; +import { FileQuestion } from 'lucide-react'; export default function NotFound() { return (
- +

Page Not Found

- The page you are looking for might have been removed, had its name changed, or is temporarily unavailable. + The page you are looking for might have been removed, had its name changed, or is + temporarily unavailable.

- ) + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 892287a..6f9b4ac 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -48,7 +48,7 @@ export default async function Page() {
{/* Quick Actions - always visible */} -
+
- + 🔱 @@ -460,12 +471,21 @@ export default function SettingsPage() { : 'border-red-200 bg-red-500/10 text-red-600 dark:border-red-800 dark:text-red-300' )} > - {dbStatus.status === 'loading' && } - {dbStatus.status === 'ok' && } - {dbStatus.status === 'error' && } - {dbStatus.status === 'ok' && 'Connected'} - {dbStatus.status === 'loading' && 'Checking...'} - {dbStatus.status === 'error' && 'Error'} + {dbStatus.status === 'loading' && ( + <> + Checking... + + )} + {dbStatus.status === 'ok' && ( + <> + Connected + + )} + {dbStatus.status === 'error' && ( + <> + Error + + )}
@@ -540,12 +560,14 @@ export default function SettingsPage() {

{cacheStatus.enabled ? 'Yes' : 'No'}

+ {cacheStatus.backend !== 'redis' && ( +
+ Redis is not configured. Live sync still works, but collaboration may fall back to + polling and increase database traffic. +
+ )}
- @@ -591,125 +613,62 @@ export default function SettingsPage() {

Activity (Last 30 Days)

{stats.activity.length > 0 ? ( - (() => { - const maxNotes = Math.max(...stats.activity.map((d) => d.notes), 1); - const maxDiagrams = Math.max(...stats.activity.map((d) => d.diagrams), 1); - const maxValue = Math.max(maxNotes, maxDiagrams, 1); - const width = 100; - const height = 100; - const padding = 4; - const graphWidth = width - padding * 2; - const graphHeight = height - padding * 2; - const stepX = graphWidth / (stats.activity.length - 1 || 1); - - const notesPath = stats.activity - .map((day, i) => { - const x = padding + i * stepX; - const y = padding + graphHeight - (day.notes / maxValue) * graphHeight; - return `${i === 0 ? 'M' : 'L'} ${x} ${y}`; - }) - .join(' '); - - const diagramsPath = stats.activity - .map((day, i) => { - const x = padding + i * stepX; - const y = padding + graphHeight - (day.diagrams / maxValue) * graphHeight; - return `${i === 0 ? 'M' : 'L'} ${x} ${y}`; - }) - .join(' '); - - return ( -
- - {/* Grid lines */} - {[0, 0.25, 0.5, 0.75, 1].map((ratio) => ( - - ))} - {/* Notes line (blue) */} - - {/* Diagrams line (emerald) */} - - {/* Data points for notes */} - {stats.activity.map((day, i) => { - const x = padding + i * stepX; - const y = padding + graphHeight - (day.notes / maxValue) * graphHeight; - return ( - - ); - })} - {/* Data points for diagrams */} - {stats.activity.map((day, i) => { - const x = padding + i * stepX; - const y = padding + graphHeight - (day.diagrams / maxValue) * graphHeight; - return ( - - ); - })} - - {/* Legend */} -
-
- - Notes -
-
- - Diagrams -
+ <> + + + + formatActivityDate(String(value))} + /> + } /> + + + + +
+
+
+ + Notes +
+
+ + Diagrams
- ); - })() + {stats.activity.length} days +
+ ) : (

No activity data

)} -
- 30 days ago - Today -
@@ -717,8 +676,6 @@ export default function SettingsPage() { - - {/* Tags Settings */} @@ -727,11 +684,9 @@ export default function SettingsPage() { Tags
- {stats.loading ? ( - 'Loading...' - ) : ( - `Organize your content with tags. (${stats.totalTags} of 25 created)` - )} + {stats.loading + ? 'Loading...' + : `Organize your content with tags. (${stats.totalTags} of 25 created)`} @@ -760,39 +715,24 @@ export default function SettingsPage() {

Choose your preferred theme.

- - - + {[ + { id: 'light', icon: Sun, label: 'Light' }, + { id: 'dark', icon: Moon, label: 'Dark' }, + { id: 'system', icon: Monitor, label: 'System' }, + ].map(({ id, icon: Icon, label }) => ( + + ))}
@@ -806,22 +746,22 @@ export default function SettingsPage() { { - setSnowMode(checked); + updateSettings({ snowMode: checked }); toast.success(checked ? 'Let it snow! ❄️' : 'Snow stopped'); }} />
-

- 🐱 Kitty Mode +

🐱 Kitty Mode

+

+ A playful kitty wanders across your screen!

-

A playful kitty wanders across your screen!

{ - setKittyMode(checked); + updateSettings({ kittyMode: checked }); toast.success(checked ? 'Meow! 🐱' : 'Kitty went to sleep'); }} /> @@ -846,7 +786,7 @@ export default function SettingsPage() { { - setAutoSave(checked); + updateSettings({ autoSave: checked }); toast.success(checked ? 'Auto-save enabled' : 'Auto-save disabled'); }} /> @@ -864,7 +804,7 @@ export default function SettingsPage() { onChange={async (e) => { const val = Number(e.target.value); setLocalAutoSaveDelay(val); - setAutoSaveDelay(val); + updateSettings({ autoSaveDelay: val }); try { const csrf = await ensureCsrfToken(); await fetch('/api/settings/advanced', { @@ -888,39 +828,37 @@ export default function SettingsPage() {

Live Sync

- Automatically sync changes from other users. + Always enabled for realtime updates across sessions.

- { - setLiveSync(checked); - toast.success(checked ? 'Live sync enabled' : 'Live sync disabled'); - }} - /> + Always On
+
-

Sync Interval

+

Sync Transport

- How often to check for updates from others. + Controlled via environment variable.

- + + {LIVE_SYNC_CONFIG.method} +
+ + {LIVE_SYNC_CONFIG.isPolling && ( +
+
+

Sync Interval

+

+ Used only when polling transport is enabled. +

+
+ + {LIVE_SYNC_CONFIG.pollIntervalMs / 1000} seconds + +
+ )} @@ -1138,10 +1076,12 @@ export default function SettingsPage() { exportScale: localExportScale, }), }); - setMaxCheckpoints(localMaxCheckpoints); - setAutoSaveDelay(localAutoSaveDelay); - setDefaultExportFormat(localExportFormat); - setExportScale(localExportScale); + updateSettings({ + maxCheckpoints: localMaxCheckpoints, + autoSaveDelay: localAutoSaveDelay, + defaultExportFormat: localExportFormat, + exportScale: localExportScale, + }); toast.success('Advanced settings saved'); } catch { toast.error('Failed to save settings'); @@ -1173,17 +1113,21 @@ export default function SettingsPage() { Permanently delete all diagrams, notes, and settings.

-
- + {/* Wipe Confirmation Dialog */} - < AlertDialog open={isWipeDialogOpen} onOpenChange={handleWipeDialogClose} > + @@ -1245,10 +1189,10 @@ export default function SettingsPage() { - + {/* Footer */} - < footer className="container mx-auto max-w-2xl px-4 py-8 text-center" > +

Made with ❤️ by Terrestrian 🌏

@@ -1264,7 +1208,7 @@ export default function SettingsPage() { Fantastic-Computing-Machine/atlantis
- - + + ); } diff --git a/src/app/tags/page.tsx b/src/app/tags/page.tsx index 7e482bc..2cfef7c 100644 --- a/src/app/tags/page.tsx +++ b/src/app/tags/page.tsx @@ -8,61 +8,59 @@ import { Button } from '@/components/ui/button'; export const dynamic = 'force-dynamic'; export default async function TagsPage() { - const tags = await prisma.tag.findMany({ - orderBy: { name: 'asc' }, - include: { - _count: { - select: { diagrams: true, notes: true } - } - } - }); + const tags = await prisma.tag.findMany({ + orderBy: { name: 'asc' }, + include: { + _count: { + select: { diagrams: true, notes: true }, + }, + }, + }); - return ( -
- + return ( +
+ -
-
-
- -

All Tags

-
- -
+
+
+
+ +

All Tags

+
+ +
- {tags.length === 0 ? ( -
- -

No tags found

-

Tags will appear here once you create them.

+ {tags.length === 0 ? ( +
+ +

No tags found

+

Tags will appear here once you create them.

+
+ ) : ( +
+ {tags.map((tag) => ( + + + + #{tag.name} +
+ + +
+ {tag._count.diagrams + tag._count.notes} items
- ) : ( -
- {tags.map((tag) => ( - - - - - #{tag.name} - -
- - -
- {tag._count.diagrams + tag._count.notes} items -
-
- - - ))} -
- )} -
-
- ); + + + + ))} +
+ )} + + + ); } diff --git a/src/components/AiChatPanel.tsx b/src/components/AiChatPanel.tsx index d819cd8..6b5ae6a 100644 --- a/src/components/AiChatPanel.tsx +++ b/src/components/AiChatPanel.tsx @@ -59,11 +59,11 @@ export function AiChatPanel({ diagramId, currentContent, onApply }: AiChatPanelP }; return ( -
-
+
+
- - AI assistant + + AI assistant
{isLoading ? 'Thinking…' : 'Ready'}
@@ -79,9 +79,8 @@ export function AiChatPanel({ diagramId, currentContent, onApply }: AiChatPanelP

)}
-
-

+

AI can make mistakes. Please cross-check the output.

diff --git a/src/components/Canvas.tsx b/src/components/Canvas.tsx index 8f5b124..996830f 100644 --- a/src/components/Canvas.tsx +++ b/src/components/Canvas.tsx @@ -90,7 +90,12 @@ const isNodeElement = (element: Element): boolean => { if (classList.includes('node') || classList.includes('cluster')) return true; if (classList.some((cls) => cls.endsWith('node') || cls.includes('node'))) return true; const id = element.getAttribute('id') ?? ''; - if (/^(flowchart|graph|classDiagram|stateDiagram|erDiagram|gitGraph|mindmap|timeline|quadrantChart|requirementDiagram|c4|sankey|xyChart|block|packet|kanban|pie|gantt|sequence|journey|treemap|architecture)-/i.test(id)) return true; + if ( + /^(flowchart|graph|classDiagram|stateDiagram|erDiagram|gitGraph|mindmap|timeline|quadrantChart|requirementDiagram|c4|sankey|xyChart|block|packet|kanban|pie|gantt|sequence|journey|treemap|architecture)-/i.test( + id + ) + ) + return true; return !!element.querySelector('title'); }; @@ -161,8 +166,8 @@ export function Canvas({ code, diagramId, title, selectedNodeId, onNodeSelect }: typeof err === 'string' ? err : (err as { str?: string; message?: string }).str || - (err as { str?: string; message?: string }).message || - 'Mermaid parse error'; + (err as { str?: string; message?: string }).message || + 'Mermaid parse error'; throw new Error(message); }, }); @@ -615,7 +620,12 @@ export function Canvas({ code, diagramId, title, selectedNodeId, onNodeSelect }: - @@ -666,7 +676,12 @@ export function Canvas({ code, diagramId, title, selectedNodeId, onNodeSelect }: - @@ -743,7 +758,12 @@ export function Canvas({ code, diagramId, title, selectedNodeId, onNodeSelect }: - - - - - History - {checkpoints.length} versions - + return ( + <> + + + + + + + History + + {checkpoints.length} versions + + -
- -
+
+ +
- + - - {isLoading ? ( -
Loading...
- ) : checkpoints.length === 0 ? ( -
- No checkpoints yet. -
- ) : ( -
- {checkpoints.map((cp, index) => { - const isCurrent = index === 0 || cp.id === currentCheckpointId; - const isViewing = cp.id === viewingCheckpointId; + + {isLoading ? ( +
Loading...
+ ) : checkpoints.length === 0 ? ( +
+ No checkpoints yet. +
+ ) : ( +
+ {checkpoints.map((cp, index) => { + const isCurrent = index === 0 || cp.id === currentCheckpointId; + const isViewing = cp.id === viewingCheckpointId; - return ( - onViewCheckpoint(cp.id)} - className="flex flex-col items-start gap-1 py-3 cursor-pointer group" - > -
-
- - {formatDate(cp.updatedAt)} - - {isCurrent && ( - - - Current - - )} - {isViewing && !isCurrent && ( - - Viewing - - )} -
-
- {!isCurrent && ( - <> - - - - )} -
-
- - {cp.content.slice(0, 60).replace(/\n/g, ' ')}... - -
- ); - })} -
- )} -
- - + return ( + onViewCheckpoint(cp.id)} + className="group flex cursor-pointer flex-col items-start gap-1 py-3" + > +
+
+ {formatDate(cp.updatedAt)} + {isCurrent && ( + + + Current + + )} + {isViewing && !isCurrent && ( + + Viewing + + )} +
+
+ {!isCurrent && ( + <> + + + + )} +
+
+ + {cp.content.slice(0, 60).replace(/\n/g, ' ')}... + +
+ ); + })} +
+ )} +
+
+
- !open && setDeleteConfirmId(null)}> - - - Delete Checkpoint? - - This will permanently delete this checkpoint. This action cannot be undone. - - - - Cancel - - Delete - - - - - - ); + !open && setDeleteConfirmId(null)} + > + + + Delete Checkpoint? + + This will permanently delete this checkpoint. This action cannot be undone. + + + + Cancel + + Delete + + + + + + ); } diff --git a/src/components/ConsoleWelcome.tsx b/src/components/ConsoleWelcome.tsx index 4309ff6..3bccc88 100644 --- a/src/components/ConsoleWelcome.tsx +++ b/src/components/ConsoleWelcome.tsx @@ -1,6 +1,6 @@ -"use client"; +'use client'; -import { useEffect } from "react"; +import { useEffect } from 'react'; export function ConsoleWelcome() { useEffect(() => { @@ -15,7 +15,7 @@ export function ConsoleWelcome() { A' VML .AMA. .AMMA. `, - "font-family: monospace; color: #3b82f6; font-weight: bold;" + 'font-family: monospace; color: #3b82f6; font-weight: bold;' ); }, []); diff --git a/src/components/DashboardCardMenu.tsx b/src/components/DashboardCardMenu.tsx index c852e91..52140b3 100644 --- a/src/components/DashboardCardMenu.tsx +++ b/src/components/DashboardCardMenu.tsx @@ -5,196 +5,198 @@ import { useRouter } from 'next/navigation'; import { MoreHorizontal, Star, Trash2, Download, Share2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { CSRF_HEADER_NAME, ensureCsrfToken } from '@/lib/csrf-client'; import { copyToClipboard, cn } from '@/lib/utils'; import { toast } from 'sonner'; interface DashboardCardMenuProps { - id: string; - title: string; - type: 'diagram' | 'note'; - isStarred: boolean; + id: string; + title: string; + type: 'diagram' | 'note'; + isStarred: boolean; } export function DashboardCardMenu({ id, title, type, isStarred }: DashboardCardMenuProps) { - const router = useRouter(); - const [starred, setStarred] = useState(isStarred); - const [showDelete, setShowDelete] = useState(false); - - const handleStar = async (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - - const newStarred = !starred; - setStarred(newStarred); - - try { - const csrfToken = await ensureCsrfToken(); - const url = type === 'diagram' ? `/api/diagrams/${id}` : `/api/notes/${id}`; - const body = type === 'diagram' ? { isFavorite: newStarred } : { starred: newStarred }; - - const res = await fetch(url, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - [CSRF_HEADER_NAME]: csrfToken, - }, - body: JSON.stringify(body), - }); - - if (!res.ok) throw new Error('Failed to update'); - router.refresh(); - } catch (error) { - console.error('DashboardCardMenu: Failed to update star status:', error); - setStarred(!newStarred); - toast.error('Failed to update'); - } - }; - - const handleDelete = async () => { - try { - const csrfToken = await ensureCsrfToken(); - const url = type === 'diagram' ? `/api/diagrams/${id}` : `/api/notes/${id}`; - - const res = await fetch(url, { - method: 'DELETE', - headers: { - [CSRF_HEADER_NAME]: csrfToken, - }, - }); - - if (!res.ok) throw new Error('Failed to delete'); - toast.success(`${type === 'diagram' ? 'Diagram' : 'Note'} deleted`); - router.refresh(); - } catch (error) { - console.error('DashboardCardMenu: Failed to delete item:', error); - toast.error('Failed to delete'); - } - setShowDelete(false); - }; - - const handleShare = async (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - const path = type === 'diagram' ? `/diagram/${id}` : `/notes/${id}`; - const url = `${window.location.origin}${path}`; - const success = await copyToClipboard(url); - if (success) { - toast.success('Link copied'); - } else { - toast.error('Failed to copy'); - } - }; - - const handleDownload = async (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - - if (type === 'note') { - // Download note as .txt - try { - const res = await fetch(`/api/notes/${id}`); - const note = await res.json(); - const blob = new Blob([note.content || ''], { type: 'text/plain' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `${title || 'note'}.txt`; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - toast.success('Downloaded'); - } catch (error) { - console.error('DashboardCardMenu: Failed to download:', error); - toast.error('Failed to download'); - } - } else { - // For diagrams, navigate to the diagram page where full download options exist - window.open(`/diagram/${id}`, '_blank'); - } - }; - - return ( - <> - - - - - - - - Copy link - - - - {starred ? 'Unstar' : 'Star'} - - - - Download - - - { - e.preventDefault(); - e.stopPropagation(); - setShowDelete(true); - }} - > - - Delete - - - - - - - - Delete {type}? - - This will permanently delete “{title}”. This action cannot be undone. - - - - Cancel - - Delete - - - - - - ); + const router = useRouter(); + const [starred, setStarred] = useState(isStarred); + const [showDelete, setShowDelete] = useState(false); + + const handleStar = async (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + + const newStarred = !starred; + setStarred(newStarred); + + try { + const csrfToken = await ensureCsrfToken(); + const url = type === 'diagram' ? `/api/diagrams/${id}` : `/api/notes/${id}`; + const body = type === 'diagram' ? { isFavorite: newStarred } : { starred: newStarred }; + + const res = await fetch(url, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + [CSRF_HEADER_NAME]: csrfToken, + }, + body: JSON.stringify(body), + }); + + if (!res.ok) throw new Error('Failed to update'); + router.refresh(); + } catch (error) { + console.error('DashboardCardMenu: Failed to update star status:', error); + setStarred(!newStarred); + toast.error('Failed to update'); + } + }; + + const handleDelete = async () => { + try { + const csrfToken = await ensureCsrfToken(); + const url = type === 'diagram' ? `/api/diagrams/${id}` : `/api/notes/${id}`; + + const res = await fetch(url, { + method: 'DELETE', + headers: { + [CSRF_HEADER_NAME]: csrfToken, + }, + }); + + if (!res.ok) throw new Error('Failed to delete'); + toast.success(`${type === 'diagram' ? 'Diagram' : 'Note'} deleted`); + router.refresh(); + } catch (error) { + console.error('DashboardCardMenu: Failed to delete item:', error); + toast.error('Failed to delete'); + } + setShowDelete(false); + }; + + const handleShare = async (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + const path = type === 'diagram' ? `/diagram/${id}` : `/notes/${id}`; + const url = `${window.location.origin}${path}`; + const success = await copyToClipboard(url); + if (success) { + toast.success('Link copied'); + } else { + toast.error('Failed to copy'); + } + }; + + const handleDownload = async (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + + if (type === 'note') { + // Download note as .txt + try { + const res = await fetch(`/api/notes/${id}`); + const note = await res.json(); + const blob = new Blob([note.content || ''], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `${title || 'note'}.txt`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + toast.success('Downloaded'); + } catch (error) { + console.error('DashboardCardMenu: Failed to download:', error); + toast.error('Failed to download'); + } + } else { + // For diagrams, navigate to the diagram page where full download options exist + window.open(`/diagram/${id}`, '_blank'); + } + }; + + return ( + <> + + + + + + + + Copy link + + + + {starred ? 'Unstar' : 'Star'} + + + + Download + + + { + e.preventDefault(); + e.stopPropagation(); + setShowDelete(true); + }} + > + + Delete + + + + + + + + Delete {type}? + + This will permanently delete “{title}”. This action cannot be undone. + + + + Cancel + + Delete + + + + + + ); } diff --git a/src/components/DashboardCards.tsx b/src/components/DashboardCards.tsx index 402c350..92f702e 100644 --- a/src/components/DashboardCards.tsx +++ b/src/components/DashboardCards.tsx @@ -10,127 +10,128 @@ import { Diagram, Note } from '@/lib/types'; import { ArrowRight } from 'lucide-react'; export function CompactCard({ - type, - item, + type, + item, }: { - type: 'diagram' | 'note'; - item: Diagram | Omit; + type: 'diagram' | 'note'; + item: Diagram | Omit; }) { - const href = type === 'diagram' ? `/diagram/${item.id}` : `/notes/${item.id}`; - const icon = item.emoji || (type === 'diagram' ? '📊' : '📝'); + const href = type === 'diagram' ? `/diagram/${item.id}` : `/notes/${item.id}`; + const icon = item.emoji || (type === 'diagram' ? '📊' : '📝'); - return ( - - {icon} - {item.title} - - ); + return ( + + {icon} + {item.title} + + ); } export function DashboardCard({ - type, - item, + type, + item, }: { - type: 'diagram' | 'note'; - item: Diagram | Omit; + type: 'diagram' | 'note'; + item: Diagram | Omit; }) { - const href = type === 'diagram' ? `/diagram/${item.id}` : `/notes/${item.id}`; - const icon = item.emoji || (type === 'diagram' ? '📊' : '📝'); - const description = type === 'diagram' ? (item as Diagram).description : (item as Note).language; - const badgeLabel = type === 'diagram' ? 'Diagram' : 'Note'; - const isStarred = type === 'diagram' ? (item as Diagram).isFavorite : (item as Omit).starred; + const href = type === 'diagram' ? `/diagram/${item.id}` : `/notes/${item.id}`; + const icon = item.emoji || (type === 'diagram' ? '📊' : '📝'); + const description = type === 'diagram' ? (item as Diagram).description : (item as Note).language; + const badgeLabel = type === 'diagram' ? 'Diagram' : 'Note'; + const isStarred = + type === 'diagram' ? (item as Diagram).isFavorite : (item as Omit).starred; - return ( - - - View {item.title} - - -
- {/* Left: emoji + title + badge */} -
- {icon} -
-
- {item.title} - - {badgeLabel} - -
- - {formatDate(item.updatedAt)} - -
-
- {/* Right: 3-dot menu */} -
- -
-
-
- -

- {type === 'diagram' ? description || 'No description' : `Language // ${description}`} -

- {item.tags && item.tags.length > 0 && ( -
- {item.tags.slice(0, 2).map((tag) => ( - - ))} - {item.tags.length > 2 && ( - +{item.tags.length - 2} - )} -
- )} -
-
- ); + return ( + + + View {item.title} + + +
+ {/* Left: emoji + title + badge */} +
+ {icon} +
+
+ {item.title} + + {badgeLabel} + +
+ + {formatDate(item.updatedAt)} + +
+
+ {/* Right: 3-dot menu */} +
+ +
+
+
+ +

+ {type === 'diagram' ? description || 'No description' : `Language // ${description}`} +

+ {item.tags && item.tags.length > 0 && ( +
+ {item.tags.slice(0, 2).map((tag) => ( + + ))} + {item.tags.length > 2 && ( + +{item.tags.length - 2} + )} +
+ )} +
+
+ ); } export function EmptySectionPlaceholder({ - icon, - title, - description, - ctaLabel, - ctaHref, + icon, + title, + description, + ctaLabel, + ctaHref, }: { - icon: ReactNode; - title: string; - description: string; - ctaLabel: string; - ctaHref: string; + icon: ReactNode; + title: string; + description: string; + ctaLabel: string; + ctaHref: string; }) { - return ( -
-
- - {icon} - - {title} -
-

{description}

- - {ctaLabel} - - -
- ); + return ( +
+
+ + {icon} + + {title} +
+

{description}

+ + {ctaLabel} + + +
+ ); } diff --git a/src/components/DashboardHeader.tsx b/src/components/DashboardHeader.tsx index d18fbaf..fd5912d 100644 --- a/src/components/DashboardHeader.tsx +++ b/src/components/DashboardHeader.tsx @@ -23,7 +23,7 @@ interface DashboardHeaderProps { } export function DashboardHeader({ enableApiAccess }: DashboardHeaderProps) { - const { settings, setHasAiApiKey, setAiProvider } = useDiagramStore(); + const { settings, updateSettings } = useDiagramStore(); const { isMac } = useShortcutPlatform(); const { setPaletteOpen } = useKeyboardShortcuts(); @@ -34,17 +34,17 @@ export function DashboardHeader({ enableApiAccess }: DashboardHeaderProps) { const res = await fetch('/api/settings/ai-key'); const data = await res.json(); if (typeof data.hasKey === 'boolean') { - setHasAiApiKey(data.hasKey); + updateSettings({ hasAiApiKey: data.hasKey }); } if (typeof data.provider === 'string') { - setAiProvider(data.provider); + updateSettings({ aiProvider: data.provider }); } } catch { // ignore } }; loadAiKey(); - }, [setHasAiApiKey, setAiProvider]); + }, [updateSettings]); return (
diff --git a/src/components/DashboardSection.tsx b/src/components/DashboardSection.tsx index 4e9012b..a813f4b 100644 --- a/src/components/DashboardSection.tsx +++ b/src/components/DashboardSection.tsx @@ -6,102 +6,102 @@ import { Diagram, Note } from '@/lib/types'; import { DashboardCard, EmptySectionPlaceholder } from './DashboardCards'; interface DashboardSectionProps { - items: (Diagram | Omit)[]; - title: string; + items: (Diagram | Omit)[]; + title: string; + icon: React.ReactNode; + viewAllHref: string; + type: 'diagram' | 'note'; + emptyState: { icon: React.ReactNode; - viewAllHref: string; - type: 'diagram' | 'note'; - emptyState: { - icon: React.ReactNode; - title: string; - description: string; - ctaHref: string; - ctaLabel: string; - }; + title: string; + description: string; + ctaHref: string; + ctaLabel: string; + }; } function isToday(dateStr: string): boolean { - const date = new Date(dateStr); - const today = new Date(); - return date.toDateString() === today.toDateString(); + const date = new Date(dateStr); + const today = new Date(); + return date.toDateString() === today.toDateString(); } function groupByTime(items: T[]) { - const today: T[] = []; - const earlier: T[] = []; - for (const item of items) { - if (isToday(item.updatedAt)) { - today.push(item); - } else { - earlier.push(item); - } + const today: T[] = []; + const earlier: T[] = []; + for (const item of items) { + if (isToday(item.updatedAt)) { + today.push(item); + } else { + earlier.push(item); } - return { today, earlier }; + } + return { today, earlier }; } export function DashboardSection({ - items, - title, - icon, - viewAllHref, - type, - emptyState, + items, + title, + icon, + viewAllHref, + type, + emptyState, }: DashboardSectionProps) { - const { today, earlier } = groupByTime(items); + const { today, earlier } = groupByTime(items); - return ( -
-
-

- {icon} - {title} {'//'}{' '} - {items.length} -

- - View all - + return ( +
+
+

+ {icon} + {title} {'//'}{' '} + {items.length} +

+ + View all + +
+ {items.length > 0 ? ( +
+ {/* Today */} + {today.length > 0 && ( +
+

+ Today +

+
+ {today.map((item) => ( + + ))} +
+
+ )} + {/* Earlier */} + {earlier.length > 0 && ( +
+

+ Earlier +

+
+ {earlier.map((item) => ( + + ))} +
- {items.length > 0 ? ( -
- {/* Today */} - {today.length > 0 && ( -
-

- Today -

-
- {today.map((item) => ( - - ))} -
-
- )} - {/* Earlier */} - {earlier.length > 0 && ( -
-

- Earlier -

-
- {earlier.map((item) => ( - - ))} -
-
- )} -
- ) : ( - - )} -
- ); + )} +
+ ) : ( + + )} +
+ ); } diff --git a/src/components/DiagramEditor.tsx b/src/components/DiagramEditor.tsx index 88d46d6..1e48a95 100644 --- a/src/components/DiagramEditor.tsx +++ b/src/components/DiagramEditor.tsx @@ -31,9 +31,10 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/componen import { Textarea } from '@/components/ui/textarea'; import { ResponsiveTagPicker } from '@/components/responsive-tag-picker'; import { CSRF_HEADER_NAME, ensureCsrfToken } from '@/lib/csrf-client'; +import { LIVE_SYNC_CONFIG } from '@/lib/live-sync-config'; import { useDiagramStore } from '@/lib/store'; import { Checkpoint, Diagram, Tag } from '@/lib/types'; -import { useLiveSync } from '@/lib/useLiveSync'; +import { getLiveSyncClientId, useLiveSync } from '@/lib/useLiveSync'; import { copyToClipboard, formatDate, cn } from '@/lib/utils'; import { @@ -244,6 +245,13 @@ const upsertNodeStyleLine = (content: string, nodeId: string, color: string | nu return lines.join('\n'); }; +const nextIsoAfter = (currentIso: string): string => { + const currentMs = Date.parse(currentIso); + const nowMs = Date.now(); + const nextMs = Number.isFinite(currentMs) ? Math.max(nowMs, currentMs + 1) : nowMs; + return new Date(nextMs).toISOString(); +}; + export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { const router = useRouter(); const [diagram, setDiagram] = useState(initialDiagram); @@ -263,14 +271,16 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { const settings = useDiagramStore((state) => state.settings); const updateDiagram = useDiagramStore((state) => state.updateDiagram); const removeDiagram = useDiagramStore((state) => state.removeDiagram); - const setHasAiApiKey = useDiagramStore((state) => state.setHasAiApiKey); - const setAiProvider = useDiagramStore((state) => state.setAiProvider); + const updateSettings = useDiagramStore((state) => state.updateSettings); const autoSaveTimerRef = useRef(null); + const draftPublishTimerRef = useRef(null); const lastSavedContentRef = useRef(initialDiagram.content); const lastSavedTitleRef = useRef(initialDiagram.title); const lastSavedDescriptionRef = useRef(initialDiagram.description); const lastSavedTagsRef = useRef(initialDiagram.tags || []); + const draftSeqRef = useRef(0); const selectedNodeId = selectedNode?.id ?? null; + const clientId = useMemo(() => getLiveSyncClientId(), []); const [aiChatOpen, setAiChatOpen] = useState(false); const [activePane, setActivePane] = useState<'editor' | 'preview'>('preview'); @@ -278,15 +288,76 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { const hasLocalChanges = diagram.content !== lastSavedContentRef.current || diagram.title !== lastSavedTitleRef.current || - diagram.description !== lastSavedDescriptionRef.current; + diagram.description !== lastSavedDescriptionRef.current || + JSON.stringify(tags) !== JSON.stringify(lastSavedTagsRef.current); + + const publishDraftUpdate = useCallback( + async (nextDiagram: Diagram) => { + if (!mounted) return; + + try { + const csrfToken = await ensureCsrfToken(); + const seq = ++draftSeqRef.current; + await fetch('/api/sync/publish', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + [CSRF_HEADER_NAME]: csrfToken, + 'x-client-id': clientId, + }, + body: JSON.stringify({ + topic: `draft:diagram:${nextDiagram.id}`, + source: clientId, + payload: { + ...nextDiagram, + tags, + seq, + }, + }), + }); + } catch { + // ignore draft sync errors; autosave remains source of truth + } + }, + [clientId, mounted, tags] + ); + + const queueDraftUpdate = useCallback( + (nextDiagram: Diagram) => { + if (!mounted) return; + + if (draftPublishTimerRef.current) { + clearTimeout(draftPublishTimerRef.current); + } + + draftPublishTimerRef.current = setTimeout(() => { + draftPublishTimerRef.current = null; + void publishDraftUpdate(nextDiagram); + }, 180); + }, + [mounted, publishDraftUpdate] + ); - // Live sync: poll for external changes from other users - const { refresh: syncFromServer } = useLiveSync({ + useLiveSync({ resourceUrl: `/api/diagrams/${diagram.id}`, currentUpdatedAt: diagram.updatedAt, hasLocalChanges, - enabled: Boolean(settings.liveSync) && mounted, - intervalMs: settings.liveSyncInterval ?? 5000, + enabled: LIVE_SYNC_CONFIG.enabled && mounted, + intervalMs: LIVE_SYNC_CONFIG.pollIntervalMs, + liveSyncMethod: LIVE_SYNC_CONFIG.method, + eventTopics: [`doc:diagram:${diagram.id}`, `draft:diagram:${diagram.id}`], + allowWhileDirty: true, + isInstantPayload: (payload): payload is Diagram => { + if (!payload || typeof payload !== 'object') return false; + const candidate = payload as Partial; + return ( + typeof candidate.id === 'string' && + typeof candidate.title === 'string' && + typeof candidate.description === 'string' && + typeof candidate.content === 'string' && + typeof candidate.updatedAt === 'string' + ); + }, onUpdate: (remoteDiagram) => { setDiagram(remoteDiagram); setTags(remoteDiagram.tags || []); @@ -306,23 +377,31 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { setMounted(true); }, []); + useEffect(() => { + return () => { + if (draftPublishTimerRef.current) { + clearTimeout(draftPublishTimerRef.current); + } + }; + }, []); + useEffect(() => { const loadAiKey = async () => { try { const res = await fetch('/api/settings/ai-key'); const data = await res.json(); if (typeof data.hasKey === 'boolean') { - setHasAiApiKey(data.hasKey); + updateSettings({ hasAiApiKey: data.hasKey }); } if (typeof data.provider === 'string') { - setAiProvider(data.provider); + updateSettings({ aiProvider: data.provider }); } } catch { // silently ignore; AI is optional } }; loadAiKey(); - }, [setHasAiApiKey, setAiProvider]); + }, [updateSettings]); useEffect(() => { if (!selectedNodeId) { @@ -333,18 +412,40 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { setSelectionRange(range); }, [diagram.content, selectedNodeId]); + useEffect(() => { + if (!mounted) return; + const tagsChanged = JSON.stringify(tags) !== JSON.stringify(lastSavedTagsRef.current); + if (!tagsChanged) return; + + const nextDiagram = { + ...diagram, + tags, + updatedAt: nextIsoAfter(diagram.updatedAt), + }; + queueDraftUpdate(nextDiagram); + }, [diagram, mounted, queueDraftUpdate, tags]); + const handleEditorChange = (value: string) => { // Ignore changes when viewing a past checkpoint (read-only mode) if (viewingCheckpointId !== null) return; - setDiagram((prev) => ({ ...prev, content: value })); + const nextUpdatedAt = nextIsoAfter(diagram.updatedAt); + const nextDiagram = { ...diagram, content: value, updatedAt: nextUpdatedAt }; + setDiagram(nextDiagram); + queueDraftUpdate(nextDiagram); }; const handleTitleChange = (e: React.ChangeEvent) => { - setDiagram((prev) => ({ ...prev, title: e.target.value })); + const nextUpdatedAt = nextIsoAfter(diagram.updatedAt); + const nextDiagram = { ...diagram, title: e.target.value, updatedAt: nextUpdatedAt }; + setDiagram(nextDiagram); + queueDraftUpdate(nextDiagram); }; const handleDescriptionChange = (e: React.ChangeEvent) => { - setDiagram((prev) => ({ ...prev, description: e.target.value })); + const nextUpdatedAt = nextIsoAfter(diagram.updatedAt); + const nextDiagram = { ...diagram, description: e.target.value, updatedAt: nextUpdatedAt }; + setDiagram(nextDiagram); + queueDraftUpdate(nextDiagram); }; const handleNodeSelect = useCallback( @@ -384,12 +485,16 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { const handleNodeColorChange = useCallback( (color: string | null) => { if (!selectedNodeId) return; - setDiagram((prev) => { - const updatedContent = upsertNodeStyleLine(prev.content, selectedNodeId, color); - return { ...prev, content: updatedContent }; - }); + const updatedContent = upsertNodeStyleLine(diagram.content, selectedNodeId, color); + const nextDiagram = { + ...diagram, + content: updatedContent, + updatedAt: nextIsoAfter(diagram.updatedAt), + }; + setDiagram(nextDiagram); + queueDraftUpdate(nextDiagram); }, - [selectedNodeId] + [diagram, queueDraftUpdate, selectedNodeId] ); const handleToggleAiChat = useCallback(() => { @@ -398,10 +503,16 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { const handleApplyAiContent = useCallback( (content: string) => { - setDiagram((prev) => ({ ...prev, content })); + const nextDiagram = { + ...diagram, + content, + updatedAt: nextIsoAfter(diagram.updatedAt), + }; + setDiagram(nextDiagram); + queueDraftUpdate(nextDiagram); updateDiagram(diagram.id, { content }); }, - [diagram.id, updateDiagram] + [diagram, queueDraftUpdate, updateDiagram] ); const saveChanges = useCallback( @@ -413,6 +524,7 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { headers: { 'Content-Type': 'application/json', [CSRF_HEADER_NAME]: csrfToken, + 'x-client-id': clientId, }, body: JSON.stringify({ ...diagram, tags: tags.map((t) => t.id) }), }); @@ -435,13 +547,11 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { if (showToast) { toast.success('Changes saved'); } - // Sync from server after save to pull any concurrent changes - syncFromServer(); } catch { toast.error('Failed to save changes'); } }, - [diagram, updateDiagram, syncFromServer, tags] + [diagram, updateDiagram, tags, clientId] ); // Ctrl+S to save @@ -462,27 +572,21 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { }, [saveChanges, viewingCheckpointId]); // Auto-save with debounce - // Content-only auto-save with debounce useEffect(() => { - // Don't auto-save when viewing a past checkpoint - if (!settings.autoSave || viewingCheckpointId !== null) return; - - const hasContentChanged = diagram.content !== lastSavedContentRef.current; - const hasTitleChanged = diagram.title !== lastSavedTitleRef.current; - const hasDescriptionChanged = diagram.description !== lastSavedDescriptionRef.current; - - // Explicitly exclude tags from this check - if (!hasContentChanged && !hasTitleChanged && !hasDescriptionChanged) return; + // Don't auto-save when viewing a past checkpoint or if there are no changes + if (!settings.autoSave || viewingCheckpointId !== null || !hasLocalChanges) return; // Clear existing timer if (autoSaveTimerRef.current) { clearTimeout(autoSaveTimerRef.current); } - // Set new timer for auto-save (2 second debounce) + const autoSaveDelay = settings.autoSaveDelay ?? 2000; + + // Set new timer for auto-save autoSaveTimerRef.current = setTimeout(() => { saveChanges(false); // Silent save - }, 2000); + }, autoSaveDelay); return () => { if (autoSaveTimerRef.current) { @@ -490,28 +594,13 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { } }; }, [ - diagram.content, - diagram.title, - diagram.description, - // tags removed from dependencies + hasLocalChanges, settings.autoSave, + settings.autoSaveDelay, saveChanges, viewingCheckpointId, ]); - // Immediate save for tags - useEffect(() => { - // Skip initial mount or if no changes - if (JSON.stringify(tags) === JSON.stringify(lastSavedTagsRef.current)) return; - - // If we are viewing a past checkpoint, we shouldn't save tags either (or maybe we should? tags are global). - // Logic above says "Don't save when viewing a past checkpoint". Following that rule. - if (viewingCheckpointId !== null) return; - - // Save immediately - saveChanges(false); - }, [tags, saveChanges, viewingCheckpointId]); - // Save on blur for title (if auto-save is off) const handleTitleBlur = () => { // Don't save when viewing a past checkpoint @@ -541,6 +630,7 @@ export function DiagramEditor({ initialDiagram }: DiagramEditorProps) { headers: { 'Content-Type': 'application/json', [CSRF_HEADER_NAME]: csrfToken, + 'x-client-id': clientId, }, body: JSON.stringify({ isFavorite: nextFavorite }), }); diff --git a/src/components/DiagramGrid.tsx b/src/components/DiagramGrid.tsx index 2f1072d..bc9a696 100644 --- a/src/components/DiagramGrid.tsx +++ b/src/components/DiagramGrid.tsx @@ -14,13 +14,7 @@ import { AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from '@/components/ui/card'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { DropdownMenu, DropdownMenuContent, @@ -35,13 +29,26 @@ import { } from '@/components/ui/dropdown-menu'; import { Skeleton } from '@/components/ui/skeleton'; import { CSRF_HEADER_NAME, ensureCsrfToken } from '@/lib/csrf-client'; +import { LIVE_SYNC_CONFIG } from '@/lib/live-sync-config'; import { useDiagramStore } from '@/lib/store'; import { Diagram, SortOption } from '@/lib/types'; import { useListSync } from '@/lib/useListSync'; import { useShortcutPlatform } from '@/lib/use-platform'; import { cn, copyToClipboard, formatDate, sanitizeFilename } from '@/lib/utils'; -import { Download, Eye, ListFilter, Loader2, MoreHorizontal, Plus, Search, Settings2, Share2, Star, Trash2 } from 'lucide-react'; +import { + Download, + Eye, + ListFilter, + Loader2, + MoreHorizontal, + Plus, + Search, + Settings2, + Share2, + Star, + Trash2, +} from 'lucide-react'; import { useTheme } from 'next-themes'; import Link from 'next/link'; @@ -74,7 +81,7 @@ export function DiagramGrid({ const [peekDiagram, setPeekDiagram] = useState(null); const [sortMode, setSortMode] = useState('recent'); const { theme } = useTheme(); - const { settings, setHasAiApiKey, setAiProvider } = useDiagramStore(); + const { settings, updateSettings } = useDiagramStore(); const router = useRouter(); const loadMoreRef = useRef(null); const [isCreating, setIsCreating] = useState(false); @@ -83,8 +90,10 @@ export function DiagramGrid({ useListSync({ listUrl: `/api/diagrams?limit=24&offset=0&sort=${sortMode}`, currentItems: diagrams, - enabled: Boolean(settings.liveSync), - intervalMs: (settings.liveSyncInterval ?? 5000) * 2, // Poll lists less frequently + enabled: LIVE_SYNC_CONFIG.enabled, + intervalMs: LIVE_SYNC_CONFIG.pollIntervalMs * 2, + liveSyncMethod: LIVE_SYNC_CONFIG.method, + eventTopics: ['list:diagrams'], onUpdate: (serverItems, newTotal) => { setDiagrams(serverItems); setTotal(newTotal); @@ -108,17 +117,17 @@ export function DiagramGrid({ const res = await fetch('/api/settings/ai-key'); const data = await res.json(); if (typeof data.hasKey === 'boolean') { - setHasAiApiKey(data.hasKey); + updateSettings({ hasAiApiKey: data.hasKey }); } if (typeof data.provider === 'string') { - setAiProvider(data.provider); + updateSettings({ aiProvider: data.provider }); } } catch { // ignore; AI optional } }; loadAiKey(); - }, [setHasAiApiKey, setAiProvider]); + }, [updateSettings]); const fetchNextPage = useCallback(async () => { if (!hasMore || isFetchingMore) return; @@ -133,17 +142,11 @@ export function DiagramGrid({ const incoming: Diagram[] = Array.isArray(data.items) ? data.items : []; setDiagrams((prev) => { const existingIds = new Set(prev.map((d) => d.id)); - const merged = [...prev]; - incoming.forEach((item) => { - if (!existingIds.has(item.id)) { - merged.push(item); - } - }); - return merged; + return [...prev, ...incoming.filter((item) => !existingIds.has(item.id))]; }); setHasMore(Boolean(data.hasMore)); - setNextOffset(typeof data.nextOffset === 'number' ? data.nextOffset : nextOffset + (data.items?.length || 0)); - setTotal(typeof data.total === 'number' ? data.total : total); + setNextOffset(data.nextOffset ?? nextOffset + (data.items?.length || 0)); + setTotal(data.total ?? total); } catch (error) { console.error(error); toast.error('Failed to load more diagrams'); @@ -171,27 +174,30 @@ export function DiagramGrid({ return () => observer.disconnect(); }, [fetchNextPage, hasMore, isFetchingMore]); - const reloadFirstPage = useCallback(async (overrideSort?: SortOption) => { - const sortToUse = overrideSort ?? sortMode; - setIsLoading(true); - try { - const res = await fetch(`/api/diagrams?limit=24&offset=0&sort=${sortToUse}`); - if (!res.ok) { - throw new Error('Failed to load diagrams'); + const reloadFirstPage = useCallback( + async (overrideSort?: SortOption) => { + const sortToUse = overrideSort ?? sortMode; + setIsLoading(true); + try { + const res = await fetch(`/api/diagrams?limit=24&offset=0&sort=${sortToUse}`); + if (!res.ok) { + throw new Error('Failed to load diagrams'); + } + const data = await res.json(); + const items: Diagram[] = Array.isArray(data.items) ? data.items : []; + setDiagrams(items); + setHasMore(Boolean(data.hasMore)); + setNextOffset(data.nextOffset ?? items.length); + setTotal(data.total ?? items.length); + } catch (error) { + console.error(error); + toast.error('Failed to load diagrams'); + } finally { + setIsLoading(false); } - const data = await res.json(); - const items: Diagram[] = Array.isArray(data.items) ? data.items : []; - setDiagrams(items); - setHasMore(Boolean(data.hasMore)); - setNextOffset(typeof data.nextOffset === 'number' ? data.nextOffset : items.length); - setTotal(typeof data.total === 'number' ? data.total : items.length); - } catch (error) { - console.error(error); - toast.error('Failed to load diagrams'); - } finally { - setIsLoading(false); - } - }, [sortMode]); + }, + [sortMode] + ); const handleSortChange = (newSort: SortOption) => { if (newSort === sortMode) return; @@ -285,9 +291,7 @@ export function DiagramGrid({ const diagram = diagrams.find((d) => d.id === id); if (!diagram) return; - setDiagrams((prev) => - prev.map((d) => (d.id === id ? { ...d, isFavorite: !d.isFavorite } : d)) - ); + setDiagrams((prev) => prev.map((d) => (d.id === id ? { ...d, isFavorite: !d.isFavorite } : d))); const csrfToken = await ensureCsrfToken(); await fetch(`/api/diagrams/${id}`, { @@ -381,7 +385,7 @@ export function DiagramGrid({ const pdf = new jsPDF({ orientation: isLandscape ? 'landscape' : 'portrait', unit: 'px', - format: [svgWidth + 40, svgHeight + 40] + format: [svgWidth + 40, svgHeight + 40], }); pdf.setFillColor(255, 255, 255); pdf.rect(0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight(), 'F'); @@ -397,44 +401,42 @@ export function DiagramGrid({ } }; - - const diagramToDelete = deleteId ? diagrams.find((d) => d.id === deleteId) : null; const renderDiagramGrid = (list: Diagram[]) => ( -
+
{list.map((diagram) => ( Open {diagram.title} - +
-
- {diagram.emoji || '📊'} +
+ {diagram.emoji || '📊'}
- {diagram.title} - + {diagram.title} + {formatDate(diagram.updatedAt)} {diagram.totalVersions > 1 && ( - + v{diagram.totalVersions} )}
-
+
- handleShare(e, diagram.id)} - > + handleShare(e, diagram.id)}> Copy link - handleFavorite(e, diagram.id)} - > + handleFavorite(e, diagram.id)}>
- + {diagram.description && ( -

+

{diagram.description}

)} {diagram.tags && diagram.tags.length > 0 && ( -
- {diagram.tags.map(tag => ( +
+ {diagram.tags.map((tag) => ( ))}
)} -
-
+            
+
                 {diagram.content}
               
@@ -557,12 +555,15 @@ export function DiagramGrid({ return ( <> -
+
{/* Header */} -
-
+
+
- + 🔱 @@ -570,7 +571,7 @@ export function DiagramGrid({
-
+
- - - -
{/* Main Content */} -
+
{isLoading ? ( -
+
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => ( @@ -625,8 +625,8 @@ export function DiagramGrid({
) : diagrams.length === 0 ? (
- - + +
🔱 @@ -649,7 +649,7 @@ export function DiagramGrid({
{hasStarred && (
-

+

Starred // {starredDiagrams.length} @@ -660,8 +660,13 @@ export function DiagramGrid({ {(otherDiagrams.length > 0 || !hasStarred) && (
-
-

+
+

All diagrams // {otherDiagrams.length} of {Math.max(total - starredDiagrams.length, 0)} @@ -676,10 +681,15 @@ export function DiagramGrid({ - handleSortChange(v as SortOption)}> + handleSortChange(v as SortOption)} + > Recent Oldest - Alphabetical + + Alphabetical + Versions @@ -690,7 +700,10 @@ export function DiagramGrid({ )} {isFetchingMore && ( -
+
{[1, 2, 3, 4].map((i) => ( @@ -711,14 +724,14 @@ export function DiagramGrid({

{/* Footer */} -